From 1516540f7180f5a59fc8e6f4ee45f9a78d9727d4 Mon Sep 17 00:00:00 2001
From: Juraj Kusnier <jurajkusnier@users.noreply.github.com>
Date: Tue, 20 Apr 2021 16:09:03 +0200
Subject: [PATCH] Event duplication wrong time (EXPOSUREAPP-6439) (#2875)

* Use DateTime

* update tests

* update tests

* fix merge

* fix timezone in test

* lint

* update circleci config

* timezone check

* timezone check

* fix tests

* revert circleci config changes

Co-authored-by: Mohamed <mohamed.metwalli@sap.com>
---
 .../organizer/QrCodeDetailFragmentTest.kt     |  98 ++++++++++++++
 .../TraceLocationCreateFragmentTest.kt        | 122 ++++++++++++++++++
 .../organizer/TraceLocationData.kt            |  51 ++++++++
 .../organizer/TraceLocationsFragmentTest.kt   |  94 ++++++++++++++
 .../FragmentTestModuleRegistrar.kt            |   9 +-
 .../create/TraceLocationCreateFragment.kt     |  20 +--
 .../create/TraceLocationCreateViewModel.kt    |  12 +-
 .../organizer/details/QrCodeDetailFragment.kt |   2 +-
 .../details/QrCodeDetailViewModel.kt          |   4 +-
 .../TraceLocationCreateViewModelTest.kt       |  22 ++--
 10 files changed, 403 insertions(+), 31 deletions(-)
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationCreateFragmentTest.kt
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationData.kt
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationsFragmentTest.kt

diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt
new file mode 100644
index 000000000..9986448a3
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/QrCodeDetailFragmentTest.kt
@@ -0,0 +1,98 @@
+package de.rki.coronawarnapp.ui.eventregistration.organizer
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
+import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository
+import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailFragment
+import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailFragmentArgs
+import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailViewModel
+import io.mockk.MockKAnnotations
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import org.joda.time.DateTimeZone
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseUITest
+import testhelpers.TestDispatcherProvider
+import testhelpers.launchFragmentInContainer2
+import java.util.TimeZone
+
+@RunWith(AndroidJUnit4::class)
+class QrCodeDetailFragmentTest : BaseUITest() {
+
+    @MockK private lateinit var qrCodeGenerator: QrCodeGenerator
+    @MockK private lateinit var traceLocationRepository: TraceLocationRepository
+
+    private val timeZone = TimeZone.getTimeZone("Europe/Berlin")
+
+    @Before
+    fun setup() {
+        TimeZone.setDefault(timeZone)
+        DateTimeZone.setDefault(DateTimeZone.forTimeZone(timeZone))
+        MockKAnnotations.init(this, relaxed = true)
+
+        coEvery { traceLocationRepository.traceLocationForId(1) } returns TraceLocationData.traceLocationSameDate
+        coEvery { traceLocationRepository.traceLocationForId(2) } returns TraceLocationData.traceLocationDifferentDate
+
+        setupMockViewModel(
+            object : QrCodeDetailViewModel.Factory {
+                override fun create(traceLocationId: Long): QrCodeDetailViewModel {
+                    return createViewModel(traceLocationId)
+                }
+            }
+        )
+    }
+
+    @After
+    fun teardown() {
+        clearAllViewModels()
+    }
+
+    @Test
+    fun eventDetailForSameDatesTest() {
+        launchFragmentInContainer2<QrCodeDetailFragment>(
+            fragmentArgs = QrCodeDetailFragmentArgs(
+                traceLocationId = 1
+            ).toBundle()
+        )
+
+        onView(withId(R.id.title)).check(matches(withText("My Birthday Party")))
+        onView(withId(R.id.subtitle)).check(matches(withText("at my place")))
+        onView(withId(R.id.eventDate)).check(matches(withText("19.04.2021, 06:12 - 22:52 Uhr")))
+    }
+
+    @Test
+    fun eventDetailForDifferentDatesTest() {
+        launchFragmentInContainer2<QrCodeDetailFragment>(
+            fragmentArgs = QrCodeDetailFragmentArgs(
+                traceLocationId = 2
+            ).toBundle()
+        )
+        onView(withId(R.id.title)).check(matches(withText("Your Birthday Party")))
+        onView(withId(R.id.subtitle)).check(matches(withText("at your place")))
+        onView(withId(R.id.eventDate)).check(matches(withText("18.04.2021, 12:00 - 19.04.2021, 22:52 Uhr")))
+    }
+
+    private fun createViewModel(traceLocationId: Long) =
+        QrCodeDetailViewModel(
+            traceLocationId = traceLocationId,
+            qrCodeGenerator = qrCodeGenerator,
+            traceLocationRepository = traceLocationRepository,
+            dispatcher = TestDispatcherProvider()
+        )
+}
+
+@Module
+abstract class QrCodeDetailFragmentTestModule {
+    @ContributesAndroidInjector
+    abstract fun qrCodeDetailFragment(): QrCodeDetailFragment
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationCreateFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationCreateFragmentTest.kt
new file mode 100644
index 000000000..2685049bd
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationCreateFragmentTest.kt
@@ -0,0 +1,122 @@
+package de.rki.coronawarnapp.ui.eventregistration.organizer
+
+import androidx.navigation.Navigation
+import androidx.navigation.testing.TestNavHostController
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.internal.runner.junit4.statement.UiThreadStatement
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.presencetracing.locations.TraceLocationCreator
+import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository
+import de.rki.coronawarnapp.ui.presencetracing.organizer.category.adapter.category.TraceLocationCategory
+import de.rki.coronawarnapp.ui.presencetracing.organizer.create.TraceLocationCreateFragment
+import de.rki.coronawarnapp.ui.presencetracing.organizer.create.TraceLocationCreateFragmentArgs
+import de.rki.coronawarnapp.ui.presencetracing.organizer.create.TraceLocationCreateViewModel
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.coEvery
+import io.mockk.impl.annotations.MockK
+import org.joda.time.DateTimeZone
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseUITest
+import testhelpers.TestDispatcherProvider
+import testhelpers.launchFragmentInContainer2
+import java.util.TimeZone
+
+@RunWith(AndroidJUnit4::class)
+class TraceLocationCreateFragmentTest : BaseUITest() {
+
+    @MockK private lateinit var traceLocationRepository: TraceLocationRepository
+    @MockK private lateinit var traceLocationCreator: TraceLocationCreator
+
+    private val timeZone = TimeZone.getTimeZone("Europe/Berlin")
+
+    private val navController = TestNavHostController(
+        ApplicationProvider.getApplicationContext()
+    ).apply {
+        UiThreadStatement.runOnUiThread { setGraph(R.navigation.trace_location_organizer_nav_graph) }
+    }
+
+    @Before
+    fun setup() {
+        TimeZone.setDefault(timeZone)
+        DateTimeZone.setDefault(DateTimeZone.forTimeZone(timeZone))
+        MockKAnnotations.init(this, relaxed = true)
+
+        coEvery { traceLocationRepository.addTraceLocation(any()) } returns TraceLocationData.traceLocationSameDate
+
+        setupMockViewModel(
+            object : TraceLocationCreateViewModel.Factory {
+                override fun create(category: TraceLocationCategory): TraceLocationCreateViewModel {
+                    return createViewModel(category)
+                }
+            }
+        )
+    }
+
+    @After
+    fun teardown() {
+        clearAllViewModels()
+    }
+
+    @Test
+    fun duplicateEventWithSameDatesTest() {
+        launchFragmentInContainer2<TraceLocationCreateFragment>(
+            fragmentArgs = TraceLocationCreateFragmentArgs(
+                category = TraceLocationData.categoryEvent,
+                originalItem = TraceLocationData.traceLocationSameDate
+            ).toBundle()
+        ).onFragment { fragment -> Navigation.setViewNavController(fragment.requireView(), navController) }
+
+        onView(withId(R.id.description_input_edit)).check(matches(withText("My Birthday Party")))
+        onView(withId(R.id.place_input_edit)).check(matches(withText("at my place")))
+        onView(withId(R.id.value_start)).check(matches(withText("Mo., 19.04.21   06:12")))
+        onView(withId(R.id.value_end)).check(matches(withText("Mo., 19.04.21   22:52")))
+
+        onView(withId(R.id.button_submit)).perform(click())
+
+        navController.currentDestination?.id shouldBe R.id.traceLocationInfoFragment
+    }
+
+    @Test
+    fun duplicateEventWithDifferentDatesTest() {
+        launchFragmentInContainer2<TraceLocationCreateFragment>(
+            fragmentArgs = TraceLocationCreateFragmentArgs(
+                category = TraceLocationData.categoryEvent,
+                originalItem = TraceLocationData.traceLocationDifferentDate
+            ).toBundle()
+        ).onFragment { fragment -> Navigation.setViewNavController(fragment.requireView(), navController) }
+
+        onView(withId(R.id.description_input_edit)).check(matches(withText("Your Birthday Party")))
+        onView(withId(R.id.place_input_edit)).check(matches(withText("at your place")))
+        onView(withId(R.id.value_start)).check(matches(withText("So., 18.04.21   12:00")))
+        onView(withId(R.id.value_end)).check(matches(withText("Mo., 19.04.21   22:52")))
+
+        onView(withId(R.id.button_submit)).perform(click())
+
+        navController.currentDestination?.id shouldBe R.id.traceLocationInfoFragment
+    }
+
+    private fun createViewModel(category: TraceLocationCategory) =
+        TraceLocationCreateViewModel(
+            category = category,
+            traceLocationCreator = traceLocationCreator,
+            dispatcherProvider = TestDispatcherProvider()
+        )
+}
+
+@Module
+abstract class CreateEventTestModule {
+    @ContributesAndroidInjector
+    abstract fun traceLocationCreateFragment(): TraceLocationCreateFragment
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationData.kt
new file mode 100644
index 000000000..9bf3382ff
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationData.kt
@@ -0,0 +1,51 @@
+package de.rki.coronawarnapp.ui.eventregistration.organizer
+
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation
+import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
+import de.rki.coronawarnapp.ui.presencetracing.organizer.category.adapter.category.TraceLocationCategory
+import de.rki.coronawarnapp.ui.presencetracing.organizer.category.adapter.category.TraceLocationUIType
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.secondsToInstant
+import okio.ByteString.Companion.decodeBase64
+
+object TraceLocationData {
+
+    private const val CRYPTOGRAPHIC_SEED = "MTIzNA=="
+
+    private const val PUB_KEY =
+        "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0z" +
+            "K7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg=="
+
+    val traceLocationSameDate = TraceLocation(
+        id = 1,
+        type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+        description = "My Birthday Party",
+        address = "at my place",
+        startDate = 1618805545L.secondsToInstant(),
+        endDate = 1618865545L.secondsToInstant(),
+        defaultCheckInLengthInMinutes = null,
+        cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+        cnPublicKey = PUB_KEY,
+        version = TraceLocation.VERSION
+    )
+
+    val traceLocationDifferentDate = TraceLocation(
+        id = 2,
+        type = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_OTHER,
+        description = "Your Birthday Party",
+        address = "at your place",
+        startDate = 1618740005L.secondsToInstant(),
+        endDate = 1618865545L.secondsToInstant(),
+        defaultCheckInLengthInMinutes = null,
+        cryptographicSeed = CRYPTOGRAPHIC_SEED.decodeBase64()!!,
+        cnPublicKey = PUB_KEY,
+        version = TraceLocation.VERSION
+    )
+
+    val categoryEvent = TraceLocationCategory(
+        TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT,
+        TraceLocationUIType.EVENT,
+        R.string.tracelocation_organizer_category_cultural_event_title,
+        R.string.tracelocation_organizer_category_cultural_event_subtitle
+    )
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationsFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationsFragmentTest.kt
new file mode 100644
index 000000000..e478d51bc
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/eventregistration/organizer/TraceLocationsFragmentTest.kt
@@ -0,0 +1,94 @@
+package de.rki.coronawarnapp.ui.eventregistration.organizer
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
+import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository
+import de.rki.coronawarnapp.ui.presencetracing.organizer.list.TraceLocationsFragment
+import de.rki.coronawarnapp.ui.presencetracing.organizer.list.TraceLocationsViewModel
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import kotlinx.coroutines.flow.flowOf
+import org.joda.time.DateTimeZone
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseUITest
+import testhelpers.TestDispatcherProvider
+import testhelpers.launchFragmentInContainer2
+import java.util.TimeZone
+
+@RunWith(AndroidJUnit4::class)
+class TraceLocationsFragmentTest : BaseUITest() {
+
+    @MockK private lateinit var checkInsRepository: CheckInRepository
+    @MockK private lateinit var traceLocationRepository: TraceLocationRepository
+
+    private val timeZone = TimeZone.getTimeZone("Europe/Berlin")
+
+    @Before
+    fun setup() {
+        TimeZone.setDefault(timeZone)
+        DateTimeZone.setDefault(DateTimeZone.forTimeZone(timeZone))
+        MockKAnnotations.init(this, relaxed = true)
+
+        every { checkInsRepository.allCheckIns } returns flowOf(listOf())
+
+        setupMockViewModel(
+            object : TraceLocationsViewModel.Factory {
+                override fun create(): TraceLocationsViewModel {
+                    return createViewModel()
+                }
+            }
+        )
+    }
+
+    @After
+    fun teardown() {
+        clearAllViewModels()
+    }
+
+    @Test
+    fun itemWithSameDatesTest() {
+        every { traceLocationRepository.traceLocationsWithinRetention } returns
+            flowOf(listOf(TraceLocationData.traceLocationSameDate))
+
+        launchFragmentInContainer2<TraceLocationsFragment>()
+
+        onView(withId(R.id.description)).check(matches(withText("My Birthday Party")))
+        onView(withId(R.id.address)).check(matches(withText("at my place")))
+        onView(withId(R.id.duration)).check(matches(withText("19.04.21 06:12 - 22:52 Uhr")))
+    }
+
+    @Test
+    fun itemWithDifferentDatesTest() {
+        every { traceLocationRepository.traceLocationsWithinRetention } returns
+            flowOf(listOf(TraceLocationData.traceLocationDifferentDate))
+
+        launchFragmentInContainer2<TraceLocationsFragment>()
+
+        onView(withId(R.id.description)).check(matches(withText("Your Birthday Party")))
+        onView(withId(R.id.address)).check(matches(withText("at your place")))
+        onView(withId(R.id.duration)).check(matches(withText("18.04.21 12:00 - 19.04.21 22:52 Uhr")))
+    }
+
+    private fun createViewModel() = TraceLocationsViewModel(
+        checkInsRepository = checkInsRepository,
+        traceLocationRepository = traceLocationRepository,
+        dispatcherProvider = TestDispatcherProvider()
+    )
+}
+
+@Module
+abstract class TraceLocationsFragmentTestModule {
+    @ContributesAndroidInjector
+    abstract fun traceLocationsFragment(): TraceLocationsFragment
+}
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
index ecb1c406e..5f3cabbfc 100644
--- a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
@@ -10,6 +10,9 @@ import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryLocationListFragmentTest
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryOnboardingFragmentTestModule
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryOverviewFragmentTestModule
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryPersonListFragmentTestModule
+import de.rki.coronawarnapp.ui.eventregistration.organizer.CreateEventTestModule
+import de.rki.coronawarnapp.ui.eventregistration.organizer.QrCodeDetailFragmentTestModule
+import de.rki.coronawarnapp.ui.eventregistration.organizer.TraceLocationsFragmentTestModule
 import de.rki.coronawarnapp.ui.main.home.HomeFragmentTestModule
 import de.rki.coronawarnapp.ui.onboarding.OnboardingAnalyticsFragmentTestModule
 import de.rki.coronawarnapp.ui.onboarding.OnboardingDeltaInteroperabilityFragmentTestModule
@@ -74,7 +77,11 @@ import de.rki.coronawarnapp.ui.tracing.TracingDetailsFragmentTestTestModule
         StatisticsExplanationFragmentTestModule::class,
         // Bugreporting
         DebugLogUploadTestModule::class,
-        DebugLogTestModule::class
+        DebugLogTestModule::class,
+        // Event Registration
+        CreateEventTestModule::class,
+        TraceLocationsFragmentTestModule::class,
+        QrCodeDetailFragmentTestModule::class
     ]
 )
 class FragmentTestModuleRegistrar
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateFragment.kt
index 4843c35cc..64348cc5a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateFragment.kt
@@ -25,9 +25,9 @@ import de.rki.coronawarnapp.util.ui.popBackStack
 import de.rki.coronawarnapp.util.ui.viewBindingLazy
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
 import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
+import org.joda.time.DateTime
 import org.joda.time.Duration
 import org.joda.time.LocalDate
-import org.joda.time.LocalDateTime
 import org.joda.time.LocalTime
 import javax.inject.Inject
 
@@ -121,8 +121,8 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag
                     placeInputEdit.setText(it.address)
                 }
                 viewModel.apply {
-                    begin = it.startDate?.let { time -> LocalDateTime(time) }
-                    end = it.endDate?.let { time -> LocalDateTime(time) }
+                    begin = it.startDate?.toDateTime()
+                    end = it.endDate?.toDateTime()
                     checkInLength = Duration.standardMinutes(it.defaultCheckInLengthInMinutes?.toLong() ?: 0L)
                 }
             }
