Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Create events repository (EXPOSUREAPP-5470) (EXPOSUREAPP-5482)(EXPOSUREAPP-5484) #2549

Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4f8e26b
Add events card in event registration test fragment
LukasLechnerDev Mar 2, 2021
20ac9a9
Format
LukasLechnerDev Mar 2, 2021
ebf95a3
Create empty fragments and implement navigation
LukasLechnerDev Mar 2, 2021
0aed523
Create layout for CreateEventTestFragment.kt
LukasLechnerDev Mar 2, 2021
07a404a
Add spinner for event type
LukasLechnerDev Mar 3, 2021
68c3ce3
Build event object from input
LukasLechnerDev Mar 4, 2021
f214a18
Create database for event registration and store events in it
LukasLechnerDev Mar 5, 2021
b369db7
Fix date issue
LukasLechnerDev Mar 5, 2021
bf0c668
Show stored events in a simple way
LukasLechnerDev Mar 5, 2021
fc496f6
Make event list more pretty
LukasLechnerDev Mar 8, 2021
d3854ef
Add button to delete all events in ShowStoredEventsTestFragment.kt
LukasLechnerDev Mar 8, 2021
837dc2c
Change the functions of HostedEventRepository.kt to regular functions…
LukasLechnerDev Mar 8, 2021
eccd0f4
Change text in EventRegistration TestFragment
LukasLechnerDev Mar 8, 2021
0f55163
Merge branch 'feature/5062-event-registration-main' into feature/5470…
LukasLechnerDev Mar 8, 2021
d21b48c
Fix merge issues
LukasLechnerDev Mar 8, 2021
3f7004b
Add parameters from new TechSpec
LukasLechnerDev Mar 8, 2021
a5385d5
Change wording from 'hosted Events' to 'TraceLocation'
LukasLechnerDev Mar 8, 2021
5845590
Delete event registration database on app reset
LukasLechnerDev Mar 8, 2021
911ea7b
Fix detect issue 'MaxLineLength'
LukasLechnerDev Mar 8, 2021
40bfcf5
Remove parcelable from TraceLocationEntity.kt
LukasLechnerDev Mar 8, 2021
0cd1bea
Map TraceLocationEntity to TraceLocation in TraceLocationRepository
LukasLechnerDev Mar 8, 2021
65cdb5c
Use the Instant.seconds extension function
LukasLechnerDev Mar 8, 2021
b6ca9fa
Use existing EventRegistrationModule.kt instead of creating a new one
LukasLechnerDev Mar 8, 2021
8cdad4b
Only delete traceLocations on App reset instead of all tables in Trac…
LukasLechnerDev Mar 9, 2021
9af2cab
Merge branch 'feature/5062-event-registration-main' into feature/5470…
LukasLechnerDev Mar 10, 2021
f4fa24c
Add named parameters to TraceLocation mapping
LukasLechnerDev Mar 10, 2021
93968db
Add unit test for TraceLocation Mapper
LukasLechnerDev Mar 10, 2021
d27347f
Add unit tests for EventRegistrationConverters
LukasLechnerDev Mar 10, 2021
f204720
Add unit tests for TraceLocationEntity mapping
LukasLechnerDev Mar 10, 2021
ec93968
Add events database table to 'TraceLocation' database and remove 'Eve…
LukasLechnerDev Mar 10, 2021
e320ad1
Add database tests for TraceLocations
LukasLechnerDev Mar 11, 2021
82171b5
Merge branch 'feature/5062-event-registration-main' into feature/5470…
LukasLechnerDev Mar 11, 2021
5ad542f
Fix issue in EventRegistrationModule.kt
LukasLechnerDev Mar 11, 2021
0eb7bf7
Add database tests for checkInDao
LukasLechnerDev Mar 11, 2021
16f5ef6
Fix detekt maxLineLength issue
LukasLechnerDev Mar 11, 2021
a6c015b
Fix inconsistency in TraceLocationEntity.kt
LukasLechnerDev Mar 11, 2021
2caf8ee
Fix ktlint issues
LukasLechnerDev Mar 11, 2021
430a6c0
Inherit from BaseTest or BaseTestInstrumentation in tests
LukasLechnerDev Mar 11, 2021
307daa6
Fix issue in TraceLocationConverters.kt
LukasLechnerDev Mar 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "65f3afcf5d1c6bf0e15c9b721418e49e",
"entities": [
{
"tableName": "traceLocations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`guid` TEXT NOT NULL, `version` INTEGER NOT NULL, `type` INTEGER NOT NULL, `description` TEXT NOT NULL, `location` TEXT NOT NULL, `startTime` TEXT, `endTime` TEXT, `defaultCheckInLength` INTEGER, `signature` TEXT NOT NULL, PRIMARY KEY(`guid`))",
LukasLechnerDev marked this conversation as resolved.
Show resolved Hide resolved
"fields": [
{
"fieldPath": "guid",
"columnName": "guid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "address",
"columnName": "location",
LukasLechnerDev marked this conversation as resolved.
Show resolved Hide resolved
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "startDate",
"columnName": "startTime",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "endDate",
"columnName": "endTime",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "defaultCheckInLengthInMinutes",
"columnName": "defaultCheckInLength",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "signature",
"columnName": "signature",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"guid"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '65f3afcf5d1c6bf0e15c9b721418e49e')"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestEventregistrationBinding
import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
Expand All @@ -23,6 +24,8 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
private val binding: FragmentTestEventregistrationBinding by viewBindingLazy()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

with(binding) {
scanCheckInQrCode.setOnClickListener {
doNavigate(
Expand All @@ -37,6 +40,14 @@ class EventRegistrationTestFragment : Fragment(R.layout.fragment_test_eventregis
.actionEventRegistrationTestFragmentToTestQrCodeCreationFragment()
)
}

createEventButton.setOnClickListener {
findNavController().navigate(R.id.createEventTestFragment)
}

showEventsButton.setOnClickListener {
findNavController().navigate(R.id.showStoredEventsTestFragment)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package de.rki.coronawarnapp.test.eventregistration.ui.createevent

import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.contactdiary.util.hideKeyboard
import de.rki.coronawarnapp.databinding.FragmentTestCreateeventBinding
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.observe2
import de.rki.coronawarnapp.util.ui.viewBindingLazy
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import timber.log.Timber
import javax.inject.Inject

class CreateEventTestFragment : Fragment(R.layout.fragment_test_createevent), AutoInject {

@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val vm: CreateEventTestViewModel by cwaViewModels { viewModelFactory }

private val binding: FragmentTestCreateeventBinding by viewBindingLazy()

private val eventString = "Event"
private val locationString = "Location"

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

initSpinner()
initOnCreateEventClicked()
observeViewModelResult()
}

private fun observeViewModelResult() {
vm.result.observe2(this) {
when (it) {
is CreateEventTestViewModel.Result.Success ->
binding.resultText.text = "Successfully stored: ${it.eventEntity}"
is CreateEventTestViewModel.Result.Error ->
binding.resultText.text = "There is something wrong with your input values, please check again."
}
}
}

private fun initOnCreateEventClicked() = with(binding) {
createEventButton.setOnClickListener {
vm.createEvent(
eventOrLocationSpinner.editText!!.text.toString(),
eventDescription.text.toString(),
eventAddress.text.toString(),
eventStartEditText.text.toString(),
eventEndEditText.text.toString(),
eventDefaultCheckinLengthInMinutes.text.toString()
)
it.hideKeyboard()
}
}

private fun initSpinner() {
val items = listOf(eventString, locationString)
with(binding.eventOrLocationSpinner.editText as AutoCompleteTextView) {
setText(items.first(), false)
setAdapter(ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, items))
doAfterTextChanged { }
doOnTextChanged { text, start, before, count ->
Timber.d("text: $text, start: $start, before: $before, count: $count")

when (text.toString()) {
eventString -> {
binding.eventStart.visibility = View.VISIBLE
binding.eventEnd.visibility = View.VISIBLE
}
locationString -> {
binding.eventStart.visibility = View.GONE
binding.eventEnd.visibility = View.GONE
binding.eventStartEditText.text = null
binding.eventEndEditText.text = null
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package de.rki.coronawarnapp.test.eventregistration.ui.createevent

import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey

@Module
abstract class CreateEventTestFragmentModule {

@Binds
@IntoMap
@CWAViewModelKey(CreateEventTestViewModel::class)
abstract fun testCreateEventFragment(
factory: CreateEventTestViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package de.rki.coronawarnapp.test.eventregistration.ui.createevent

import androidx.lifecycle.MutableLiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.eventregistration.events.DefaultTraceLocation
import de.rki.coronawarnapp.eventregistration.events.TraceLocation
import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
import de.rki.coronawarnapp.util.TimeAndDateExtensions.seconds
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
import timber.log.Timber
import java.util.UUID

class CreateEventTestViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
private val traceLocationRepository: TraceLocationRepository
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {

@AssistedFactory
interface Factory : SimpleCWAViewModelFactory<CreateEventTestViewModel>

val result = MutableLiveData<Result>()

fun createEvent(
type: String,
description: String,
address: String,
start: String,
end: String,
defaultCheckInLengthInMinutes: String
) {
try {
val startDate =
if (start.isBlank()) null else DateTime.parse(start, DateTimeFormat.forPattern("yyyy-MM-dd HH:mm"))
val endDate =
if (end.isBlank()) null else DateTime.parse(end, DateTimeFormat.forPattern("yyyy-MM-dd HH:mm"))

/* TODO: wait for new protobuf messages 'TraceLocation' and perform network request to get
'SignedTraceLocation' */

// Backend needs UNIX timestamp in Seconds, not milliseconds
val startTimeStampSeconds = startDate?.toInstant()?.seconds ?: 0
val endTimeStampSeconds = endDate?.toInstant()?.seconds ?: 0

val traceLocationType =
if (type == "Event") TraceLocation.Type.TEMPORARY_OTHER else TraceLocation.Type.PERMANENT_OTHER

val traceLocation = DefaultTraceLocation(
UUID.randomUUID().toString(), // will be provided by the server when the endpoint is ready
traceLocationType,
description,
address,
startDate?.toInstant(),
endDate?.toInstant(),
defaultCheckInLengthInMinutes.toInt(),
"ServerSignature"
)

traceLocationRepository.addTraceLocation(traceLocation)
result.postValue(Result.Success(traceLocation))
} catch (exception: Exception) {
Timber.d("Something went wrong when trying to create an event: $exception")
result.postValue(Result.Error)
}
}

sealed class Result {
object Error : Result()
data class Success(val eventEntity: TraceLocation) : Result()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package de.rki.coronawarnapp.test.eventregistration.ui.showevents

import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestShowstoredeventsBinding
import de.rki.coronawarnapp.eventregistration.events.TraceLocation
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.observe2
import de.rki.coronawarnapp.util.ui.viewBindingLazy
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import javax.inject.Inject

class ShowStoredEventsTestFragment : Fragment(R.layout.fragment_test_showstoredevents), AutoInject {

@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val vm: ShowStoredEventsTestViewModel by cwaViewModels { viewModelFactory }

private val binding: FragmentTestShowstoredeventsBinding by viewBindingLazy()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

vm.storedEvents.observe2(this) { events ->
binding.storedEvents.text = events.joinToString(separator = "\n\n") { it.getSimpleUIString() }
}

binding.deleteAllEvents.setOnClickListener {
vm.deleteAllEvents()
}
}

private fun TraceLocation.getSimpleUIString(): String {
return listOf(
"guid = $guid",
"type = $type",
"description = $description",
"location = $address",
"startTime = $startDate",
"endTime = $endDate",
"defaultCheckInLengthInMinutes = $defaultCheckInLengthInMinutes",
"signature = $signature",
"version = $version"
).joinToString(separator = "\n")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package de.rki.coronawarnapp.test.eventregistration.ui.showevents

import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey

@Module
abstract class ShowStoredEventsTestFragmentModule {

@Binds
@IntoMap
@CWAViewModelKey(ShowStoredEventsTestViewModel::class)
abstract fun testStoredEventsFragment(
factory: ShowStoredEventsTestViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package de.rki.coronawarnapp.test.eventregistration.ui.showevents

import androidx.lifecycle.asLiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory

class ShowStoredEventsTestViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
private val traceLocationRepository: TraceLocationRepository
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {

@AssistedFactory
interface Factory : SimpleCWAViewModelFactory<ShowStoredEventsTestViewModel>

val storedEvents = traceLocationRepository.allTraceLocations.asLiveData()

fun deleteAllEvents() {
traceLocationRepository.deleteAllTraceLocations()
}
}
Loading