@@ -152,9 +152,9 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag
     }
 
     private fun showDatePicker(
-        defaultValue: LocalDateTime?,
-        minConstraint: LocalDateTime? = null,
-        callback: (LocalDateTime) -> Unit
+        defaultValue: DateTime?,
+        minConstraint: DateTime? = null,
+        callback: (DateTime) -> Unit
     ) {
         MaterialDatePicker
             .Builder
@@ -181,7 +181,7 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag
             .show(childFragmentManager, DATE_PICKER_TAG)
     }
 
-    private fun showTimePicker(date: LocalDate, hours: Int?, minutes: Int?, callback: (LocalDateTime) -> Unit) {
+    private fun showTimePicker(date: LocalDate, hours: Int?, minutes: Int?, callback: (DateTime) -> Unit) {
         MaterialTimePicker
             .Builder()
             .setTimeFormat(if (is24HourFormat(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H)
@@ -194,7 +194,7 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag
             .build()
             .apply {
                 addOnPositiveButtonClickListener {
-                    callback(date.toLocalDateTime(LocalTime(this.hour, this.minute)))
+                    callback(date.toDateTime(LocalTime(this.hour, this.minute)))
                 }
             }
             .show(childFragmentManager, TIME_PICKER_TAG)
@@ -228,8 +228,8 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag
         savedInstanceState?.getLong(LENGTH_OF_STAY)?.let {
             viewModel.checkInLength = Duration.standardMinutes(it)
         }
-        viewModel.begin = savedInstanceState?.getSerializable(BEGIN) as LocalDateTime?
-        viewModel.end = savedInstanceState?.getSerializable(END) as LocalDateTime?
+        viewModel.begin = savedInstanceState?.getSerializable(BEGIN) as DateTime?
+        viewModel.end = savedInstanceState?.getSerializable(END) as DateTime?
     }
 
     companion object {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModel.kt
index 4e862e265..29976a36c 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModel.kt
@@ -19,8 +19,8 @@ import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
+import org.joda.time.DateTime
 import org.joda.time.Duration
-import org.joda.time.LocalDateTime
 import timber.log.Timber
 import java.util.Locale
 import kotlin.properties.ReadWriteProperty
@@ -42,8 +42,8 @@ class TraceLocationCreateViewModel @AssistedInject constructor(
     var description: String by UpdateDelegateWithDefaultValue("")
     var address: String by UpdateDelegateWithDefaultValue("")
     var checkInLength: Duration by UpdateDelegateWithDefaultValue(Duration.ZERO)
-    var begin: LocalDateTime? by UpdateDelegate()
-    var end: LocalDateTime? by UpdateDelegate()
+    var begin: DateTime? by UpdateDelegate()
+    var end: DateTime? by UpdateDelegate()
 
     init {
         checkInLength = when (category.uiType) {
@@ -111,8 +111,8 @@ class TraceLocationCreateViewModel @AssistedInject constructor(
     private fun String.isTextFormattedCorrectly() = trim().length in 1..100 && !contains('\n')
 
     data class UIState(
-        private val begin: LocalDateTime? = null,
-        private val end: LocalDateTime? = null,
+        private val begin: DateTime? = null,
+        private val end: DateTime? = null,
         private val checkInLength: Duration? = null,
         @StringRes val title: Int,
         val isRequestInProgress: Boolean,
@@ -129,7 +129,7 @@ class TraceLocationCreateViewModel @AssistedInject constructor(
             )
         }
 
-        private fun getFormattedTime(value: LocalDateTime?, locale: Locale) =
+        private fun getFormattedTime(value: DateTime?, locale: Locale) =
             value?.toString("E, ${locale.shortDatePattern()}   HH:mm", locale)
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt
index 260749909..3dc3137e1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailFragment.kt
@@ -125,7 +125,7 @@ class QrCodeDetailFragment : Fragment(R.layout.trace_location_organizer_qr_code_
                         requireContext().getString(
                             R.string.trace_location_organizer_detail_item_duration_multiple_days,
                             startTime.toLocalDate().toString("dd.MM.yyyy"),
-                            endTime.toLocalTime().toString("HH:mm"),
+                            startTime.toLocalTime().toString("HH:mm"),
                             endTime.toLocalDate().toString("dd.MM.yyyy"),
                             endTime.toLocalTime().toString("HH:mm")
                         )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt
index 0a33ec89e..e69e39631 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/details/QrCodeDetailViewModel.kt
@@ -8,7 +8,7 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation
-import de.rki.coronawarnapp.presencetracing.storage.repo.DefaultTraceLocationRepository
+import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
 import de.rki.coronawarnapp.ui.presencetracing.organizer.category.adapter.category.traceLocationCategories
@@ -24,7 +24,7 @@ class QrCodeDetailViewModel @AssistedInject constructor(
     @Assisted private val traceLocationId: Long,
     private val dispatcher: DispatcherProvider,
     private val qrCodeGenerator: QrCodeGenerator,
-    private val traceLocationRepository: DefaultTraceLocationRepository
+    private val traceLocationRepository: TraceLocationRepository
 ) : CWAViewModel() {
 
     private var traceLocation: TraceLocation? = null
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModelTest.kt
index 2736f0d6a..4041652f0 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/organizer/create/TraceLocationCreateViewModelTest.kt
@@ -12,9 +12,9 @@ import io.mockk.coEvery
 import io.mockk.impl.annotations.MockK
 import kotlinx.coroutines.test.runBlockingTest
 import okio.ByteString.Companion.encode
+import org.joda.time.DateTime
 import org.joda.time.Duration
 import org.joda.time.Instant
-import org.joda.time.LocalDateTime
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
@@ -60,8 +60,8 @@ internal class TraceLocationCreateViewModelTest : BaseTest() {
 
         viewModel.address = "Address"
         viewModel.description = "Description"
-        viewModel.begin = LocalDateTime()
-        viewModel.end = LocalDateTime().plusHours(1)
+        viewModel.begin = DateTime()
+        viewModel.end = DateTime().plusHours(1)
         viewModel.checkInLength = Duration.standardMinutes(1)
 
         viewModel.uiState.observeForTesting {
@@ -76,8 +76,8 @@ internal class TraceLocationCreateViewModelTest : BaseTest() {
 
         viewModel.address = "Address"
         viewModel.description = "A".repeat(101)
-        viewModel.begin = LocalDateTime()
-        viewModel.end = LocalDateTime().plusHours(1)
+        viewModel.begin = DateTime()
+        viewModel.end = DateTime().plusHours(1)
         viewModel.checkInLength = Duration.standardMinutes(1)
 
         viewModel.uiState.observeForTesting {
@@ -92,8 +92,8 @@ internal class TraceLocationCreateViewModelTest : BaseTest() {
 
         viewModel.address = "A".repeat(101)
         viewModel.description = "Description"
-        viewModel.begin = LocalDateTime()
-        viewModel.end = LocalDateTime().plusHours(1)
+        viewModel.begin = DateTime()
+        viewModel.end = DateTime().plusHours(1)
         viewModel.checkInLength = Duration.standardMinutes(1)
 
         viewModel.uiState.observeForTesting {
@@ -136,8 +136,8 @@ internal class TraceLocationCreateViewModelTest : BaseTest() {
 
         viewModel.address = "Address"
         viewModel.description = "Description"
-        viewModel.begin = LocalDateTime()
-        viewModel.end = LocalDateTime().plusHours(1)
+        viewModel.begin = DateTime()
+        viewModel.end = DateTime().plusHours(1)
         viewModel.checkInLength = Duration.ZERO
 
         viewModel.uiState.observeForTesting {
@@ -151,8 +151,8 @@ internal class TraceLocationCreateViewModelTest : BaseTest() {
 
         viewModel.address = "Address"
         viewModel.description = "Description"
-        viewModel.begin = LocalDateTime().plusHours(1)
-        viewModel.end = LocalDateTime()
+        viewModel.begin = DateTime().plusHours(1)
+        viewModel.end = DateTime()
         viewModel.checkInLength = Duration.ZERO
 
         viewModel.uiState.observeForTesting {
-- 
GitLab