diff --git a/.circleci/config.yml b/.circleci/config.yml index 249d3793e1021f1295507f12fa62b65ef17a28db..0a0a2ace152a0ffbb74647192c0260376fce3b98 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -27,21 +27,6 @@ commands: - ~/.gradle key: gradle-v1-{{ arch }}-{{ checksum "build.gradle" }}-{{ checksum "Corona-Warn-App/build.gradle" }}-{{ checksum "Server-Protocol-Buffer/build.gradle" }} - restore-android-build-cache-macos: - description: "Restore Android build caches on macOS" - steps: - - restore_cache: - key: android-buildcache-v1-{{ arch }} - - save-android-build-cache-macos: - description: "Save Android build caches on macOS" - steps: - - save_cache: - paths: - - ~/.android/build-cache - - ~/.android/cache - key: android-buildcache-v1-{{ arch }}-{{ epoch }} - run-gradle-cmd: description: "Running gradle command with environment options" parameters: @@ -104,90 +89,6 @@ commands: circleci step halt fi - setup-android-macos: - description: "Setup Android environment on macOS executor" - steps: - - restore_cache: - key: android-sdk-v1-{{ arch }}-{{ checksum ".circleci/install-android-sdk.sh" }} - - run: - name: Set ANDROID_SDK_ROOT environment variable - command: echo 'export ANDROID_SDK_ROOT=$HOME/android-sdk' >> $BASH_ENV - - run: - name: Install Android SDK - command: | - sh .circleci/install-android-sdk.sh - echo 'export PATH=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/cmdline-tools/latest:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/platform-tools:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/emulator:$PATH' >> $BASH_ENV - echo 'export PATH=$ANDROID_SDK_ROOT/build-tools/29.0.3:$PATH' >> $BASH_ENV - source $BASH_ENV - sdkmanager --list - - save_cache: - key: android-sdk-v1-{{ arch }}-{{ checksum ".circleci/install-android-sdk.sh" }} - paths: - - /Users/distiller/android-sdk - - run-emulator-for-api: - parameters: - apilevel: - type: integer - description: "Setup and start emulator for API<< parameters.apilevel >>" - steps: - - run: - name: Create emulator AVD - command: > - echo "no" | avdmanager --verbose create avd --force - --name "emulator_API<< parameters.apilevel >>" - --package "system-images;android-<< parameters.apilevel >>;google_apis;x86_64" - - run: - name: Configure emulator settings - command: | - cd $HOME/.android/avd/emulator_API<< parameters.apilevel >>.avd - sed -i '' -e 's/hw.lcd.density=[0-9]*/hw.lcd.density=560/g' config.ini - sed -i '' -e 's/hw.lcd.height=[0-9]*/hw.lcd.height=2880/g' config.ini - sed -i '' -e 's/hw.lcd.width=[0-9]*/hw.lcd.width=1440/g' config.ini - sed -i '' -e 's/hw.ramSize=[0-9]*/hw.ramSize=1536/g' config.ini - - run: - name: Check host state - command: | - emulator -accel-check - emulator -version - - run: - name: Start emulator AVD - command: > - emulator @emulator_API<< parameters.apilevel >> - -no-window - -no-audio - -no-boot-anim - -memory 2048 - -nojni - background: true - no_output_timeout: 60m - - run: - name: Wait for emulator - command: | - adb wait-for-device shell 'while [[ -z $(getprop dev.bootcomplete) ]]; do sleep 1; done;' - adb devices - sleep 5 - - run: - name: Disable animations - command: | - adb shell settings put global window_animation_scale 0 - adb shell settings put global transition_animation_scale 0 - adb shell settings put global animator_duration_scale 0 - - kill-all-emulators: - description: "Kill all emulators" - steps: - - run: - name: Kill all emulators - command: | - adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done - sleep 2 - adb kill-server - sleep 2 - compress-path: parameters: input: diff --git a/.circleci/install-android-sdk.sh b/.circleci/install-android-sdk.sh deleted file mode 100644 index fc79de5a31dc8b7add7729e6ee24dd44a0328b4e..0000000000000000000000000000000000000000 --- a/.circleci/install-android-sdk.sh +++ /dev/null @@ -1,29 +0,0 @@ -if [ -d $ANDROID_SDK_ROOT ] -then - echo "Directory $ANDROID_SDK_ROOT already exists so we're skipping the install. If you'd like to install fresh tools, edit this script to invalidate the CI cache..." - exit 0 -fi - -mkdir -p $ANDROID_SDK_ROOT -cd $ANDROID_SDK_ROOT -curl https://dl.google.com/android/repository/commandlinetools-mac-6858069_latest.zip -o cmdline-tools.zip - -unzip cmdline-tools.zip -d $ANDROID_SDK_ROOT/cmdline-tools -mv $ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/latest - -mkdir -p "$ANDROID_SDK_ROOT/licenses" - -echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_SDK_ROOT/licenses/android-sdk-license" -echo "84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_SDK_ROOT/licenses/android-sdk-preview-license" -echo "d975f751698a77b662f1254ddbeed3901e976f5a" > "$ANDROID_SDK_ROOT/licenses/intel-android-extra-license" - -SDKMANAGER=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager - -$SDKMANAGER "platform-tools" -$SDKMANAGER "platforms;android-29" -$SDKMANAGER "build-tools;29.0.3" -$SDKMANAGER "ndk-bundle" -$SDKMANAGER "system-images;android-29;google_apis;x86_64" -$SDKMANAGER "emulator" - -echo "y" | sudo $SDKMANAGER --install "ndk;21.2.6472646" --sdk_root=${ANDROID_SDK_ROOT} \ No newline at end of file diff --git a/Corona-Warn-App/proguard-rules.pro b/Corona-Warn-App/proguard-rules.pro index a494dc86a67e75431934ce0fd0adeeab58b9ddee..c5061b216a2ede12f11af5a1a62291482b5d3eea 100644 --- a/Corona-Warn-App/proguard-rules.pro +++ b/Corona-Warn-App/proguard-rules.pro @@ -86,4 +86,11 @@ ##---------------End: proguard configuration for Gson ---------- --keep class de.rki.coronawarnapp.server.protocols.internal.** { *; } \ No newline at end of file +-keep class de.rki.coronawarnapp.server.protocols.internal.** { *; } + +# Fixes R8 bug https://issuetracker.google.com/issues/170709331 +# May be removed after newer R8 version is in use and the fix is confirmed +# Prevents the app from crashing on navigation due to animation resources not being found. +-keepclassmembers class **.R$* { + public static <fields>; +} \ No newline at end of file diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt index 8966f716c4a63d2fd8142e319f03d034822c223a..8f89855cf01a8d2882cbf0a1b6234b876f76625f 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeData.kt @@ -29,6 +29,12 @@ import de.rki.coronawarnapp.tracing.ui.homecards.TracingDisabledCard import de.rki.coronawarnapp.tracing.ui.homecards.TracingFailedCard import de.rki.coronawarnapp.tracing.ui.homecards.TracingProgressCard import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson +import de.rki.coronawarnapp.vaccination.ui.homecard.ImmuneVaccinationHomeCard +import de.rki.coronawarnapp.vaccination.ui.homecard.VaccinationHomeCard +import io.mockk.every +import io.mockk.mockk +import org.joda.time.Duration import org.joda.time.Instant object HomeData { @@ -169,4 +175,34 @@ object HomeData { onClickAction = {} ) } + + object Vaccination { + val INCOMPLETE = VaccinationHomeCard.Item( + vaccinatedPerson = mockk<VaccinatedPerson>().apply { + every { fullName } returns "Andrea Schneider" + every { identifier } returns mockk() + every { getVaccinationStatus(any()) } returns VaccinatedPerson.Status.INCOMPLETE + every { getTimeUntilImmunity(any()) } returns Duration.standardDays(14) + }, + onClickAction = {} + ) + val COMPLETE = VaccinationHomeCard.Item( + vaccinatedPerson = mockk<VaccinatedPerson>().apply { + every { fullName } returns "Andrea Schneider" + every { identifier } returns mockk() + every { getVaccinationStatus(any()) } returns VaccinatedPerson.Status.COMPLETE + every { getTimeUntilImmunity(any()) } returns Duration.standardDays(14) + }, + onClickAction = {} + ) + val IMMUNITY = ImmuneVaccinationHomeCard.Item( + vaccinatedPerson = mockk<VaccinatedPerson>().apply { + every { fullName } returns "Andrea Schneider" + every { identifier } returns mockk() + every { getVaccinationStatus(any()) } returns VaccinatedPerson.Status.IMMUNITY + every { getTimeUntilImmunity(any()) } returns Duration.standardDays(14) + }, + onClickAction = {} + ) + } } diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt index b3e9922c9195fea17295954099074f981e272597..03430513efd136f91f631d65df8dfbd2df483029 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentTest.kt @@ -34,6 +34,8 @@ import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.vaccination.core.VaccinationSettings import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository +import de.rki.coronawarnapp.vaccination.ui.homecard.CreateVaccinationHomeCard +import de.rki.coronawarnapp.vaccination.ui.homecard.VaccinationStatusItem import io.mockk.MockKAnnotations import io.mockk.Runs import io.mockk.every @@ -89,7 +91,7 @@ class HomeFragmentTest : BaseUITest() { every { refreshRequiredData() } just Runs every { tracingHeaderState } returns MutableLiveData(TracingHeaderState.TracingActive) every { showLoweredRiskLevelDialog } returns MutableLiveData() - every { homeItems } returns MutableLiveData(emptyList()) + every { homeItems } returns homeFragmentItemsLiveData() every { popupEvents } returns SingleLiveEvent() every { showPopUps() } just Runs every { restoreAppShortcuts() } just Runs @@ -272,6 +274,51 @@ class HomeFragmentTest : BaseUITest() { captureHomeFragment("compatibility_ble_scan_not_supported") } + @Screenshot + @Test + fun captureVaccinationNoCertificate() { + launchInMainActivity<HomeFragment>() + onView(withId(R.id.recycler_view)).perform(recyclerScrollTo(2, additionalY = 450)) + + takeScreenshot<HomeFragment>("vaccination_none") + } + + @Screenshot + @Test + fun captureVaccinationIncomplete() { + every { homeFragmentViewModel.homeItems } returns homeFragmentItemsLiveData( + vaccinationStatus = HomeData.Vaccination.INCOMPLETE + ) + launchInMainActivity<HomeFragment>() + onView(withId(R.id.recycler_view)).perform(recyclerScrollTo(2)) + + takeScreenshot<HomeFragment>("vaccination_incomplete") + } + + @Screenshot + @Test + fun captureVaccinationComplete() { + every { homeFragmentViewModel.homeItems } returns homeFragmentItemsLiveData( + vaccinationStatus = HomeData.Vaccination.COMPLETE + ) + launchInMainActivity<HomeFragment>() + onView(withId(R.id.recycler_view)).perform(recyclerScrollTo(2)) + + takeScreenshot<HomeFragment>("vaccination_complete") + } + + @Screenshot + @Test + fun captureVaccinationImmunity() { + every { homeFragmentViewModel.homeItems } returns homeFragmentItemsLiveData( + vaccinationStatus = HomeData.Vaccination.IMMUNITY + ) + launchInMainActivity<HomeFragment>() + onView(withId(R.id.recycler_view)).perform(recyclerScrollTo(2)) + + takeScreenshot<HomeFragment>("vaccination_immunity") + } + @After fun teardown() { clearAllViewModels() @@ -313,7 +360,8 @@ class HomeFragmentTest : BaseUITest() { // LiveData item for fragments private fun homeFragmentItemsLiveData( tracingStateItem: TracingStateItem = HomeData.Tracing.LOW_RISK_ITEM_WITH_ENCOUNTERS, - submissionTestResultItem: TestResultItem = HomeData.Submission.TEST_UNREGISTERED_ITEM + submissionTestResultItem: TestResultItem = HomeData.Submission.TEST_UNREGISTERED_ITEM, + vaccinationStatus: VaccinationStatusItem? = null, ): LiveData<List<HomeItem>> = MutableLiveData( mutableListOf<HomeItem>().apply { @@ -324,7 +372,15 @@ class HomeFragmentTest : BaseUITest() { } else -> add(tracingStateItem) } + + vaccinationStatus?.let { + add(it) + } + add(submissionTestResultItem) + + add(CreateVaccinationHomeCard.Item {}) + Statistics.statisticsData?.let { add(StatisticsHomeCard.Item(data = it, onHelpAction = { })) } diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..10e7acdf14539cb7128ede16db3fabccef1a6e4d --- /dev/null +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/vaccination/VaccinationConsentFragmentTest.kt @@ -0,0 +1,67 @@ +package de.rki.coronawarnapp.ui.vaccination + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import dagger.Module +import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment +import de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentViewModel +import io.mockk.MockKAnnotations +import io.mockk.impl.annotations.MockK +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import testhelpers.BaseUITest +import testhelpers.Screenshot +import testhelpers.SystemUIDemoModeRule +import testhelpers.launchFragment2 +import testhelpers.launchFragmentInContainer2 +import testhelpers.takeScreenshot +import tools.fastlane.screengrab.locale.LocaleTestRule + +@RunWith(AndroidJUnit4::class) +class VaccinationConsentFragmentTest : BaseUITest() { + @Rule + @JvmField + val localeTestRule = LocaleTestRule() + + @get:Rule + val systemUIDemoModeRule = SystemUIDemoModeRule() + + @MockK lateinit var viewModel: VaccinationConsentViewModel + + @Before + fun setup() { + MockKAnnotations.init(this, relaxed = true) + + setupMockViewModel( + object : VaccinationConsentViewModel.Factory { + override fun create(): VaccinationConsentViewModel = viewModel + } + ) + } + + @After + fun teardown() { + clearAllViewModels() + } + + @Test + fun launch_fragment() { + launchFragment2<VaccinationConsentFragment>() + } + + @Screenshot + @Test + fun capture_screenshot() { + launchFragmentInContainer2<VaccinationConsentFragment>() + takeScreenshot<VaccinationConsentFragment>() + } +} + +@Module +abstract class VaccinationConsentFragmentTestModule { + @ContributesAndroidInjector + abstract fun vaccinationConsentFragment(): VaccinationConsentFragment +} diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt index 14a82715c08142c3879fe95ba2bfeb3262a6398c..a63d7dbb9f73319145dd28bc793eab657bde6aec 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragmentTest.kt @@ -13,7 +13,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import dagger.Module import dagger.android.ContributesAndroidInjector import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.ui.Country import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate import io.mockk.MockKAnnotations import io.mockk.every @@ -104,7 +103,7 @@ class VaccinationDetailsFragmentTest : BaseUITest() { every { vaccineName } returns "Comirnaty (mRNA)" every { vaccineManufacturer } returns "BioNTech" every { certificateIssuer } returns "Landratsamt Musterstadt" - every { certificateCountry } returns Country.DE + every { certificateCountry } returns "Deutschland" every { certificateId } returns "05930482748454836478695764787841" every { expiresAt } returns Instant.parse("2021-05-16T00:00:00.000Z") every { medicalProductName } returns "mRNA" diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ef246ec48c8cf7810dd832066d9773b3082887ec --- /dev/null +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentTest.kt @@ -0,0 +1,229 @@ +package de.rki.coronawarnapp.vaccination.ui.list + +import android.content.Context +import android.graphics.BitmapFactory +import androidx.lifecycle.MutableLiveData +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.swipeUp +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 +import dagger.Module +import dagger.android.ContributesAndroidInjector +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.IMMUNITY +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.INCOMPLETE +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import org.joda.time.Duration +import org.joda.time.Instant +import org.joda.time.LocalDate +import org.joda.time.format.DateTimeFormat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import testhelpers.BaseUITest +import testhelpers.Screenshot +import testhelpers.SystemUIDemoModeRule +import testhelpers.launchFragment2 +import testhelpers.launchFragmentInContainer2 +import testhelpers.takeScreenshot +import tools.fastlane.screengrab.locale.LocaleTestRule + +@RunWith(AndroidJUnit4::class) +internal class VaccinationListFragmentTest : BaseUITest() { + + @MockK lateinit var vaccinationListViewModel: VaccinationListViewModel + + @Rule + @JvmField + val localeTestRule = LocaleTestRule() + + @get:Rule + val systemUIDemoModeRule = SystemUIDemoModeRule() + + private val applicationContext = ApplicationProvider.getApplicationContext<Context>() + private val testQrCode = BitmapFactory.decodeResource(applicationContext.resources, R.drawable.test_qr_code) + private val formatter = DateTimeFormat.forPattern("dd.MM.yyyy") + + private val fragmentArgs = VaccinationListFragmentArgs("personIdentifierCodeSha256").toBundle() + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxed = true) + + setupMockViewModel( + object : VaccinationListViewModel.Factory { + override fun create(personIdentifierCode: String): VaccinationListViewModel = vaccinationListViewModel + } + ) + } + + @Test + fun launch_fragment() { + launchFragment2<VaccinationListFragment>(fragmentArgs = fragmentArgs) + } + + @Screenshot + @Test + fun capture_screenshots_incomplete() { + + val listItems = listOf( + createQrCodeCardItem( + doseNumber = 1, + totalSeriesOfDoses = 2 + ), + createNameCardItem(), + createVaccinationCardItem( + doseNumber = 1, + totalSeriesOfDoses = 2, + vaccinationStatus = INCOMPLETE + ) + ) + + every { vaccinationListViewModel.uiState } returns mockUiState( + itemList = listItems, + vaccinationStatus = INCOMPLETE + ) + launchFragmentInContainer2<VaccinationListFragment>(fragmentArgs = fragmentArgs) + takeScreenshot<VaccinationListFragment>("incomplete") + onView(withId(R.id.coordinator_layout)).perform(swipeUp()) + takeScreenshot<VaccinationListFragment>("incomplete_scrolled_down") + } + + @Screenshot + @Test + fun capture_screenshots_complete() { + + val listItems = listOf( + createQrCodeCardItem( + doseNumber = 2, + totalSeriesOfDoses = 2, + vaccinatedAt = LocalDate.parse("24.04.2021", formatter), + expiresAt = Instant.parse("2022-04-24T00:00:00.000Z") + ), + createNameCardItem(), + VaccinationListImmunityInformationCardItem(Duration.standardDays(14)), + createVaccinationCardItem( + doseNumber = 1, + totalSeriesOfDoses = 2, + vaccinationStatus = COMPLETE + ), + createVaccinationCardItem( + doseNumber = 2, + totalSeriesOfDoses = 2, + vaccinationStatus = COMPLETE, + vaccinatedAt = LocalDate.parse("24.04.2021", formatter) + ) + ) + + every { vaccinationListViewModel.uiState } returns mockUiState( + itemList = listItems, + vaccinationStatus = COMPLETE + ) + launchFragmentInContainer2<VaccinationListFragment>(fragmentArgs = fragmentArgs) + takeScreenshot<VaccinationListFragment>("complete") + onView(withId(R.id.coordinator_layout)).perform(swipeUp()) + takeScreenshot<VaccinationListFragment>("complete_scrolled_down") + } + + @Screenshot + @Test + fun capture_screenshots_immunity() { + val listItems = listOf( + createQrCodeCardItem( + doseNumber = 2, + totalSeriesOfDoses = 2, + vaccinatedAt = LocalDate.parse("24.04.2021", formatter), + expiresAt = Instant.parse("2022-04-24T00:00:00.000Z") + ), + createNameCardItem(), + createVaccinationCardItem( + doseNumber = 1, + totalSeriesOfDoses = 2, + vaccinationStatus = IMMUNITY + ), + createVaccinationCardItem( + doseNumber = 2, + totalSeriesOfDoses = 2, + vaccinationStatus = IMMUNITY, + vaccinatedAt = LocalDate.parse("24.04.2021", formatter) + ) + ) + + every { vaccinationListViewModel.uiState } returns mockUiState( + itemList = listItems, + vaccinationStatus = IMMUNITY + ) + launchFragmentInContainer2<VaccinationListFragment>(fragmentArgs = fragmentArgs) + takeScreenshot<VaccinationListFragment>("immunity") + onView(withId(R.id.coordinator_layout)).perform(swipeUp()) + takeScreenshot<VaccinationListFragment>("immunity_scrolled_down") + } + + private fun mockUiState(itemList: List<VaccinationListItem>, vaccinationStatus: VaccinatedPerson.Status) = + MutableLiveData( + VaccinationListViewModel.UiState( + listItems = itemList, + vaccinationStatus = vaccinationStatus + ) + ) + + private fun createVaccinationCardItem( + doseNumber: Int, + totalSeriesOfDoses: Int, + vaccinationStatus: VaccinatedPerson.Status, + vaccinatedAt: LocalDate = LocalDate.parse("12.04.2021", formatter) + ) = VaccinationListVaccinationCardItem( + vaccinationCertificateId = "vaccinationCertificateId", + doseNumber = doseNumber, + totalSeriesOfDoses = totalSeriesOfDoses, + vaccinatedAt = vaccinatedAt.toDayFormat(), + vaccinationStatus = vaccinationStatus, + isFinalVaccination = doseNumber == totalSeriesOfDoses, + onCardClick = {}, + onDeleteClick = {}, + onSwipeToDelete = { _, _ -> } + ) + + private fun createNameCardItem() = VaccinationListNameCardItem( + fullName = "Max Mustermann", + dayOfBirth = LocalDate.parse("01.02.1976", formatter).toDayFormat() + ) + + private fun createQrCodeCardItem( + doseNumber: Int, + totalSeriesOfDoses: Int, + vaccinatedAt: LocalDate = LocalDate.parse("12.04.2021", formatter), + expiresAt: Instant = Instant.parse("2022-04-12T00:00:00.000Z") + ) = VaccinationListQrCodeCardItem( + qrCode = testQrCode, + doseNumber = doseNumber, + totalSeriesOfDoses = totalSeriesOfDoses, + vaccinatedAt = vaccinatedAt, + expiresAt = expiresAt + ) {} + + @After + fun tearDown() { + clearAllViewModels() + } +} + +@Module +abstract class VaccinationListFragmentTestModule { + + @ContributesAndroidInjector + abstract fun vaccinationListFragment(): VaccinationListFragment +} diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt index 038042a5810542131a3ebe6ccb8f898fb435a572..937486ea384b8b2e3835c2dcc74aee533ff7a657 100644 --- a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt +++ b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt @@ -36,7 +36,9 @@ import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestModule import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestNegativeModule import de.rki.coronawarnapp.ui.submission.SubmissionYourConsentFragmentTestModule import de.rki.coronawarnapp.ui.tracing.TracingDetailsFragmentTestTestModule +import de.rki.coronawarnapp.ui.vaccination.VaccinationConsentFragmentTestModule import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragmentTestModule +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragmentTestModule @Module( includes = [ @@ -83,8 +85,10 @@ import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragmentTes CreateEventTestModule::class, TraceLocationsFragmentTestModule::class, QrCodeDetailFragmentTestModule::class, - // Vaccination Passport + // Vaccination VaccinationDetailsFragmentTestModule::class, + VaccinationConsentFragmentTestModule::class, + VaccinationListFragmentTestModule::class ] ) class FragmentTestModuleRegistrar diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/ViewActions.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/ViewActions.kt index ab0e0e65d36e005edde33439106fcfda24c0fb06..ca567a039bfa44626ec0aa88f9d770f1c183811b 100644 --- a/Corona-Warn-App/src/androidTest/java/testhelpers/ViewActions.kt +++ b/Corona-Warn-App/src/androidTest/java/testhelpers/ViewActions.kt @@ -13,9 +13,21 @@ import com.google.android.material.tabs.TabLayout import org.hamcrest.CoreMatchers.allOf import org.hamcrest.Matcher -fun recyclerScrollTo(position: Int? = null): ViewAction = RecyclerViewScrollAction(position) +fun recyclerScrollTo( + position: Int? = null, + additionalX: Int = 0, + additionalY: Int = 0, +): ViewAction = RecyclerViewScrollAction( + position = position, + additionalX = additionalX, + additionalY = additionalY +) -private class RecyclerViewScrollAction(private val position: Int? = null) : ViewAction { +private class RecyclerViewScrollAction( + private val position: Int? = null, + private val additionalX: Int = 0, + private val additionalY: Int = 0, +) : ViewAction { override fun getDescription(): String { return "scroll RecyclerView to bottom" } @@ -30,6 +42,8 @@ private class RecyclerViewScrollAction(private val position: Int? = null) : View val itemPosition = position ?: itemCount?.minus(1) ?: 0 recyclerView.scrollToPosition(itemPosition) uiController.loopMainThreadUntilIdle() + recyclerView.scrollBy(additionalX, additionalY) + uiController.loopMainThreadUntilIdle() } } diff --git a/Corona-Warn-App/src/deviceForTesters/res/drawable/test_qr_code.png b/Corona-Warn-App/src/debug/res/drawable/test_qr_code.png similarity index 100% rename from Corona-Warn-App/src/deviceForTesters/res/drawable/test_qr_code.png rename to Corona-Warn-App/src/debug/res/drawable/test_qr_code.png diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/miscinfo/MiscInfoFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/miscinfo/MiscInfoFragment.kt index 67b2d7be1fc7c38361c7923b8b463721a0928565..eea90254e92f696c8b64140a6a46f0a4a3479aa6 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/miscinfo/MiscInfoFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/miscinfo/MiscInfoFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.databinding.FragmentTestDeviceinfoBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -21,7 +21,7 @@ class MiscInfoFragment : Fragment(R.layout.fragment_test_deviceinfo), AutoInject @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: MiscInfoFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestDeviceinfoBinding by viewBindingLazy() + private val binding: FragmentTestDeviceinfoBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/appconfig/ui/AppConfigTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/appconfig/ui/AppConfigTestFragment.kt index c151d90a77c3853a014e640c38a5dce0d7f5305e..b6bcb6f1f1b083286e294e6441f4285d3715fc00 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/appconfig/ui/AppConfigTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/appconfig/ui/AppConfigTestFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.databinding.FragmentTestAppconfigBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.joda.time.DateTimeZone @@ -23,7 +23,7 @@ class AppConfigTestFragment : Fragment(R.layout.fragment_test_appconfig), AutoIn @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: AppConfigTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestAppconfigBinding by viewBindingLazy() + private val binding: FragmentTestAppconfigBinding by viewBinding() private val timeFormatter = ISODateTimeFormat.dateTime() .withZone(DateTimeZone.forID("Europe/Berlin")) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt index 3cf44a65b58741a7f91b905ec23c5ab1cf6537d2..4714387635d352abd0d7d74aa392cedac4a8bee4 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.ui.durationpicker.DurationPicker import de.rki.coronawarnapp.ui.durationpicker.toContactDiaryFormat 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.joda.time.Duration @@ -27,7 +27,7 @@ class ContactDiaryTestFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: ContactDiaryTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestContactDiaryBinding by viewBindingLazy() + private val binding: FragmentTestContactDiaryBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/coronatest/ui/CoronaTestTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/coronatest/ui/CoronaTestTestFragment.kt index db311e72acf102f8facc9498d1fb09c92ae2a9bb..16d5cdc4527c205bcc11b49f7efb91ffa3d56e22 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/coronatest/ui/CoronaTestTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/coronatest/ui/CoronaTestTestFragment.kt @@ -17,7 +17,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.permission.CameraPermissionHelper import de.rki.coronawarnapp.util.tryHumanReadableError import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -28,7 +28,7 @@ class CoronaTestTestFragment : Fragment(R.layout.fragment_test_coronatest), Auto @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: CoronaTestTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestCoronatestBinding by viewBindingLazy() + private val binding: FragmentTestCoronatestBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportDetailsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportDetailsFragment.kt index f7b9ce4dbc002399282e8297029ed970fa3ec50b..4c7eb42705f41f73bc607f973050024adc0811c1 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportDetailsFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportDetailsFragment.kt @@ -8,7 +8,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSettingsCrashReportDetailsBinding 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -21,7 +21,7 @@ class SettingsCrashReportDetailsFragment : ownerProducer = { requireActivity().viewModelStore }, factoryProducer = { viewModelFactory } ) - private val fragmentSettingsCrashReportDetailsBinding: FragmentSettingsCrashReportDetailsBinding by viewBindingLazy() + private val fragmentSettingsCrashReportDetailsBinding: FragmentSettingsCrashReportDetailsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportFragment.kt index 9268d0cdefb3d4c4250d39ae10dea7bced9c412d..e4b5894a44829a57da7e1518bce830ba30b7fc80 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/crash.ui/SettingsCrashReportFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import timber.log.Timber @@ -24,7 +24,7 @@ class SettingsCrashReportFragment : Fragment(R.layout.fragment_crashreporter_ove factoryProducer = { viewModelFactory } ) - private val fragmentCrashreporterOverviewBinding: FragmentCrashreporterOverviewBinding by viewBindingLazy() + private val fragmentCrashreporterOverviewBinding: FragmentCrashreporterOverviewBinding by viewBinding() private lateinit var adapter: CrashReportAdapter override fun onCreate(savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt index 26659a70227711ac3798bacb43f4e89b198f3212..ee563f4199bb1fa381e6fdbbfe3d5d98db8bd3f3 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/datadonation/ui/DataDonationTestFragment.kt @@ -19,7 +19,7 @@ import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.tryHumanReadableError import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.json.JSONObject @@ -31,7 +31,7 @@ class DataDonationTestFragment : Fragment(R.layout.fragment_test_datadonation), @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: DataDonationTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestDatadonationBinding by viewBindingLazy() + private val binding: FragmentTestDatadonationBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt index 1c1441fb24dba0532ac10ff9c8f31bb9695f4b4e..7c18b62ce80dbb7d1966fd375d7b6a97519545de 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.databinding.FragmentTestDebugoptionsBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -26,7 +26,7 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: DebugOptionsFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestDebugoptionsBinding by viewBindingLazy() + private val binding: FragmentTestDebugoptionsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -71,7 +71,6 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto environmentCdnurlVerification.text = "Verification CDN:\n${state.urlVerification}" environmentUrlDatadonation.text = "DataDonation:\n${state.urlDataDonation}" environmentUrlLogUpload.text = "LogUpload:\n${state.urlLogUpload}" - environmentCdnUrlVaccination.text = "Vaccination CDN: \n${state.urlVaccination}" environmentPubkeyCrowdnotifier.text = "CrowdNotifierPubKey:\n${state.pubKeyCrowdNotifier}" environmentPubkeyAppconfig.text = "AppConfigPubKey:\n${state.pubKeyAppConfig}" } diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt index 604996995a54bc7ef8e0e241e677d3588afa17ce..c9b907793ab6812a252f519c71a9bee66af2387a 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/EnvironmentState.kt @@ -10,7 +10,6 @@ data class EnvironmentState( val urlVerification: String, val urlDataDonation: String, val urlLogUpload: String, - val urlVaccination: String, val pubKeyCrowdNotifier: String, val pubKeyAppConfig: String, ) { @@ -23,7 +22,6 @@ data class EnvironmentState( urlVerification = verificationCdnUrl, urlDataDonation = dataDonationCdnUrl, urlLogUpload = logUploadServerUrl, - urlVaccination = vaccinationCdnUrl, pubKeyCrowdNotifier = crowdNotifierPublicKey, pubKeyAppConfig = appConfigPublicKey, ) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt index a11cf74e0d51080c3619ad5e360b80b439e846a7..17a54fe5bd151c50edc615498a16f18994dd291d 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt @@ -8,7 +8,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentTestDeltaonboardingBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -19,7 +19,7 @@ class DeltaonboardingFragment : Fragment(R.layout.fragment_test_deltaonboarding) @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: DeltaOnboardingFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestDeltaonboardingBinding by viewBindingLazy() + private val binding: FragmentTestDeltaonboardingBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragment.kt index 7983ba7decb18272f7b0f5266c72786a13ec113c..841e52ebb543c55bec62c9c4b4f9ee683e5666ef 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/hometestcards/ui/HomeTestCardsFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -24,7 +24,7 @@ class HomeTestCardsFragment : Fragment(R.layout.fragment_test_home_test_cards_la @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: HomeTestCardsFragmentViewModel by cwaViewModels { viewModelFactory } - val binding: FragmentTestHomeTestCardsLayoutBinding by viewBindingLazy() + val binding: FragmentTestHomeTestCardsLayoutBinding by viewBinding() private val homeAdapter = HomeAdapter() diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/keydownload/ui/KeyDownloadTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/keydownload/ui/KeyDownloadTestFragment.kt index 4ef7851fb2c31975621c3e299f37caf508bab83a..14dd2b7c3e8b5f26ff72be7c655b538ed479ada3 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/keydownload/ui/KeyDownloadTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/keydownload/ui/KeyDownloadTestFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -24,7 +24,7 @@ class KeyDownloadTestFragment : Fragment(R.layout.fragment_test_keydownload), Au @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: KeyDownloadTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestKeydownloadBinding by viewBindingLazy() + private val binding: FragmentTestKeydownloadBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt index 8ccbcf5f5490cd8f634ad1780f7d1345b38592d6..9e859a8926e7c3488bf8e0c66fb2b297a69c1942 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/menu/ui/TestMenuFragment.kt @@ -9,7 +9,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentTestMenuBinding 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -19,7 +19,7 @@ class TestMenuFragment : Fragment(R.layout.fragment_test_menu), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: TestMenuFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestMenuBinding by viewBindingLazy() + private val binding: FragmentTestMenuBinding by viewBinding() @Inject lateinit var menuAdapter: TestMenuAdapter diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/playground/ui/PlaygroundFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/playground/ui/PlaygroundFragment.kt index 82abd140ca37879355c243effa1dada36922f96d..e2a173fe2c6e6edc516f9ee3cda96c7602600842 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/playground/ui/PlaygroundFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/playground/ui/PlaygroundFragment.kt @@ -11,7 +11,7 @@ import de.rki.coronawarnapp.datadonation.analytics.ui.input.AnalyticsUserInputFr import de.rki.coronawarnapp.datadonation.analytics.ui.input.AnalyticsUserInputFragmentArgs import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -22,7 +22,7 @@ class PlaygroundFragment : Fragment(R.layout.fragment_test_playground), AutoInje @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: PlaygroundViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestPlaygroundBinding by viewBindingLazy() + private val binding: FragmentTestPlaygroundBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragment.kt index df4137e7ea3f37172547d6fce752f39beb97ff1a..6bb2421293615918ff039779c0a775d4138c7187 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestFragment.kt @@ -19,7 +19,7 @@ import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -30,7 +30,7 @@ class PresenceTracingTestFragment : Fragment(R.layout.fragment_test_presence_tra @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: PresenceTracingTestViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestPresenceTracingBinding by viewBindingLazy() + private val binding: FragmentTestPresenceTracingBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt index c4aa4a257925c75f84e399058b78d5abfc9eddb6..62b579655527bc019393f45e4028f1523af0b460 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/poster/QrCodePosterTestFragment.kt @@ -28,7 +28,7 @@ import de.rki.coronawarnapp.ui.print.PrintingAdapter import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -51,7 +51,7 @@ class QrCodePosterTestFragment : Fragment(R.layout.fragment_test_qr_code_poster) private var itemId = -1 - private val binding: FragmentTestQrCodePosterBinding by viewBindingLazy() + private val binding: FragmentTestQrCodePosterBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt index d4c56ea83e3f8753fa506dddc816ffc5027b98a3..d8e1a5ba4f928dbaad8591c69ecc345a7150577a 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/risklevel/ui/TestRiskLevelCalculationFragment.kt @@ -18,7 +18,7 @@ import de.rki.coronawarnapp.storage.TestSettings import de.rki.coronawarnapp.test.menu.ui.TestMenuItem 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -39,7 +39,7 @@ class TestRiskLevelCalculationFragment : } ) - private val binding: FragmentTestRiskLevelCalculationBinding by viewBindingLazy() + private val binding: FragmentTestRiskLevelCalculationBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt index 5281b569b4fe3d20f13c0f176603b50d21f8ba83..5b08b0ce3206c87c435f004ce0f36dcf3c585b53 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/submission/ui/SubmissionTestFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.tracing.ui.TracingConsentDialog import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -23,7 +23,7 @@ class SubmissionTestFragment : Fragment(R.layout.fragment_test_submission), Auto @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: SubmissionTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestSubmissionBinding by viewBindingLazy() + private val binding: FragmentTestSubmissionBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/tasks/ui/TestTaskControllerFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/tasks/ui/TestTaskControllerFragment.kt index 13ccbc2e9a73f15b4bd2b52bcbe143d9d879022b..07cb7c986165940fec6c105d51c46fac51b35aca 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/tasks/ui/TestTaskControllerFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/tasks/ui/TestTaskControllerFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.databinding.FragmentTestTaskControllerBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -21,7 +21,7 @@ class TestTaskControllerFragment : Fragment(R.layout.fragment_test_task_controll @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: TestTaskControllerFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestTaskControllerBinding by viewBindingLazy() + private val binding: FragmentTestTaskControllerBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt index 0c8f3dafe73f689994352de0b5e776b84c2cc510..97cc21c5f6e96f4c5176c7c834cd97305b93ec87 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt @@ -9,7 +9,7 @@ import de.rki.coronawarnapp.databinding.FragmentTestVaccinationBinding import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -20,7 +20,7 @@ class VaccinationTestFragment : Fragment(R.layout.fragment_test_vaccination), Au @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: VaccinationTestFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTestVaccinationBinding by viewBindingLazy() + private val binding: FragmentTestVaccinationBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml index 60061a05c16fe75d0af8856d12ffec4d6388853b..165e76a5873ac28d6015f1d63ec99802ff2c4a4f 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_debugoptions.xml @@ -109,14 +109,6 @@ android:layout_marginTop="4dp" tools:text="LogUpload: ?" /> - <TextView - android:id="@+id/environment_cdn_url_vaccination" - style="@style/TextAppearance.MaterialComponents.Caption" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="4dp" - tools:text="Vaccination: ?" /> - <TextView android:id="@+id/environment_pubkey_appconfig" style="@style/TextAppearance.MaterialComponents.Caption" diff --git a/Corona-Warn-App/src/main/assets/privacy_de.html b/Corona-Warn-App/src/main/assets/privacy_de.html index 554e2c1e1f3479d7d99881f4ac81881d58a66fb2..d07e702a1e17005b76827a5865f8bb8df6011a31 100644 --- a/Corona-Warn-App/src/main/assets/privacy_de.html +++ b/Corona-Warn-App/src/main/assets/privacy_de.html @@ -89,10 +89,11 @@ Sie eine auf Ihren Namen ausgestellte Bestätigung für negative Schnelltest-Ergebnisse anzeigen lassen können (siehe hierzu Punkt 6 c.) sowie die Funktion zum Anlegen eines „Schnelltest-Profils“, mit der Sie einer Teststelle die zur Durchführung eines Schnelltests - erforderlichen Daten bereitstellen können (siehe hierzu Punkt 6 d.). -</p> - -<p> + erforderlichen Daten bereitstellen können (siehe hierzu Punkt 6 d.). Die App verzichtet + standardmäßig auf die Auswertung Ihres Nutzungsverhaltens durch Analyse-Tools. Nur wenn Sie + ausdrücklich der freiwilligen Datenspende zustimmen oder einen Fehlerbericht aufzeichnen und mit + dem RKI teilen, werden bestimmte Daten über Ihre Nutzung der App an das RKI übermittelt (siehe + hierzu Punkt 5 i. und Punkt 5 k.). Die App verzichtet standardmäßig auf die Auswertung Ihres Nutzungsverhaltens durch Analyse-Tools. Nur wenn Sie ausdrücklich der freiwilligen Datenspende zustimmen, werden bestimmte Daten über Ihre Nutzung der App an das RKI übermittelt (siehe hierzu Punkt 5 h.). @@ -185,7 +186,7 @@ Smartphone nicht über diese Zufalls-IDs identifiziert werden kann. Die von Ihrem Smartphone ausgesendeten eigenen Begegnungsdaten und die aufgezeichneten Begegnungsdaten der Personen, mit denen Sie Kontakt hatten, - werden auf Ihrem Smartphone gespeichert und jeweils nach 14 Tage gelöscht. + werden auf Ihrem Smartphone gespeichert und jeweils nach 14 Tagen gelöscht. Auf die gleiche Weise werden Ihre ausgesendeten Begegnungsdaten verarbeitet, wenn sie von den Smartphones anderer App-Nutzer aufgezeichnet werden. @@ -268,7 +269,7 @@ </p> <p> Außerdem wird standardmäßig ein Eintrag in Ihrem Kontakt-Tagebuch angelegt. Die Einzelheiten - hierzu werden unter Punkt 5.g. und 6.g. erläutert. Wenn Sie für ein Event oder Ort keinen + hierzu werden unter Punkt 5 g. und 6 g. erläutert. Wenn Sie für ein Event oder Ort keinen Eintrag in Ihrem Kontakt-Tagebuch anlegen möchten, können Sie diese Funktion einfach über den entsprechenden Schieberegler ausschalten. </p> @@ -311,7 +312,10 @@ vor einer möglichen Ansteckung warnen </li> <li> - wenn Sie Angaben zum Beginn von eventuellen Corona-Symptomen machen + wenn Sie Angaben zum Beginn von eventuellen Corona-Symptomen machen oder + </li> + <li> + wenn Sie digitale Impfzertifikate in der App hinzufügen. </li> </ul> <p> @@ -344,7 +348,34 @@ </p> <h3> - h. Nutzungsdaten (Datenspende) + h. Daten über Ihre Corona-Impfung +</h3> +<p> + Sie können Ihre Impfzertifikate in der App hinzufügen, die Sie bei der Impfung erhalten haben. + Die Anforderung des digitalen Impfzertifikats ist freiwillig. Sollten Sie dieses Angebot + wahrnehmen, erhalten Sie bei der Impfung einen Ausdruck mit einem QR-Code. In diesem sind die + folgenden Daten zu Ihrer Corona-Impfung kodiert: +</p> +<ul> + <li> + Daten zu Ihrer Person (Name, Vorname, Geburtsdatum) + </li> + <li> + Informationen zum Impfstoff (Krankheit, Impfstoff, Produkt, Hersteller) + </li> + <li> + Informationen zur Impfung (Dosennummer, Gesamtdosen, Impfdatum, Land, Aussteller) + </li> + <li> + Eindeutige Kennung des Impfnachweises + </li> +</ul> +<p> + Die Daten werden in der App gespeichert, sobald Sie den QR-Code zum digitalen Impfzertifikat + scannen. Diese Daten wurden zuvor bei Ihrer Impfung erhoben. +</p> +<h3> + i. Nutzungsdaten (Datenspende) </h3> <p> @@ -420,10 +451,10 @@ <p> Die Teilnahme an der Datenspende ist freiwillig. Die Aktivierung der Datenspende setzt die Bestätigung der Echtheit Ihrer App voraus (Beachten Sie bitte die weiteren Informationen hierzu - unter Punkt 5 j. und Punkt 11). + unter Punkt 5 l. und Punkt 11). </p> <h3> - i. Teilnahme an einer Befragung + j. Teilnahme an einer Befragung </h3> <p> Einigen Nutzern wird in der App die Teilnahme an einer Befragung des RKI angeboten. In der Regel @@ -442,7 +473,65 @@ </p> <h3> - j. Bestätigung der Echtheit Ihrer App + k. Inhalte der Fehlerberichte +</h3> +<p> + Um den technischen Support der App bei der Fehleranalyse zu unterstützen, können Sie in der App + einen Fehlerbericht aufzeichnen. Wenn Sie die Aufzeichnung des Fehlerberichts starten, werden +</p> +<ul> + <li> + Ihre Bedienschritte in der App, + </li> + <li> + die technischen Schritte und Abläufe sowie Statusmeldungen + <ul> + <li> + zur Risiko-Ermittlung (z.B. zur Funktionsweise der Verarbeitung der Begegnungsdaten, + der Berechnung des Ansteckungsrisikos, der Aktualisierung der Positiv-Listen, der + Anzeige des errechneten Risikostatus + </li> + <li> + zum Abruf und der Anzeige von Testergebnissen und + </li> + <li> + zu möglichen Vorgängen zur Warnung Anderer (z.B. die Berechnung von + Übertragungsrisiko-Werten und die technische Bereitstellung Ihrer Zufalls-IDs durch + Ihr Smartphone) + </li> + </ul> + </li> +</ul> +<p> + umfassend aufgezeichnet und auf Ihrem Smartphone gespeichert. Im Fehlerbericht können auch + Gesundheitsdaten enthalten sein, weil auch die technischen Schritte und Abläufe im Zusammenhang + mit der Erkennung einer Risiko-Begegnung aufgezeichnet werden. +</p> +<p> + Der Fehlerbericht enthält jedoch keine Informationen über QR-Codes für die Testregistrierung, + das in Ihrer App gespeicherte Token (siehe dazu unten Punkt 6 b. unter „Testergebnis abrufen“), + Schnelltest-Ergebnisse, Impfzertifikate und Einträge in Ihrem Kontakt-Tagebuch. Der + Fehlerbericht enthält auch nicht Ihren Namen oder andere Angaben, mit denen Sie vom RKI + identifiziert werden können. +</p> +<p> + Sie können die Aufzeichnung des Fehlerberichts jederzeit stoppen und den Fehlerbericht löschen. + Wenn Sie sich entscheiden, den Fehlerbericht mit dem RKI zu teilen, erhalten Sie über die App + eine Kennung zu Ihrem Fehlerbericht (Fehlerbericht-ID). Mit der Fehlerbericht-ID ermöglichen Sie + dem RKI die Zuordnung Ihres Fehlerberichts zu weiteren Informationen, die Sie dem technischen + Support gesondert mitteilen, z.B. wenn Sie noch eine Fehlerbeschreibung per E-Mail bereitstellen + möchten. Wenn Sie dem technischen Support Ihre Fehlerbericht-ID mitteilen, kann anhand dieser + weiteren Informationen möglicherweise eine Verbindung zu Ihrer Person hergestellt werden. +</p> +<p> + Die Erstellung und Übersendung eines Fehlerberichts an das RKI ist freiwillig. Sie entscheiden + selbst darüber, ob Sie einen Fehlerbericht aufzeichnen möchten und diesen an den technischen + Support der App übersenden. Die Übersendung des Fehlerberichts setzt die Bestätigung der + Echtheit Ihrer App voraus (Beachten Sie bitte die weiteren Informationen hierzu unter Punkt 5 l. + und Punkt 11). +</p> +<h3> + l. Bestätigung der Echtheit Ihrer App </h3> <p> Einige Funktionen der App setzen voraus, dass vorab die Echtheit Ihrer App geprüft und gegenüber @@ -768,7 +857,42 @@ </p> <h3> - h. Datenspende + h. Digitaler Impfnachweis + +</h3> +<p> + Die App erlaubt es Ihnen, Ihre Impfzertifikate zu speichern und in digitaler Form bei sich zu + führen. Bei Bedarf können Sie dann die App nutzen, um in den gesetzlich vorgesehenen Fällen + nachzuweisen, dass bei Ihnen eine vollständige Schutzimpfung gegen das Coronavirus durchgeführt + wurde. +</p> +<p> + Um ein Impfzertifikat in der App hinzuzufügen, scannen Sie den QR-Code, den Sie bei der Impfung + erhalten haben. Die App liest die Daten zu Ihrer Impfung aus dem QR-Code aus und speichert sie + in einem gesicherten Bereich Ihres Smartphones. +</p> +<p> + 14 Tage nach der letzten erforderlichen Impfung wird auf dem Homescreen in der App angezeigt, + dass Ihr Impfschutz vollständig ist. Zum Nachweis können Sie den in der App dargestellten + QR-Code des digitalen Impfnachweises vorzeigen. Mit der offiziellen Prüf-App kann dieser QR-Code + gescannt werden, die Daten über Ihre Corona-Impfung werden dabei ausgelesen. In der Prüf-App + wird dann angezeigt, ob Ihr Impfschutz vollständig ist. Zusätzlich werden auch Ihr Name und Ihr + Geburtsdatum angezeigt, damit die prüfende Person diese Angaben mit Ihrem offiziellen + Ausweisdokument abgleichen kann. +</p> +<p> + Bitte beachten Sie, dass die Verwendung der Funktion zum Speichern Ihrer Impfzertifikate in der + App freiwillig ist. Sie können Ihren Impfschutz in den gesetzlich vorgesehenen Fällen auch auf + andere Weise nachweisen. +</p> +<p> + Bitte beachten Sie, dass der QR-Code Ihres digitalen Impfnachweises Ihre Daten über Ihre + Corona-Impfung enthält. Zeigen Sie diesen nur vor, wenn Sie Ihren Impfstatus nachweisen möchten. + Stellen Sie die Impfzertifikate und QR-Codes niemandem zur Verfügung, wenn Sie nicht wollen, + dass die Daten ausgelesen werden. +</p> +<h3> + i. Datenspende </h3> <p> @@ -810,7 +934,24 @@ oder wen Sie getroffen haben. </p> <h3> - i. Befragungen + j. Fehlerberichte +</h3> +<p> + Das RKI ist bemüht, eine fehlerfreie App anzubieten. Aufgrund der großen Anzahl verschiedener + Systeme kann dies jedoch nicht immer gewährleistet werden. Um den technischen Support der App + bei der Fehleranalyse zu unterstützen, können Sie den in Ihrer App erstellten Fehlerbericht an + das RKI übermitteln. Das RKI wird den Fehlerbericht auswerten, um die Ursache der in Ihrer App + auftretenden Fehler erkennen und beseitigen zu können. +</p> +<p> + Die Fehlerberichte werden ohne jeden Zusammenhang mit Ihrem Namen oder Ihrer Identität + vorübergehend gespeichert und im Rahmen der Fehleranalyse ausgewertet. Das RKI erfährt also + nicht, wer Sie sind oder wen Sie getroffen haben. Beachten Sie bitte, dass sich Hinweise auf + Ihre Identität ergeben können, wenn Sie dem technischen Support Ihre Fehlerbericht-ID unter + Offenlegung Ihrer Identität (z. B. per E-Mail) mitteilen. +</p> +<h3> + k. Befragungen </h3> <p> Befragungen finden auf einer Webseite außerhalb der App statt, auf die Sie weitergeleitet @@ -819,7 +960,7 @@ Befragung auf der Befragungs-Webseite beschrieben. </p> <h3> - j. Bestätigung der Echtheit Ihrer App + l. Bestätigung der Echtheit Ihrer App </h3> <p> Zur Bestätigung der Echtheit Ihrer App wird eine Funktion des Betriebssystems Ihres Smartphones @@ -1039,7 +1180,8 @@ Einchecken zu einem Event oder an einem Ort übernommene Einträge im Kontakt-Tagebuch auch nach der Löschung des zugehörigen Check-Ins dort noch gespeichert sind. Wenn Sie Ihr Schnelltest-Profil einmal angelegt haben, bleibt dieses so lange in der App gespeichert, bis Sie - es selbst wieder löschen. + es selbst wieder löschen. Wenn Sie Impfzertifikate gescannt haben, bleiben auch diese so lange + in der App gespeichert, bis Sie sie selbst wieder löschen. </p> <h3> @@ -1062,7 +1204,15 @@ übermittelt werden, werden nach 180 Tagen gelöscht. </p> <h3> - d. Bestätigung der Echtheit Ihrer App + d. Fehlerberichte +</h3> +<p> + Sie können einen aufgezeichneten Fehlerbericht auf Ihrem Smartphone jederzeit löschen. + Fehlerberichte, die Sie an den technischen Support übersandt haben, werden spätestens nach 14 + Tagen gelöscht. +</p> +<h3> + e. Bestätigung der Echtheit Ihrer App </h3> <p> Die Kennungen, die Ihr Smartphone zur Bestätigung der Echtheit Ihrer App erzeugt, werden nach 30 @@ -1218,7 +1368,18 @@ aktivieren. </p> <h3> - f. Einverständnis „Befragung“ + f. Einverständnis „Fehlerberichte“ +</h3> +<p> + Ihr Einverständnis zur Analyse von bereits an das RKI übermittelten Fehlerberichten können Sie + zurücknehmen, indem Sie dem technischen Support unter Nennung Ihrer Fehlerbericht-ID mitteilen, + dass Sie die Analyse des Fehlerberichts nicht mehr wünschen. Ihr Fehlerbericht wird dann + gelöscht. Bitte beachten Sie, dass das RKI dabei Ihre Identität erfahren kann. Wenn Sie dem + technischen Support Ihre Fehlerbericht-ID nicht mitteilen, wird der übermittelte Fehlerbericht + automatisch nach 14 Tagen gelöscht. +</p> +<h3> + g. Einverständnis „Befragung“ </h3> <p> Ihr Einverständnis zur Teilnahme an einer Befragung des RKI erteilen Sie nicht in der App, @@ -1226,7 +1387,7 @@ beschrieben, wie Sie Ihr Einverständnis zurücknehmen können. </p> <h3> - g. Einverständnis „Bestätigung der Echtheit Ihrer App“ + h. Einverständnis „Bestätigung der Echtheit Ihrer App“ </h3> <p> Wenn Sie Ihr Einverständnis zur Bestätigung der Echtheit Ihrer App zurücknehmen, hat dies keine @@ -1295,5 +1456,6 @@ <a href="mailto:datenschutz@rki.de">datenschutz@rki.de</a>. </p> <p> - Stand: 12.05.2021 -</p> \ No newline at end of file + Stand: 28.05.2021 +</p> + diff --git a/Corona-Warn-App/src/main/assets/privacy_en.html b/Corona-Warn-App/src/main/assets/privacy_en.html index eb20192d522c7931cd2a8d17fc287e8016d335f3..3cab6eaf586af2ed48b5f696178842a32787b41b 100644 --- a/Corona-Warn-App/src/main/assets/privacy_en.html +++ b/Corona-Warn-App/src/main/assets/privacy_en.html @@ -97,8 +97,9 @@ </p> <p> The app refrains by default from using analysis tools to evaluate the way you use it. Only if - you expressly agree to voluntarily share data (see Section 5 h.), will certain data about your - use of the app be transmitted to the RKI. + you expressly agree to voluntarily share data or to record an error report and share it with the + RKI (see Sections 5 i. and 5 k.), will certain data about your use of the app be transmitted to + the RKI. </p> <p> @@ -310,7 +311,10 @@ same time that they may be infected </li> <li> - If you provide information about the onset of any coronavirus symptoms. + If you provide information about the onset of any coronavirus symptoms or + </li> + <li> + If you add digital vaccination certificates in the app. </li> </ul> <p> @@ -341,7 +345,35 @@ </p> <h3> - h. Usage Data (data sharing) + h. Data about your COVID-19 vaccination + +</h3> +<p> + In the app, it is possible to add your vaccination certificates that you received when you were + vaccinated. Requesting a digital vaccination certificate is voluntary. If you choose to use this + service, you will receive a printout with a QR code at the time of your vaccination. This will + contain the following data about your COVID-19 vaccination in encoded form: +</p> +<ul> + <li> + Personal data (last name, first name, date of birth) + </li> + <li> + Information about the vaccine (disease, vaccine, product, manufacturer) + </li> + <li> + Vaccination information (dose number, total doses, date of vaccination, country, issuer) + </li> + <li> + Unique certificate identifier. + </li> +</ul> +<p> + The data will be stored in the app as soon as you scan the QR code for the digital vaccination + certificate. This data will have been collected previously at the time of your vaccination. +</p> +<h3> + i. Usage Data (data sharing) </h3> <p> @@ -402,10 +434,10 @@ <p> Participation in data sharing is voluntary. To enable the data sharing feature, the authenticity of your app first needs to be confirmed (please note the further information about this under - Sections 5 j. and 11). + Sections 5 l. and 11). </p> <h3> - i. Participation in a survey + j. Participation in a survey </h3> <p> Some app users are offered to participate in a survey by the RKI. This offer to participate in @@ -423,8 +455,61 @@ </p> <h3> - j. Confirmation of the authenticity of your app - + k. Contents of the error reports +</h3> +<p> + To assist the app’s technical support team with error analysis, you can record an error report + in the app. When you start recording the error report, a comprehensive record is made of +</p> +<ul> + <li> + the steps you take in the app + </li> + <li> + the technical steps and processes as well as status messages involving + <ul> + <li> + exposure logging (e.g. involving the functioning of the processing of exposure data, + the calculation of the risk of infection, the updating of the positive lists, the + display of the calculated risk status), + </li> + <li> + the retrieval and display of test results, and + </li> + <li> + possible processes for warning others (e.g. the calculation of transmission risk + values and the technical provision of your random IDs by your smartphone) + </li> + </ul> + </li> +</ul> +<p> + and stored on your smartphone. The error report may also contain health data, because the + technical steps and processes related to the detection of a possible exposure are also recorded. +</p> +<p> + However, the error report does not contain information about QR codes for test registration, the + token stored in your app (see “Retrieving a test result†in Section 6 b. below) rapid test + results, vaccination certificates and entries in your contact journal. Furthermore, the error + report does not contain your name or other information with which the RKI can identify you. +</p> +<p> + You can stop recording the error report and delete the error report at any time. If you choose + to share the error report with the RKI, you will receive an identifier for your error report + (error report ID) via the app. The error report ID allows the RKI to assign your error report to + further information that you provide separately to the technical support team, e.g. if you also + wish to provide a description of the error by email. If you provide your error report ID to the + technical support team, it may be possible to establish a link to you based on this further + information. +</p> +<p> + Creating and sending an error report to the RKI is voluntary. You decide yourself whether you + want to record an error report and send it to the app’s technical support team. To send the + error report, the authenticity of your app first needs to be confirmed (please note the further + information about this in Sections 5 l. and 11). +</p> +<h3> + l. Confirmation of the authenticity of your app </h3> <p> Before you can use some of the app’s features, the authenticity of your app first needs to be @@ -736,8 +821,40 @@ </p> <h3> - h. Data sharing - + h. Digital vaccination certificate +</h3> +<p> + The app allows you to save your vaccination certificates and keep them with you in digital form. + If necessary, you can then use the app to prove that you have been fully vaccinated against + coronavirus if required by law. +</p> +<p> + To add a vaccination certificate in the app, scan the QR code you received when you were + vaccinated. The app will read the information about your vaccination from the QR code and store + it in a secure area on your smartphone. +</p> +<p> + Fourteen days after receiving the last vaccination dose required, the home screen in the app + will show that you are fully vaccinated. To prove this, you can show the QR code from your + digital vaccination certificate, which will be displayed in the app. The official verification + app can be used to scan this QR code and read the information about your COVID-19 vaccination. + The verification app will then show whether you are fully vaccinated. In addition, your name and + date of birth will also be displayed so that the person verifying your vaccination status can + check this information against your official identification document. +</p> +<p> + Please note that using the feature for saving your vaccination certificates in the app is + voluntary. If you are required by law to prove that you have been vaccinated, then you can also + do this in other ways. +</p> +<p> + Please note that the QR code from your digital vaccination certificate contains your COVID-19 + vaccination details. You should only show it if you wish to prove your vaccination status. Do + not provide vaccination certificates or QR codes to anyone if you do not want the data to be + read. +</p> +<h3> + i. Data sharing </h3> <p> Data sharing is an additional feature of the app. The usage data and other voluntary information @@ -779,8 +896,23 @@ </p> <h3> - i. Surveys - + j. Error reports +</h3> +<p> + The RKI strives to offer a bug-free app. However, due to the large number of different systems + involved, this cannot always be guaranteed. To assist the app’s technical support team with + error analysis, you can send the error report that has been recorded in your app to the RKI. The + RKI will analyse the error report in order to be able to identify and eliminate the cause of the + errors that occur in your app. +</p> +<p> + For the error analysis, the error reports will be temporarily stored and analysed without any + connection to your name or identity. This means the RKI will not find out who you are or who you + have met. Please note that if you provide your error report ID to the technical support team + (e.g. by email), this may reveal information about your identity. +</p> +<h3> + k. Surveys </h3> <p> The surveys take place on a website outside of the app, which you will be redirected to. The app @@ -789,7 +921,7 @@ </p> <h3> - j. Confirmation of the authenticity of your app + l. Confirmation of the authenticity of your app </h3> <p> @@ -1004,7 +1136,8 @@ time. Please note that if entries are added to the contact journal when you check in at an event or place, these will still be stored there even after you delete the associated check-in. Once you have created your rapid test profile, it will be stored in the app until you delete it - yourself. + yourself. Once you have scanned your vaccination certificates, these will also be stored in the + app until you delete them yourself. </p> <h3> @@ -1026,8 +1159,14 @@ will be deleted after 180 days. </p> <h3> - d. Confirmation of the authenticity of your app - + d. Error reports +</h3> +<p> + You can delete a recorded error report on your smartphone at any time. Error reports that you + have sent to the technical support team will be deleted after 14 days at the latest. +</p> +<h3> + e. Confirmation of the authenticity of your app </h3> <p> The identifier generated by your smartphone to confirm the authenticity of your app will be @@ -1087,7 +1226,7 @@ </p> <p> - In addition, the confirmation of the authenticity of your app may involve the transfer of data + The EU has issued an adequacy decision for Switzerland, which determines the adequacy of the level of data protection in the country (Art. 45 GDPR). In addition, please note that users can retrieve the latest positive lists regardless of where they are (even if they are abroad on holiday or on a business trip, for example). In addition, the confirmation of the authenticity of your app may involve the transfer of data to a country outside the EU. The identifier generated by your smartphone, which contains information about the version of your smartphone and the app, will be transmitted to the provider of your smartphone’s operating system (Apple or Google). This may result in data being @@ -1117,7 +1256,7 @@ </p> <h3> - a. Consent to "exposure logging" + a. Consent to “exposure logging†</h3> <p> @@ -1195,8 +1334,17 @@ </p> <h3> - f. Consent to “survey participation†- + f. Consent to “error reports†+</h3> +<p> + You can withdraw your consent to the analysis of error reports already submitted to the RKI by + informing the technical support team that you no longer wish to have the error report analysed, + stating your error report ID. Your error report will then be deleted. Please note that the RKI + may learn your identity in the process. If you do not provide your error report ID to the + technical support team, the submitted error report will be automatically deleted after 14 days. +</p> +<h3> + g. Consent to “survey participation†</h3> <p> You do not give your consent to participate in an RKI survey in the app, but via the website on @@ -1205,7 +1353,7 @@ </p> <h3> - g. Consent to “confirmation of the authenticity of your app†+ h. Consent to “confirmation of the authenticity of your app†</h3> <p> @@ -1272,5 +1420,5 @@ 13353 Berlin, or by emailing <a href="mailto:datenschutz@rki.de">datenschutz@rki.de</a>. </p> <p> - Last amended: 12 May 2021 -</p> \ No newline at end of file + Last amended: 28 May 2021 +</p> diff --git a/Corona-Warn-App/src/main/assets/privacy_tr.html b/Corona-Warn-App/src/main/assets/privacy_tr.html index 19c11bba1c11f568d76f0e4057367e5509649990..e8ea93be63cf2ea3f718825d721fc9d8181c4773 100644 --- a/Corona-Warn-App/src/main/assets/privacy_tr.html +++ b/Corona-Warn-App/src/main/assets/privacy_tr.html @@ -28,7 +28,7 @@ terimler içermeyen bir metin hazırladık. </p> <h2> - 1. Corona-Warn-App’ın yayımcısı kimdir? + 1. Corona-Warn-App’ın yayımcısı kimdir? </h2> <p> Bu Uygulama, Almanya Federal Hükümeti için Robert Koch-Institut (Robert Koch Enstitüsü) @@ -44,7 +44,7 @@ müştereken sorumlu olur. Ayrıntılar için Madde 7’ye bakın. </p> <h2> - 2. Uygulamanın kullanılması isteğe bağlı mı? + 2. Uygulamanın kullanılması isteğe bağlı mı? </h2> <p> Uygulamanın kullanılması isteğe bağlıdır. Uygulamayı yüklemeniz, Uygulamanın hangi işlevlerini @@ -74,7 +74,7 @@ Uygulama, en az 16 yaşında olan ve Almanya’da yaşayan kişilere yönelik hazırlanmıştır. </p> <h2> - 5. Hangi veriler işlenir? + 5. Hangi veriler işlenir? </h2> <p> Uygulamanın tüm sistemi, mümkün olduğunca az kişisel verileri işleyecek şekilde @@ -90,15 +90,15 @@ <p> Dolayısıyla Uygulama, standart olarak analiz araçları üzerinden kullanıcı davranışınızın herhangi bir değerlendirmesini yapmaz. Sadece isteğe bağlı veri bağışına açıkça onay vermeniz - durumunda, Uygulama kullanımınıza ilişkin belirli veriler, RKI’ye aktarılacaktır (bkz. Madde 5 - h.). + veya bir hata raporu kaydetmeniz ve bunu RKI’ye iletmeniz durumunda, Uygulama kullanımınıza + ilişkin belirli veriler, RKI’ye aktarılacaktır (bkz. Madde 5 i ve Madde 5 k.). </p> <p> Uygulama tarafından işlenen veriler aşağıdaki kategorilerde sınıflandırılabilir: </p> <h3> - a. Erişim verileri + a. Erişim verileri </h3> <p> @@ -136,7 +136,7 @@ sunucuya iletir, bu sayede IP adresi sunucu sisteminde işlenmez. </p> <h3> - b. Maruz kalma verileri + b. Maruz kalma verileri </h3> <p> @@ -292,7 +292,10 @@ üzerinden olası bir enfeksiyon konusunda uyarırsanız </li> <li> - Olası Korona semptomların başlangıcına ilişkin beyanda bulunursanız + Olası Korona semptomlarının başlangıcına ilişkin beyanda bulunursanız veya + </li> + <li> + Uygulamaya dijital aşı sertifikaları eklediğinizde. </li> </ul> <p> @@ -323,9 +326,35 @@ </p> <h3> - h. Kullanım verileri (veri bağışı) + h. Korona aşılarınıza ilişkin veriler +</h3> +<p> + Aşı olduğunuzda size sağlanan aşı sertifikalarınızı Uygulamaya ekleyebilirsiniz. Dijital aşı + sertifikasını talep etmeniz isteğe bağlıdır. Bu olanaktan yararlanmak isterseniz, aşı olduktan + sonra size QR kodlu bir çıktı verilir. Bu kod, Korona aşılamanızla ilgili şu verileri içerir: +</p> +<ul> + <li> + Kişisel veriler (adı, soyadı, doğum tarihi) + </li> + <li> + Aşıya ilişkin bilgiler (hastalık, aşı maddesi, ürün, üretici firma) + </li> + <li> + Aşılamaya ilişkin bilgiler (doz numarası, toplam doz sayısı, aşılama tarihi, ülke, + düzenleyen kurum) + </li> + <li> + Aşı sertifikasının benzersiz kimlik kodu. + </li> +</ul> +<p> + Aşı olduğunuzda toplanan bu veriler, dijital aşı sertifikası için QR kodu taradığınız anda + Uygulamaya kaydedilir. +</p> +<h3> + i. Kullanım verileri (veri bağışı) </h3> - <p> Veri bağışını etkinleştirdiğinizde Uygulama, Uygulama kullanımınıza ilişkin belirli verileri günde bir kez RKI’ye aktarır (bundan böyle: Kullanım verileri). Bu kullanım verileri, Uygulama @@ -382,10 +411,10 @@ <p> Veri bağışına katılım, gönüllü olarak gerçekleşmektedir. Veri bağışının etkinleştirilmesi, Uygulamanızın orijinalliğinin doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için - bkz. Madde 5 j. ve 11.). + bkz. Madde 5 l. ve 11.). </p> <h3> - i. Ankete katılım + j. Ankete katılım </h3> <p> @@ -403,7 +432,63 @@ doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için bkz. Madde 5 j. ve 11.). </p> <h3> - j. Uygulamanızın orijinalliğinin doğrulanması + k. Hata raporlarının içerikleri +</h3> +<p> + Hata analizi ile ilgili olarak Uygulama teknik desteğine yardımcı olmak için Uygulamanızda hata + raporu kaydedebilirsiniz. Hata raporunu kaydetmeye başladığınızda, +</p> +<ul> + <li> + Uygulamadaki kullanım adımlarınız, + </li> + <li> + teknik adımlar ve süreçler ile durum raporları + <ul> + <li> + risk değerlendirmesi (örneğin, maruz kalma verilerinin nasıl işlendiği, enfeksiyon + riskinin hesaplanması, pozitif listelerin güncellenmesi, hesaplanan risk durumunun + görüntülenmesi), + </li> + <li> + test sonuçlarını çağrılması ve görüntülenmesi ve + </li> + <li> + başkalarını uyarmak için olası prosedürler (örneğin akıllı telefonunuz tarafından + taşıma riski değerlerinin hesaplanması ve rastgele kimlik numaralarınızın tekniksel + açıdan sağlanması) + </li> + </ul> + </li> +</ul> +<p> + akıllı telefonunuzda kapsamlı bir şekilde kaydedilir ve saklanır. Bir hata raporu sağlık + verileri de içerebilir, çünkü bir riskli karşılaşmanın saptanmasına yönelik teknik adımlar ve + süreçler de kaydedilmektedir. +</p> +<p> + Ancak hata raporu, test kaydı QR kodları ile Uygulamanızda depolanan belirteç, hızlı test + sonuçları, aşı sertifikaları ve temas günlüğünüzdeki veri girişlerine ilişkin herhangi bir bilgi + içermez. Hata raporu, adınızı ve RKI tarafından kimliğinizin tanımlanmasını sağlayacak diğer + verileri içermez. +</p> +<p> + İstediğiniz zaman hata raporunu kaydını durdurabilir ve hata raporunu silebilirsiniz. Hata + raporunu RKI ile paylaşmaya karar verdiğinizde, size Uygulama üzerinden hata raporu bir kimlik + kodu (hata raporu kimlik numarası) gönderilir. Hata raporu kimlik numarası üzerinden RKI, hata + raporunuzu, teknik desteğe örneğin hatanın bir açıklamasını e-posta ile ilettiğinizde ayrı + olarak sağladığınız diğer bilgilere atayabilir. Hata raporu kimlik numaranızı teknik desteğe + aktardığınızda, onların diğer bazı veriler aracılığıyla sizin kimliğinize bağlantı kurması + mümkün olabilir. +</p> +<p> + Bir hata raporunun oluşturulması ve RKI’ye gönderimi isteğe bağlı gerçekleşir. Bir hata raporu + kaydetmek ve bunu Uygulama teknik desteğe göndermek isteyip istemediğinize siz kendiniz karar + verirsiniz. Veri bağışının gönderiminin etkinleştirilmesi, Uygulamanızın orijinalliğinin + doğrulanmasını gerektirir (bu konuyla ilgili daha fazla bilgi için bkz. Madde 5 l ve Madde 11). +</p> +<h3> + l. Uygulamanızın orijinalliğinin doğrulanması </h3> <p> @@ -423,7 +508,7 @@ etmezseniz, Uygulamanın başka bazı işlevleri sizin için sunulmayabilir. </p> <h2> - 6. Verileriniz niçin işleniyor? + 6. Verileriniz niçin işleniyor? </h2> <h3> a. Risk değerlendirmesi @@ -526,7 +611,7 @@ </p> <p> - <u>Test sonucunun çağrılması </u> + <u>Test sonucunun çağrılması </u> </p> <p> @@ -667,7 +752,7 @@ olabilir. </p> <h3> - f. Uygulamanın bilgilenme amaçlı kullanımı + f. Uygulamanın bilgilenme amaçlı kullanımı </h3> <p> @@ -678,7 +763,7 @@ erişilen web sitesinin ilgili sağlayıcısı tarafından belirlenmektedir. </p> <h3> - g. Temas güncesi + g. Temas güncesi </h3> <p> @@ -695,7 +780,39 @@ enfeksiyonların önüne geçebilir. </p> <h3> - h. Veri bağışı + h. Dijital aşı sertifikası +</h3> +<p> + Uygulama, aşı sertifikalarınızı kaydetmenizi ve dijital olarak yanınızda bulundurmanızı mümkün + kılar. Gerekli olduğunda, yasal açıdan zorunlu durumlarda, Koronavirüse karşı aşılamanızı + eksiksiz olarak tamamladığınızı kanıtlamak için Uygulamayı kullanabilirsiniz. +</p> +<p> + Uygulamaya bir aşı sertifikası eklemek için, aşı ile birlikte size sağlanan QR kodu tarayın. Bu + sayede Uygulama, aşılamanıza ilişkin verileri QR kod üzerinden okur ve bunları akıllı + telefonunuzun güvenli bir alanına saklar. +</p> +<p> + Gerekli son aşılamanızdan 14 gün sonra Uygulama, ana ekranda aşı korumanızın eksiksiz olarak + tamamlandığını gösterir. Uygulamada gösterilen dijital aşı sertifikasının QR kodu gerektiğinde + kanıt olarak gösterebilirsiniz. Bu QR kod, resmi kontrol uygulamasıyla taranabilir ve Korona + aşılamanıza ilişkin veriler buradan okunabilir. Bunun ardından kontrol uygulamasında aşı + korumanızın tamamlanıp tamamlanmadığı gösterilir. Ayrıca adınız ve doğum tarihiniz de + görüntülenir, bu sayede kontrol eden kişi bu bilgileri resmi kimlik belgenizdeki bilgiler ile + karşılaştırabilir. +</p> +<p> + Uygulamadaki aşı sertifikalarınızı kaydetme işlevini kullanmanın isteğe bağlı olduğunu göz + önünde bulundurun. Aşı koruması yaptırdığınızı, yasal açıdan zorunlu durumlarda diğer + yöntemlerle de kanıtlayabilirsiniz. +</p> +<p> + Dijital aşı sertifikanızdaki QR kodun Korona aşılarınıza ilişkin veriler içerdiğini lütfen + unutmayın. Yalnızca aşı durumunuzu kanıtlamanız gerektiğinde bunu gösterin. Söz konusu verilerin + okunmasını istemiyorsanız, aşı sertifikasını ve QR kodu hiç kimseye göstermeyin. +</p> +<h3> + i. Veri bağışı </h3> <p> @@ -737,7 +854,25 @@ öğrenmez. </p> <h3> - i. Anketler + j. Hata raporları +</h3> + +<p> + RKI, hatasız bir Uygulama sunmayı hedeflemektedir. Ancak, çok sayıda farklı sistem nedeniyle bu + hedefe her zaman ulaşılmayabilmektedir. Hata analizi ile ilgili olarak Uygulama teknik desteğine + yardımcı olmak için, Uygulamanızda hata raporu oluşturup RKI’ye aktarabilirsiniz. RKI, + Uygulamanızda ortaya çıkan hataların nedenlerini belirlemek ve bunları gidermek için hata + raporunu değerlendirmeye alacaktır. +</p> +<p> + Bu hata raporları, adınız ve kimliğiniz ile herhangi bir bağlam olmaksızın geçici olarak + saklanır ve hata analizi kapsamında değerlendirilir. RKI, kim olduğunuzu veya kiminle + karşılaştığınızı öğrenmez. Ancak hata raporunu teknik desteğe iletirken, hata raporu kimlik + numarasını ifşa ederseniz (örn. e-posta yoluyla), bu işlemin kimliğiniz hakkında ipuçları ortaya + çıkarabileceğini göz önünde bulundurun. +</p> +<h3> + k. Anketler </h3> <p> @@ -746,7 +881,7 @@ amaçları, anket web sitesinde anketteki bilgilerde yer almaktadır. </p> <h3> - j. Uygulamanızın orijinalliğinin doğrulanması + l. Uygulamanızın orijinalliğinin doğrulanması </h3> <p> @@ -826,7 +961,7 @@ adresinden erişebilirsiniz. </p> <h2> - 8. Uygulamanın hangi izinlere gerek duyar? + 8. Uygulamanın hangi izinlere gerek duyar? </h2> <p> Uygulama, akıllı telefonunuzdaki çeşitli işlevlere ve arabirimlere erişim gerektirir. Bunun @@ -838,7 +973,7 @@ kullanılabileceğini lütfen unutmayın. </p> <h3> - a. Teknik gereksinimler (tüm akıllı telefonlar) + a. Teknik gereksinimler (tüm akıllı telefonlar) </h3> <ul> @@ -914,7 +1049,7 @@ </li> </ul> <h2> - 9. Verileriniz ne zaman silinir? + 9. Verileriniz ne zaman silinir? </h2> <p> Saklama süresi, verilerinizin kaydedildiği amaçlara veya Uygulama işlevlerine göre @@ -925,7 +1060,7 @@ belirtilmedikçe, aşağıdaki süreler geçerlidir: </p> <h3> - a. Akıllı telefonunuzdaki veriler + a. Akıllı telefonunuzdaki veriler </h3> <p> @@ -939,7 +1074,8 @@ silinir. Ancak bu verileri istediğiniz zaman, daha erken de silebilirsiniz. Bir olaya veya bir konuma giriş denetimi yaptırdığınızda, ilgili giriş denetimi kaydı silindikten sonra bile temas günlüğündeki verilerin hâlâ orada saklı kaldıklarını lütfen unutmayın. Bir kez hızlı test - profili oluşturduysanız bu, siz tekrar silene kadar uygulamada kalır. + profili oluşturduysanız bu, siz tekrar silene kadar uygulamada kalır. Aşı sertifikalarını + taradıysanız, bu veriler siz onları silene kadar Uygulamada kayıtlı kalacaktır. </p> <h3> b. Sunucu sistemlerindeki veriler @@ -957,7 +1093,14 @@ Veri bağışı kapsamında RKI’ye aktarılan kullanım verileri ve diğer isteğe bağlı veriler 180 gün sonra silinir.</p> <h3> - d. Uygulamanızın orijinalliğinin doğrulanması + d. Hata raporları +</h3> +<p> + Akıllı telefonunuzda kaydedilmiş bir hata raporunu istediğiniz zaman silebilirsiniz. Teknik + desteğe göndermiş olduğunuz hata raporları ise en geç 14 gün sonra silinecektir. +</p> +<h3> + e. Uygulamanızın orijinalliğinin doğrulanması </h3> <p> @@ -1029,7 +1172,7 @@ kalır. </p> <h2> - 12. Verdiğiniz rıza beyanını nasıl geri alabilirsiniz? + 12. Verdiğiniz rıza beyanını nasıl geri alabilirsiniz? </h2> <p> Geleceğe dönük geçerli olmak üzere, Uygulamada RKI’ye verdiğiniz bir onayı istediğiniz zaman @@ -1104,7 +1247,18 @@ Diğer insanları uyarmak için test sonucunuzun ( (daha doğrusu, son 14 güne yeniden izin vermek isterseniz, ilgili işlevi ayarlardan yeniden etkinleştirebilirsiniz. </p> <h3> - f. “Anket†rıza beyanı + f. “Hata raporları†rıza beyanı +</h3> +<p> + Daha önceden RKI’ye gönderdiğiniz hata raporlarının analizi için olan rıza beyanınızı geri + çekebilirsiniz, bunun için teknik desteğe hata raporu kimlik numaranızı belirterek, hata + raporunun artık analiz edilmesini istemediğinizi bildirmeniz yeterlidir. Bunun üzerine hata + raporunuz silinir. RKI’nin bu prosedürde kimliğinizi öğrenebileceğini göz önünde bulundurun. + Hata raporu kimlik numaranızı teknik destek aktarmazsanız, gönderilen hata raporu 14 gün sonra + otomatik olarak silinecektir. +</p> +<h3> + g. “Anket†rıza beyanı </h3> <p> @@ -1113,7 +1267,7 @@ Diğer insanları uyarmak için test sonucunuzun ( (daha doğrusu, son 14 güne açıklama da bulunmaktadır. </p> <h3> - g. “Uygulamanızın orijinalliğinin doğrulanması†rıza beyanı + h. “Uygulamanızın orijinalliğinin doğrulanması†rıza beyanı </h3> <p> @@ -1166,7 +1320,7 @@ Diğer insanları uyarmak için test sonucunuzun ( (daha doğrusu, son 14 güne genellikle yerine getirilememektedir. </p> <h2> - 14. Veri koruma görevlisi ve iletişim + 14. Veri koruma görevlisi ve iletişim </h2> <p> Veri gizliliğine ilişkin sorularınızı ve endişelerinizi RKI’nin resmi veri koruma görevlisine @@ -1174,5 +1328,5 @@ Diğer insanları uyarmak için test sonucunuzun ( (daha doğrusu, son 14 güne görevlisi), Nordufer 20,13353 Berlin veya e-posta yoluyla: <a href="mailto:datenschutz@rki.de">datenschutz@rki.de</a>. </p> <p> - Baskı 12.05.2021 -</p> + Baskı 28.05.2021 +</p> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt index 638bc4082866a671d4fa8b1222f3da2111faf573..b753f30df1c058f28895e797933d93c78edd28f0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/BugReportingSharedModule.kt @@ -16,6 +16,7 @@ import de.rki.coronawarnapp.bugreporting.censors.submission.PcrQrCodeCensor import de.rki.coronawarnapp.bugreporting.censors.submission.RACoronaTestCensor import de.rki.coronawarnapp.bugreporting.censors.submission.RatProfileCensor import de.rki.coronawarnapp.bugreporting.censors.submission.RatQrCodeCensor +import de.rki.coronawarnapp.bugreporting.censors.vaccination.CertificateQrCodeCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.bugreporting.debuglog.upload.server.LogUploadApiV1 @@ -117,4 +118,8 @@ class BugReportingSharedModule { @Provides @IntoSet fun ratProfileCensor(censor: RatProfileCensor): BugCensor = censor + + @Provides + @IntoSet + fun certificateQrCodeCensor(censor: CertificateQrCodeCensor): BugCensor = censor } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt new file mode 100644 index 0000000000000000000000000000000000000000..b3de1ea4f938ebcb8e7b4f2287702d5a50a4072c --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt @@ -0,0 +1,162 @@ +package de.rki.coronawarnapp.bugreporting.censors.vaccination + +import dagger.Reusable +import de.rki.coronawarnapp.bugreporting.censors.BugCensor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 +import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData +import java.util.LinkedList +import javax.inject.Inject + +@Reusable +class CertificateQrCodeCensor @Inject constructor() : BugCensor { + + override suspend fun checkLog(entry: LogLine): LogLine? { + var newMessage = entry.message + + synchronized(qrCodeStringsToCensor) { qrCodeStringsToCensor.toList() }.forEach { + newMessage = newMessage.replace( + it, + PLACEHOLDER + it.takeLast(4) + ) + } + + synchronized(certsToCensor) { certsToCensor.toList() }.forEach { + it.certificate.apply { + newMessage = newMessage.replace( + dob, + "vaccinationCertificate/dob" + ) + + newMessage = newMessage.replace( + dateOfBirth.toString(), + "vaccinationCertificate/dateOfBirth" + ) + + newMessage = censorNameData(nameData, newMessage) + + vaccinationDatas.forEach { data -> + newMessage = censorVaccinationData(data, newMessage) + } + } + } + + return entry.toNewLogLineIfDifferent(newMessage) + } + + private fun censorVaccinationData( + vaccinationData: VaccinationDGCV1.VaccinationData, + message: String + ): String { + var newMessage = message + + newMessage = newMessage.replace( + vaccinationData.dt, + "vaccinationData/dt" + ) + + newMessage = newMessage.replace( + vaccinationData.marketAuthorizationHolderId, + "vaccinationData/marketAuthorizationHolderId" + ) + + newMessage = newMessage.replace( + vaccinationData.medicalProductId, + "vaccinationData/medicalProductId" + ) + + newMessage = newMessage.replace( + vaccinationData.targetId, + "vaccinationData/targetId" + ) + + newMessage = newMessage.replace( + vaccinationData.certificateIssuer, + "vaccinationData/certificateIssuer" + ) + + newMessage = newMessage.replace( + vaccinationData.uniqueCertificateIdentifier, + "vaccinationData/uniqueCertificateIdentifier" + ) + + newMessage = newMessage.replace( + vaccinationData.countryOfVaccination, + "vaccinationData/countryOfVaccination" + ) + + newMessage = newMessage.replace( + vaccinationData.vaccineId, + "vaccinationData/vaccineId" + ) + + newMessage = newMessage.replace( + vaccinationData.vaccinatedAt.toString(), + "vaccinationData/vaccinatedAt" + ) + + return newMessage + } + + private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: String): String { + var newMessage = message + + nameData.familyName?.let { fName -> + newMessage = newMessage.replace( + fName, + "nameData/familyName" + ) + } + + newMessage = newMessage.replace( + nameData.familyNameStandardized, + "nameData/familyNameStandardized" + ) + + nameData.givenName?.let { gName -> + newMessage = newMessage.replace( + gName, + "nameData/givenName" + ) + } + + nameData.givenNameStandardized?.let { gName -> + newMessage = newMessage.replace( + gName, + "nameData/givenNameStandardized" + ) + } + + return newMessage + } + + companion object { + private val qrCodeStringsToCensor = LinkedList<String>() + + fun addQRCodeStringToCensor(rawString: String) = synchronized(qrCodeStringsToCensor) { + qrCodeStringsToCensor.apply { + if (contains(rawString)) return@apply + addFirst(rawString) + // Max certs is at 4, but we may scan invalid qr codes that are not added which will be shown in raw + if (size > 8) removeLast() + } + } + + fun clearQRCodeStringToCensor() = synchronized(qrCodeStringsToCensor) { qrCodeStringsToCensor.clear() } + + private val certsToCensor = LinkedList<VaccinationCertificateData>() + fun addCertificateToCensor(cert: VaccinationCertificateData) = synchronized(certsToCensor) { + certsToCensor.apply { + if (contains(cert)) return@apply + addFirst(cert) + // max certs we should have is 2, 50% leeway + if (size > 4) removeLast() + } + } + + fun clearCertificateToCensor() = synchronized(certsToCensor) { certsToCensor.clear() } + + private const val PLACEHOLDER = "########-####-####-####-########" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotter.kt index 8bf4d816bfdff47cc35fe8a7535243b206097d78..cbbd0e13e69cce358e844b948e19b2cbdef41aa1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotter.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.bugreporting.debuglog.internal import android.content.Context import dagger.Reusable import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone import de.rki.coronawarnapp.util.TimeStamper import de.rki.coronawarnapp.util.di.AppContext import de.rki.coronawarnapp.util.files.Zipper @@ -32,8 +33,9 @@ class LogSnapshotter @Inject constructor( if (it.delete()) Timber.tag(TAG).w("Deleted stale snapshot: %s", it) } - val now = timeStamper.nowUTC - val formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS") + val now = timeStamper.nowUTC.toUserTimeZone() + // Avoid ":" in filename since it is a reserved character in Microsoft Windows + val formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH_mm_ss.SSS") val formattedFileName = "CWA Log ${now.toString(formatter)}" if (!snapshotDir.exists() && snapshotDir.mkdirs()) { Timber.tag(TAG).v("Created %s", snapshotDir) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt index 7c2913791e8582c7ec1881d6e4f38f863f2c46e5..0f2eb837232fd0e51d7d5b8ad01db53fa06eed14 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/DebugLogFragment.kt @@ -21,7 +21,7 @@ import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack import de.rki.coronawarnapp.util.ui.setGone -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.joda.time.Duration @@ -34,7 +34,7 @@ class DebugLogFragment : Fragment(R.layout.bugreporting_debuglog_fragment), Auto @Inject lateinit var fileSharing: FileSharing private val vm: DebugLogViewModel by cwaViewModels { viewModelFactory } - private val binding: BugreportingDebuglogFragmentBinding by viewBindingLazy() + private val binding: BugreportingDebuglogFragmentBinding by viewBinding() @Suppress("ComplexMethod") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/legal/DebugLogLegalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/legal/DebugLogLegalFragment.kt index a56f0df1882c8fceef57fe95538714f45a7870ec..ecbc5f7b11cbba94c0618f5b146490cf86e25250 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/legal/DebugLogLegalFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/legal/DebugLogLegalFragment.kt @@ -8,7 +8,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.BugreportingLegalFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -18,7 +18,7 @@ class DebugLogLegalFragment : Fragment(R.layout.bugreporting_legal_fragment), Au @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: DebugLogLegalViewModel by cwaViewModels { viewModelFactory } - private val binding: BugreportingLegalFragmentBinding by viewBindingLazy() + private val binding: BugreportingLegalFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/DebugLogUploadFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/DebugLogUploadFragment.kt index 8f4c80f1a0fc9d2d63459fd5cc91c499ec5f8f3b..7a3543d9a73f3764473544dee436265e45df3ea7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/DebugLogUploadFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/DebugLogUploadFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.util.tryHumanReadableError import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -22,7 +22,7 @@ class DebugLogUploadFragment : Fragment(R.layout.bugreporting_debuglog_upload_fr @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: DebugLogUploadViewModel by cwaViewModels { viewModelFactory } - private val binding: BugreportingDebuglogUploadFragmentBinding by viewBindingLazy() + private val binding: BugreportingDebuglogUploadFragmentBinding by viewBinding() private lateinit var uploadDialog: LogUploadBlockingDialog override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/history/LogUploadHistoryFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/history/LogUploadHistoryFragment.kt index a608c49a4547607b6d9e6b43249bcaf42429444e..487d25dd3bc08fb9e6a1c0b91e09371d3fcaac19 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/history/LogUploadHistoryFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/ui/upload/history/LogUploadHistoryFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.databinding.BugreportingUploadHistoryFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -19,7 +19,7 @@ class LogUploadHistoryFragment : Fragment(R.layout.bugreporting_upload_history_f @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: LogUploadHistoryViewModel by cwaViewModels { viewModelFactory } - private val binding: BugreportingUploadHistoryFragmentBinding by viewBindingLazy() + private val binding: BugreportingUploadHistoryFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt index 91f74937cdb7256d787219c6432bd25b1b578958..eff34b12094fca97c5c4eb4c32aaf7f8a53d658a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/ContactDiaryDayFragment.kt @@ -20,13 +20,13 @@ import de.rki.coronawarnapp.databinding.ContactDiaryDayFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject class ContactDiaryDayFragment : Fragment(R.layout.contact_diary_day_fragment), AutoInject { - private val binding: ContactDiaryDayFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryDayFragmentBinding by viewBinding() private val navArgs by navArgs<ContactDiaryDayFragmentArgs>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryCommentInfoFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryCommentInfoFragment.kt index 06b77c17c8ed3726de6e0b502949e004679e0d3f..3297d95b038857f64c57b53cc0a5b6eee2d7a732 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryCommentInfoFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/ContactDiaryCommentInfoFragment.kt @@ -6,11 +6,11 @@ import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.ContactDiaryCommentInfoFragmentBinding import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding class ContactDiaryCommentInfoFragment : Fragment(R.layout.contact_diary_comment_info_fragment) { - private val binding: ContactDiaryCommentInfoFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryCommentInfoFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt index aaac0159e2b20f7ab1bdef5bf42c2c4a02cd9a06..7ebedf30e7f8aef1de91a31940255602b7c7358b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/ContactDiaryLocationListFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.onScroll import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -25,7 +25,7 @@ class ContactDiaryLocationListFragment : Fragment(R.layout.contact_diary_location_list_fragment), AutoInject { - private val binding: ContactDiaryLocationListFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryLocationListFragmentBinding by viewBinding() private val navArgs by navArgs<ContactDiaryLocationListFragmentArgs>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt index a824b4934c1f175cb627d2b1079855ac1229bd1e..173f72708ae027691e29d7d05e959a1efbecf6a8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/person/ContactDiaryPersonListFragment.kt @@ -15,13 +15,13 @@ import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.onScroll import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject class ContactDiaryPersonListFragment : Fragment(R.layout.contact_diary_person_list_fragment), AutoInject { - private val binding: ContactDiaryPersonListFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryPersonListFragmentBinding by viewBinding() private val navArgs by navArgs<ContactDiaryPersonListFragmentArgs>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditLocationsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditLocationsFragment.kt index d5a83e00c287beb09f8e0bda7f47b37c309854af..8e198500f1dffebdf0f4d512b66318c5f9975a8e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditLocationsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditLocationsFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -25,7 +25,7 @@ class ContactDiaryEditLocationsFragment : Fragment(R.layout.contact_diary_edit_l @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: ContactDiaryEditLocationsViewModel by cwaViewModels { viewModelFactory } - private val binding: ContactDiaryEditLocationsFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryEditLocationsFragmentBinding by viewBinding() private lateinit var listAdapter: LocationEditAdapter diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditPersonsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditPersonsFragment.kt index e3faf79896f6f42e45047f9f38647d2f00aaaab2..232efce0a890ebb0a0f9003a5953cfa4b11b2690 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditPersonsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/edit/ContactDiaryEditPersonsFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -25,7 +25,7 @@ class ContactDiaryEditPersonsFragment : Fragment(R.layout.contact_diary_edit_per @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: ContactDiaryEditPersonsViewModel by cwaViewModels { viewModelFactory } - private val binding: ContactDiaryEditPersonsFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryEditPersonsFragmentBinding by viewBinding() private lateinit var listAdapter: PersonEditAdapter diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt index bc0aa5196e4d3bf50bdea60654275aa4ad8913a1..8dac8125c5c291909d337f1463be599a76f10c78 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/location/ContactDiaryAddLocationFragment.kt @@ -16,14 +16,14 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.setTextOnTextInput import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject class ContactDiaryAddLocationFragment : Fragment(R.layout.contact_diary_add_location_fragment), AutoInject { - private val binding: ContactDiaryAddLocationFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryAddLocationFragmentBinding by viewBinding() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: ContactDiaryAddLocationViewModel by cwaViewModelsAssisted( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt index eabc87c544c1e73ae5587ecda4f0ea81f134a465..306abb31623ed021a13a874456c0ee2f5fd5db3c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/onboarding/ContactDiaryOnboardingFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.joda.time.LocalDate @@ -28,7 +28,7 @@ class ContactDiaryOnboardingFragment : Fragment(R.layout.contact_diary_onboardin @Inject lateinit var settings: ContactDiarySettings private val vm: ContactDiaryOnboardingFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: ContactDiaryOnboardingFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryOnboardingFragmentBinding by viewBinding() private val args by navArgs<ContactDiaryOnboardingFragmentArgs>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt index d08d046dac2fc4fc162f94e3bf7e2bad324a3da4..5b26115e8a4b978b0fb649ad0f686f4e3df9fb6a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import timber.log.Timber @@ -25,7 +25,7 @@ class ContactDiaryOverviewFragment : Fragment(R.layout.contact_diary_overview_fr @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: ContactDiaryOverviewViewModel by cwaViewModels { viewModelFactory } - private val binding: ContactDiaryOverviewFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryOverviewFragmentBinding by viewBinding() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt index 6379a87784dbd0f727ee8246d3de1233cf4904c7..f758771f61733a5b7a8dd936296456a97933dbdd 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/person/ContactDiaryAddPersonFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.setTextOnTextInput import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -25,7 +25,7 @@ class ContactDiaryAddPersonFragment : Fragment(R.layout.contact_diary_add_person_fragment), AutoInject { - private val binding: ContactDiaryAddPersonFragmentBinding by viewBindingLazy() + private val binding: ContactDiaryAddPersonFragmentBinding by viewBinding() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: ContactDiaryAddPersonViewModel by cwaViewModelsAssisted( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt index 55ddd315ae27b7b1fac8c1e446b9b09f58980d7c..7b31a977326e8cf8f72a7b76938766d79e1c1d3f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt @@ -14,7 +14,7 @@ class CoronaTestQrCodeValidator @Inject constructor( fun validate(rawString: String): CoronaTestQRCode { return findExtractor(rawString) ?.extract(rawString) - ?.also { Timber.i("Extracted data from QR code is $it") } + ?.also { Timber.i("Extracted data from QR code is %s", it) } ?: throw InvalidQRCodeException() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt index faedc26b6b290c1dd7a44881d9cbcee28366317a..2b25be3b5417dd86fbc81fd315aa7325ea7af0ce 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RapidAntigenCoronaTestExtensions.kt @@ -28,10 +28,10 @@ fun RACoronaTest?.toSubmissionState(nowUTC: Instant = Instant.now(), coronaTestC else -> when (getState(nowUTC, coronaTestConfig)) { INVALID -> TestError POSITIVE -> { - if (isViewed) TestPositive(testRegisteredAt = registeredAt) + if (isViewed) TestPositive(testRegisteredAt = testedAt) else TestResultReady } - NEGATIVE -> TestNegative(testRegisteredAt = registeredAt) + NEGATIVE -> TestNegative(testRegisteredAt = testedAt) REDEEMED -> TestInvalid PENDING -> TestPending OUTDATED -> TestOutdated diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/PpaMoreInfoFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/PpaMoreInfoFragment.kt index 3f921b2f18240db59e46749181990681b13ce117..91a5558e262e547c753fcd7322f290647df497f2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/PpaMoreInfoFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/PpaMoreInfoFragment.kt @@ -6,7 +6,7 @@ import android.view.accessibility.AccessibilityEvent import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentPpaMoreInfoBinding -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * The fragment displays static informative content to the user @@ -17,7 +17,7 @@ import de.rki.coronawarnapp.util.ui.viewBindingLazy class PpaMoreInfoFragment : Fragment(R.layout.fragment_ppa_more_info) { - private val binding: FragmentPpaMoreInfoBinding by viewBindingLazy() + private val binding: FragmentPpaMoreInfoBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/input/AnalyticsUserInputFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/input/AnalyticsUserInputFragment.kt index b23dee43a827a2b2099ee7df154f803df6fa4e87..12addb49037a1834b6f27b28ef30cc28d88d0711 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/input/AnalyticsUserInputFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/ui/input/AnalyticsUserInputFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.databinding.AnalyticsPpaUserinfoInputFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -28,7 +28,7 @@ class AnalyticsUserInputFragment : Fragment(R.layout.analytics_ppa_userinfo_inpu } ) - private val binding: AnalyticsPpaUserinfoInputFragmentBinding by viewBindingLazy() + private val binding: AnalyticsPpaUserinfoInputFragmentBinding by viewBinding() @Inject lateinit var itemAdapter: UserInfoItemAdapter diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentDetailFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentDetailFragment.kt index 54444e600f94654ce5f4b237d7b65eeed256c996..8f0a318a08067cb4137279e52c8446b5e3d9af7a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentDetailFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentDetailFragment.kt @@ -5,11 +5,11 @@ import android.view.View import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.SurveyConsentDetailFragmentBinding -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding class SurveyConsentDetailFragment : Fragment(R.layout.survey_consent_detail_fragment) { - private val binding: SurveyConsentDetailFragmentBinding by viewBindingLazy() + private val binding: SurveyConsentDetailFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt index 9935ba7d6b212466f85504dfe7389aa59618267a..fb9efabe0b822908b52a363637b5ff9dbfe90ad3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/survey/consent/SurveyConsentFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -31,7 +31,7 @@ class SurveyConsentFragment : Fragment(R.layout.survey_consent_fragment), AutoIn } ) - private val binding: SurveyConsentFragmentBinding by viewBindingLazy() + private val binding: SurveyConsentFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt index 3a81cb926a78ecec4b9f6e8333b31fb15e075770..b99710e6d4a6bd5a07a5bb7d08931aecf4594746 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentModule.kt @@ -5,7 +5,6 @@ import de.rki.coronawarnapp.environment.bugreporting.BugReportingServerModule import de.rki.coronawarnapp.environment.datadonation.DataDonationCDNModule import de.rki.coronawarnapp.environment.download.DownloadCDNModule import de.rki.coronawarnapp.environment.submission.SubmissionCDNModule -import de.rki.coronawarnapp.environment.vaccination.VaccinationCertificateUrlModule import de.rki.coronawarnapp.environment.verification.VerificationCDNModule @Module( @@ -14,8 +13,7 @@ import de.rki.coronawarnapp.environment.verification.VerificationCDNModule SubmissionCDNModule::class, VerificationCDNModule::class, DataDonationCDNModule::class, - BugReportingServerModule::class, - VaccinationCertificateUrlModule::class + BugReportingServerModule::class ] ) class EnvironmentModule diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt index f7d1a754da9017d98a45bc58ac599d469a978082..d44e8e88ef378eaae6e78f7c4e73591be7c08e93 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/EnvironmentSetup.kt @@ -12,7 +12,6 @@ import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.LOG_UPLOAD import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.SAFETYNET_API_KEY import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.SUBMISSION import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.USE_EUR_KEY_PKGS -import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.VACCINATION_VALUE import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.VERIFICATION import de.rki.coronawarnapp.environment.EnvironmentSetup.EnvKey.VERIFICATION_KEYS import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnvironmentType @@ -37,7 +36,6 @@ class EnvironmentSetup @Inject constructor( VERIFICATION_KEYS("PUB_KEYS_SIGNATURE_VERIFICATION"), DATA_DONATION("DATA_DONATION_CDN_URL"), LOG_UPLOAD("LOG_UPLOAD_SERVER_URL"), - VACCINATION_VALUE("VACCINATION_CDN_URL"), SAFETYNET_API_KEY("SAFETYNET_API_KEY"), CROWD_NOTIFIER_PUBLIC_KEY("CROWD_NOTIFIER_PUBLIC_KEY") } @@ -137,9 +135,6 @@ class EnvironmentSetup @Inject constructor( val logUploadServerUrl: String get() = getEnvironmentValue(LOG_UPLOAD).asString - val vaccinationCdnUrl: String - get() = getEnvironmentValue(VACCINATION_VALUE).asString - companion object { private const val PKEY_CURRENT_ENVINROMENT = "environment.current" } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/vaccination/VaccinationCertificateCDNUrl.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/vaccination/VaccinationCertificateCDNUrl.kt deleted file mode 100644 index 5740f4bf0ca8e587642020e693a8754b43e91b09..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/vaccination/VaccinationCertificateCDNUrl.kt +++ /dev/null @@ -1,8 +0,0 @@ -package de.rki.coronawarnapp.environment.vaccination - -import javax.inject.Qualifier - -@Qualifier -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -annotation class VaccinationCertificateCDNUrl diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/vaccination/VaccinationCertificateUrlModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/vaccination/VaccinationCertificateUrlModule.kt deleted file mode 100644 index 5660c7604074271c317ccd556e911bf78de18bb6..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/environment/vaccination/VaccinationCertificateUrlModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package de.rki.coronawarnapp.environment.vaccination - -import dagger.Module -import dagger.Provides -import dagger.Reusable -import de.rki.coronawarnapp.environment.BaseEnvironmentModule -import de.rki.coronawarnapp.environment.EnvironmentSetup - -@Module -class VaccinationCertificateUrlModule : BaseEnvironmentModule() { - - @Reusable - @VaccinationCertificateCDNUrl - @Provides - fun provideVaccinationValueSetUrl(environmentSetup: EnvironmentSetup): String = - requireValidUrl(environmentSetup.vaccinationCdnUrl) -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/release/NewReleaseInfoFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/release/NewReleaseInfoFragment.kt index 5e090ad1587a0af310a71330d55f70c8cdc643d9..1faefc7e3db5b8a2aa467b3c89c91200470d4665 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/release/NewReleaseInfoFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/release/NewReleaseInfoFragment.kt @@ -18,7 +18,7 @@ import de.rki.coronawarnapp.util.setUrl import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -28,7 +28,7 @@ class NewReleaseInfoFragment : Fragment(R.layout.new_release_info_screen_fragmen @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: NewReleaseInfoViewModel by cwaViewModels { viewModelFactory } - private val binding: NewReleaseInfoScreenFragmentBinding by viewBindingLazy() + private val binding: NewReleaseInfoScreenFragmentBinding by viewBinding() private val args: NewReleaseInfoFragmentArgs by navArgs() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/statistics/ui/StatisticsExplanationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/statistics/ui/StatisticsExplanationFragment.kt index f796aac3fcbc4842c540078da93e541604b98bee..9c446a568c29e94f7abd31b6778655ce94417451 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/statistics/ui/StatisticsExplanationFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/statistics/ui/StatisticsExplanationFragment.kt @@ -8,7 +8,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentStatisticsExplanationBinding import de.rki.coronawarnapp.util.setUrl import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * The fragment displays static informative content to the user @@ -19,7 +19,7 @@ import de.rki.coronawarnapp.util.ui.viewBindingLazy class StatisticsExplanationFragment : Fragment(R.layout.fragment_statistics_explanation) { - private val binding: FragmentStatisticsExplanationBinding by viewBindingLazy() + private val binding: FragmentStatisticsExplanationBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt index 9ff20b1186417ec740ca4a20b18df2d09f6ab54a..b04ebebf802dc9bb0c0522f3e1a84b44f3a5e1d5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.databinding.FragmentSubmissionAntigenTestResultNegat import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.joda.time.format.DateTimeFormat @@ -20,7 +20,7 @@ class RATResultNegativeFragment : Fragment(R.layout.fragment_submission_antigen_ @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: RATResultNegativeViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionAntigenTestResultNegativeBinding by viewBindingLazy() + private val binding: FragmentSubmissionAntigenTestResultNegativeBinding by viewBinding() private val shortTime = DateTimeFormat.shortTime() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt index 94891a7dd1ab9f2bbb43d908feab2e1053fee2ba..687c4a25e6de08edaeca5d014ed6926f8c726fb4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -31,7 +31,7 @@ class TracingDetailsFragment : Fragment(R.layout.tracing_details_fragment_layout ownerProducer = { requireActivity().viewModelStore }, factoryProducer = { viewModelFactory } ) - private val binding: TracingDetailsFragmentLayoutBinding by viewBindingLazy() + private val binding: TracingDetailsFragmentLayoutBinding by viewBinding() private val detailsAdapter = TracingDetailsAdapter { vm.onItemClicked(it) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragment.kt index d4fabbb857abca5d5c780a85bc4228a8c9115449..f6834b448b83d97ace34eeb1979895af1027aeae 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/settings/SettingsTracingFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -32,7 +32,7 @@ class SettingsTracingFragment : Fragment(R.layout.fragment_settings_tracing), Au factoryProducer = { viewModelFactory } ) - private val binding: FragmentSettingsTracingBinding by viewBindingLazy() + private val binding: FragmentSettingsTracingBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/create/RATProfileCreateFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/create/RATProfileCreateFragment.kt index 2ef3dcaca4e697d9a5cdcfa6f27bbc309cea85eb..c6f7dfe76f28f3e15fc9cf63cd959afc80d37491 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/create/RATProfileCreateFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/create/RATProfileCreateFragment.kt @@ -11,7 +11,7 @@ import de.rki.coronawarnapp.databinding.RatProfileCreateFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import org.joda.time.LocalDate @@ -20,7 +20,7 @@ import javax.inject.Inject class RATProfileCreateFragment : Fragment(R.layout.rat_profile_create_fragment), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val binding: RatProfileCreateFragmentBinding by viewBindingLazy() + private val binding: RatProfileCreateFragmentBinding by viewBinding() private val viewModel: RATProfileCreateFragmentViewModel by cwaViewModels { viewModelFactory } override fun onViewCreated(view: View, savedInstanceState: Bundle?) = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/onboarding/RATProfileOnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/onboarding/RATProfileOnboardingFragment.kt index bf3e0cb317ce6a714a2680a1b90f5282b3c18821..05943239f64d4b8c1491c7bfe70e24cb83459086 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/onboarding/RATProfileOnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/onboarding/RATProfileOnboardingFragment.kt @@ -8,14 +8,14 @@ import de.rki.coronawarnapp.databinding.RatProfileOnboardingFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject class RATProfileOnboardingFragment : Fragment(R.layout.rat_profile_onboarding_fragment), AutoInject { - private val binding: RatProfileOnboardingFragmentBinding by viewBindingLazy() + private val binding: RatProfileOnboardingFragmentBinding by viewBinding() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/qrcode/RATProfileQrCodeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/qrcode/RATProfileQrCodeFragment.kt index 447555b9e1ac22f94ae8a32cbb3808dbdc776496..1a12ab550b8aee519c6589ac15c5b95eba03fa7f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/qrcode/RATProfileQrCodeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/coronatest/rat/profile/qrcode/RATProfileQrCodeFragment.kt @@ -18,7 +18,7 @@ import de.rki.coronawarnapp.ui.qrcode.fullscreen.QrCodeFullScreenFragmentArgs import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.joinToSpannable import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -29,7 +29,7 @@ class RATProfileQrCodeFragment : Fragment(R.layout.rat_profile_qr_code_fragment) @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: RATProfileQrCodeFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: RatProfileQrCodeFragmentBinding by viewBindingLazy() + private val binding: RatProfileQrCodeFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setToolbarOverlay() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/durationpicker/DurationPicker.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/durationpicker/DurationPicker.kt index 09299192e0c77f584149029b4a4c54f6041403c4..a0aae6b2ba53c10eca47718f0deb2bc8752ec369 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/durationpicker/DurationPicker.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/durationpicker/DurationPicker.kt @@ -1,18 +1,18 @@ package de.rki.coronawarnapp.ui.durationpicker import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import androidx.annotation.IntRange import androidx.fragment.app.DialogFragment +import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.DurationPickerBinding +import de.rki.coronawarnapp.util.ui.viewBinding import org.joda.time.Duration import org.joda.time.format.PeriodFormatter import org.joda.time.format.PeriodFormatterBuilder import kotlin.math.max -class DurationPicker : DialogFragment() { +class DurationPicker : DialogFragment(R.layout.duration_picker) { fun interface OnChangeListener { fun onChange(duration: Duration) @@ -23,32 +23,28 @@ class DurationPicker : DialogFragment() { private val title by lazy { requireArguments().getString(TITLE_KEY).orEmpty() } private val minutesArray by lazy { requireArguments().getStringArray(MINUTES_KEY).orEmpty() } - private val binding: Lazy<DurationPickerBinding> = lazy { DurationPickerBinding.inflate(layoutInflater) } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - return binding.value.root - } + private val binding: DurationPickerBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - with(binding.value.hours) { + with(binding.hours) { minValue = 0 maxValue = hoursArray.size - 1 displayedValues = hoursArray } - with(binding.value.minutes) { + with(binding.minutes) { minValue = 0 maxValue = minutesArray.size - 1 displayedValues = minutesArray } - with(binding.value.title) { + with(binding.title) { text = title } - with(binding.value) { + with(binding) { var duration = requireArguments().getString(DURATION_KEY)!!.split(":").toTypedArray() if (duration.size < 2) duration = arrayOf("00", "00") @@ -68,7 +64,7 @@ class DurationPicker : DialogFragment() { } private fun getDuration(): Duration { - val durationString = hoursArray[binding.value.hours.value] + ":" + minutesArray[binding.value.minutes.value] + val durationString = hoursArray[binding.hours.value] + ":" + minutesArray[binding.minutes.value] val formatter: PeriodFormatter = PeriodFormatterBuilder() .appendHours() .appendLiteral(":") diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt index 60ef5d4f7799480fe64e79aa4ec4ab9511261f73..8a17d70a7e76972670f284ea6a47a5f581c210b5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationAboutFragment.kt @@ -9,14 +9,14 @@ import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationAboutBinding import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * Basic Fragment which only displays static content. */ class InformationAboutFragment : Fragment(R.layout.fragment_information_about) { - private val binding: FragmentInformationAboutBinding by viewBindingLazy() + private val binding: FragmentInformationAboutBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt index ad4112ba454d8b4f4c8bdcfc6badf2684ece83a2..2c06b5b9c4e9bd364a8288b00feb10793a33251e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationContactFragment.kt @@ -9,14 +9,14 @@ import de.rki.coronawarnapp.databinding.FragmentInformationContactBinding import de.rki.coronawarnapp.util.ExternalActionHelper.callPhone import de.rki.coronawarnapp.util.linkifyPhoneNumbers import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * Basic Fragment which only displays static content. */ class InformationContactFragment : Fragment(R.layout.fragment_information_contact) { - private val binding: FragmentInformationContactBinding by viewBindingLazy() + private val binding: FragmentInformationContactBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt index 303701ed54ef232c2d6596f7fa7df1f6efea48d1..7d41741cc41eae2d8143eb356ebf502f374f3e36 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack import de.rki.coronawarnapp.util.ui.setGone -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import timber.log.Timber @@ -29,7 +29,7 @@ class InformationFragment : Fragment(R.layout.fragment_information), AutoInject @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: InformationFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentInformationBinding by viewBindingLazy() + private val binding: FragmentInformationBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt index 2bf01043795a3445000392db1574221f2febc2be..4055ba4020995e2a57c6b8d6de9d20eb84c30e2e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationLegalFragment.kt @@ -9,14 +9,14 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationLegalBinding import de.rki.coronawarnapp.util.convertToHyperlink import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * Basic Fragment which only displays static content. */ class InformationLegalFragment : Fragment(R.layout.fragment_information_legal) { - private val binding: FragmentInformationLegalBinding by viewBindingLazy() + private val binding: FragmentInformationLegalBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt index 9bc1f33f8ba2e1677987b113ea2c1f1fc6804562..f3d89b4174d75c95d2e7bd50b8472b3eb5e40b4b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationPrivacyFragment.kt @@ -7,13 +7,13 @@ import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationPrivacyBinding -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * Basic Fragment which only displays static content. */ class InformationPrivacyFragment : Fragment(R.layout.fragment_information_privacy) { - private val binding: FragmentInformationPrivacyBinding by viewBindingLazy() + private val binding: FragmentInformationPrivacyBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt index fe10de37f7a1676275f86ef90b05e54e3dc4f0b6..4ebc24ff7c1bb3a66ae948a038cf96655c03bfcd 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTechnicalFragment.kt @@ -7,7 +7,7 @@ import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationTechnicalBinding import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * Basic Fragment which only displays static content. @@ -17,7 +17,7 @@ class InformationTechnicalFragment : Fragment(R.layout.fragment_information_tech private val TAG: String? = InformationTechnicalFragment::class.simpleName } - private val binding: FragmentInformationTechnicalBinding by viewBindingLazy() + private val binding: FragmentInformationTechnicalBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt index 63c99ca82f865f7f0e0484a0a522e1146e37dbba..4d076591834c4cfc01ef34c2c68c0f7da3410510 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/information/InformationTermsFragment.kt @@ -7,14 +7,14 @@ import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentInformationTermsBinding import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * Basic Fragment which only displays static content. */ class InformationTermsFragment : Fragment(R.layout.fragment_information_terms) { - private val binding: FragmentInformationTermsBinding by viewBindingLazy() + private val binding: FragmentInformationTermsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt index 347111db117b017e3d2b65ee08dfc9465ad3cd36..5e0d279f97f20b4c016af6911ec04535eed4c453 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragment.kt @@ -11,7 +11,7 @@ import de.rki.coronawarnapp.databinding.FragmentInteroperabilityConfigurationBin import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -22,7 +22,7 @@ class InteroperabilityConfigurationFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: InteroperabilityConfigurationFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentInteroperabilityConfigurationBinding by viewBindingLazy() + private val binding: FragmentInteroperabilityConfigurationBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt index abd463895d6662bb2066c423c8e3ecdf9350ac3c..1beff6b3260acfb661870f18445ae244123a546e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeAdapter.kt @@ -38,9 +38,9 @@ import de.rki.coronawarnapp.util.lists.modular.mods.DataBinderMod import de.rki.coronawarnapp.util.lists.modular.mods.SavedStateMod import de.rki.coronawarnapp.util.lists.modular.mods.StableIdMod import de.rki.coronawarnapp.util.lists.modular.mods.TypedVHCreatorMod -import de.rki.coronawarnapp.vaccination.ui.homecard.CompleteVaccinationHomeCard +import de.rki.coronawarnapp.vaccination.ui.homecard.ImmuneVaccinationHomeCard import de.rki.coronawarnapp.vaccination.ui.homecard.CreateVaccinationHomeCard -import de.rki.coronawarnapp.vaccination.ui.homecard.IncompleteVaccinationHomeCard +import de.rki.coronawarnapp.vaccination.ui.homecard.VaccinationHomeCard class HomeAdapter : ModularAdapter<HomeAdapter.HomeItemVH<HomeItem, ViewBinding>>(), @@ -80,11 +80,11 @@ class HomeAdapter : TypedVHCreatorMod({ data[it] is TestUnregisteredCard.Item }) { TestUnregisteredCard(it) }, TypedVHCreatorMod({ data[it] is StatisticsHomeCard.Item }) { StatisticsHomeCard(it) }, TypedVHCreatorMod({ data[it] is CreateVaccinationHomeCard.Item }) { CreateVaccinationHomeCard(it) }, - TypedVHCreatorMod({ data[it] is CompleteVaccinationHomeCard.Item }) { - CompleteVaccinationHomeCard(it) + TypedVHCreatorMod({ data[it] is ImmuneVaccinationHomeCard.Item }) { + ImmuneVaccinationHomeCard(it) }, - TypedVHCreatorMod({ data[it] is IncompleteVaccinationHomeCard.Item }) { - IncompleteVaccinationHomeCard(it) + TypedVHCreatorMod({ data[it] is VaccinationHomeCard.Item }) { + VaccinationHomeCard(it) }, SavedStateMod<HomeItemVH<HomeItem, ViewBinding>>() // For statistics card scroll position ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt index 78005f509523630f5a1b8e02a9e47154249187da..86ed99b07f2de4307fd264362a46bbd4c5800ad3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragment.kt @@ -26,7 +26,7 @@ import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment @@ -45,7 +45,7 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject { factoryProducer = { viewModelFactory } ) - val binding: HomeFragmentLayoutBinding by viewBindingLazy() + val binding: HomeFragmentLayoutBinding by viewBinding() @Inject lateinit var tracingExplanationDialog: TracingExplanationDialog @Inject lateinit var deviceTimeIncorrectDialog: DeviceTimeIncorrectDialog diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt index 5eebce6b2d80266b23191aadf9bc2d6790a307bd..1e6c375b886d772f4bd8edddc792d5ea02dd3f01 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeFragmentViewModel.kt @@ -75,9 +75,9 @@ import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson import de.rki.coronawarnapp.vaccination.core.VaccinationSettings import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository -import de.rki.coronawarnapp.vaccination.ui.homecard.CompleteVaccinationHomeCard +import de.rki.coronawarnapp.vaccination.ui.homecard.ImmuneVaccinationHomeCard import de.rki.coronawarnapp.vaccination.ui.homecard.CreateVaccinationHomeCard -import de.rki.coronawarnapp.vaccination.ui.homecard.IncompleteVaccinationHomeCard +import de.rki.coronawarnapp.vaccination.ui.homecard.VaccinationHomeCard import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -316,7 +316,8 @@ class HomeFragmentViewModel @AssistedInject constructor( vaccinatedPersons.forEach { vaccinatedPerson -> val card = when (vaccinatedPerson.getVaccinationStatus()) { - VaccinatedPerson.Status.COMPLETE -> CompleteVaccinationHomeCard.Item( + VaccinatedPerson.Status.COMPLETE, + VaccinatedPerson.Status.INCOMPLETE -> VaccinationHomeCard.Item( vaccinatedPerson = vaccinatedPerson, onClickAction = { popupEvents.postValue( @@ -324,7 +325,7 @@ class HomeFragmentViewModel @AssistedInject constructor( ) } ) - VaccinatedPerson.Status.INCOMPLETE -> IncompleteVaccinationHomeCard.Item( + VaccinatedPerson.Status.IMMUNITY -> ImmuneVaccinationHomeCard.Item( vaccinatedPerson = vaccinatedPerson, onClickAction = { popupEvents.postValue( @@ -332,9 +333,6 @@ class HomeFragmentViewModel @AssistedInject constructor( ) } ) - VaccinatedPerson.Status.IMMUNITY -> { - throw NotImplementedError() - } } add(card) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/overview/MainOverviewFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/overview/MainOverviewFragment.kt index 4696cb1367faff604b6775589543b6b1d58769e0..59de6c5ebfa8c5712b40db6e206bcb8187646c8a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/overview/MainOverviewFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/overview/MainOverviewFragment.kt @@ -7,7 +7,7 @@ import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentMainOverviewBinding import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * The fragment displays static informative content to the user @@ -18,7 +18,7 @@ import de.rki.coronawarnapp.util.ui.viewBindingLazy class MainOverviewFragment : Fragment(R.layout.fragment_main_overview) { - private val binding: FragmentMainOverviewBinding by viewBindingLazy() + private val binding: FragmentMainOverviewBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/share/MainShareFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/share/MainShareFragment.kt index 0fb6b9eaf491b211acfac1505e5975c3edd6561f..4df5f327ac43abd35fad922dc4a0f2ae8b4a82f7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/share/MainShareFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/share/MainShareFragment.kt @@ -8,14 +8,14 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentMainShareBinding import de.rki.coronawarnapp.util.ExternalActionHelper.shareText import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding /** * This fragment informs the user about what he is going to share and how he is going to help everybody with this :) */ class MainShareFragment : Fragment(R.layout.fragment_main_share) { - private val binding: FragmentMainShareBinding by viewBindingLazy() + private val binding: FragmentMainShareBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingAnalyticsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingAnalyticsFragment.kt index cd2d2231d7a44bb90c1a2ec4a51690bcf5aecb73..a8aebbdd5ae8f309d396741b30e55a82df7f784f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingAnalyticsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingAnalyticsFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -21,7 +21,7 @@ class OnboardingAnalyticsFragment : Fragment(R.layout.fragment_onboarding_ppa), @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: OnboardingAnalyticsViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentOnboardingPpaBinding by viewBindingLazy() + private val binding: FragmentOnboardingPpaBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaAnalyticsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaAnalyticsFragment.kt index 8efd0a961f244f665593e68517fbe20438e21050..f229edec44790dc008f52004691fb45c32f54ec0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaAnalyticsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaAnalyticsFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -23,7 +23,7 @@ class OnboardingDeltaAnalyticsFragment : Fragment(R.layout.fragment_onboarding_d @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: OnboardingAnalyticsViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentOnboardingDeltaPpaBinding by viewBindingLazy() + private val binding: FragmentOnboardingDeltaPpaBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt index 52710365102bf8daf3bf875db70d5a1898be829f..36b431511c69b25921365ebd514b19a83857809e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingDeltaInteroperabilityFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.util.convertToHyperlink import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -23,7 +23,7 @@ class OnboardingDeltaInteroperabilityFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: OnboardingDeltaInteroperabilityFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentOnboardingDeltaInteroperabilityBinding by viewBindingLazy() + private val binding: FragmentOnboardingDeltaInteroperabilityBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt index dc080acf55a7faf3509763a87fe63f2f02224ada..9b7f010b16b51f337408b3b4d1fb2b7b11196c5c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingFragment.kt @@ -9,7 +9,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentOnboardingBinding import de.rki.coronawarnapp.util.ExternalActionHelper.openUrl import de.rki.coronawarnapp.util.ui.doNavigate -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import java.util.Locale /** @@ -17,7 +17,7 @@ import java.util.Locale */ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) { - private val binding: FragmentOnboardingBinding by viewBindingLazy() + private val binding: FragmentOnboardingBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt index 60986d4539f5129eca30de0c02b84d7507abe1c5..bc62835486377428fa4c996de47c0bc895ac3f9f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt @@ -11,7 +11,7 @@ import de.rki.coronawarnapp.databinding.FragmentOnboardingNotificationsBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -28,7 +28,7 @@ class OnboardingNotificationsFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: OnboardingNotificationsViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentOnboardingNotificationsBinding by viewBindingLazy() + private val binding: FragmentOnboardingNotificationsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt index 286e5239365b4f5c83212fc6626b765a7b5b0e68..ed82a3750f6d7613a854496301b62c7846172f46 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingPrivacyFragment.kt @@ -9,7 +9,7 @@ import de.rki.coronawarnapp.databinding.FragmentOnboardingPrivacyBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -21,7 +21,7 @@ class OnboardingPrivacyFragment : Fragment(R.layout.fragment_onboarding_privacy) @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: OnboardingPrivacyViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentOnboardingPrivacyBinding by viewBindingLazy() + private val binding: FragmentOnboardingPrivacyBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt index 138cf3e0965778198092d5d98510cda8cc95ffdd..a63ba07f1e9f04306fd722386e13f3a385b42cbe 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTestFragment.kt @@ -9,7 +9,7 @@ import de.rki.coronawarnapp.databinding.FragmentOnboardingTestBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -21,7 +21,7 @@ class OnboardingTestFragment : Fragment(R.layout.fragment_onboarding_test), Auto @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: OnboardingTestViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentOnboardingTestBinding by viewBindingLazy() + private val binding: FragmentOnboardingTestBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt index 9c657fa366ef04b8eaed2885a48c48635736ad43..56dd5e6b18c6934e5e0a11f50c5f8b4ac4ff2b6e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingTracingFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.util.DialogHelper 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.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -23,7 +23,7 @@ import javax.inject.Inject */ class OnboardingTracingFragment : Fragment(R.layout.fragment_onboarding_tracing), AutoInject { - private val binding: FragmentOnboardingTracingBinding by viewBindingLazy() + private val binding: FragmentOnboardingTracingBinding by viewBinding() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: OnboardingTracingFragmentViewModel by cwaViewModels { viewModelFactory } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt index 2914a06a81f61e586bf6a1a2ef1b8e0a1c5bf88a..b7c535d6e3aff991e1e08a40d8a5560e19adb1ff 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt @@ -2,7 +2,6 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.qrcode.VerifiedTraceLocation -import de.rki.coronawarnapp.util.ui.LazyString sealed class CheckInEvent { @@ -12,8 +11,6 @@ sealed class CheckInEvent { data class ConfirmCheckIn(val verifiedTraceLocation: VerifiedTraceLocation) : CheckInEvent() - data class InvalidQrCode(val errorText: LazyString) : CheckInEvent() - data class ConfirmCheckInWithoutHistory(val verifiedTraceLocation: VerifiedTraceLocation) : CheckInEvent() data class EditCheckIn(val checkInId: Long, val position: Int) : CheckInEvent() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt index cb181fa24ae6d1ed5d384b4009ae8b64a601149f..488b48271452b4ac0e7012fb90a267387ea46d21 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt @@ -26,16 +26,14 @@ import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items.CameraPer import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items.CheckInsItem import de.rki.coronawarnapp.ui.presencetracing.attendee.edit.EditCheckInFragmentArgs import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.list.isSwipeable -import de.rki.coronawarnapp.util.list.onSwipeItem +import de.rki.coronawarnapp.util.list.setupSwipe import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.onScroll import de.rki.coronawarnapp.util.tryHumanReadableError -import de.rki.coronawarnapp.util.ui.LazyString import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -58,7 +56,7 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag ) } ) - private val binding: TraceLocationAttendeeCheckinsFragmentBinding by viewBindingLazy() + private val binding: TraceLocationAttendeeCheckinsFragmentBinding by viewBinding() private val checkInsAdapter = CheckInsAdapter() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -98,8 +96,6 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag ) } - is CheckInEvent.InvalidQrCode -> showInvalidQrCodeInformation(event.errorText) - is CheckInEvent.ConfirmCheckInWithoutHistory -> doNavigate( CheckInsFragmentDirections.actionCheckInsFragmentToConfirmCheckInFragmentCleanHistory( verifiedTraceLocation = event.verifiedTraceLocation @@ -134,15 +130,6 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag } } - private fun showInvalidQrCodeInformation(lazyErrorText: LazyString) { - MaterialAlertDialogBuilder(requireContext()).apply { - val errorText = lazyErrorText.get(context) - setTitle(R.string.trace_location_attendee_invalid_qr_code_dialog_title) - setMessage(getString(R.string.trace_location_attendee_invalid_qr_code_dialog_message, errorText)) - setPositiveButton(R.string.trace_location_attendee_invalid_qr_code_dialog_positive_button) { _, _ -> } - }.show() - } - private fun updateViews(items: List<CheckInsItem>) { checkInsAdapter.update(items) binding.apply { @@ -202,14 +189,7 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag } } - onSwipeItem( - context = requireContext(), - ) { position, direction -> - val checkInsItem = checkInsAdapter.data[position] - if (checkInsItem.isSwipeable()) { - checkInsItem.onSwipe(position, direction) - } - } + setupSwipe(context = requireContext()) } } @@ -223,11 +203,8 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag setPositiveButton(R.string.generic_action_remove) { _, _ -> viewModel.onRemoveCheckInConfirmed(checkIn) } - setNegativeButton(R.string.generic_action_abort) { _, _ -> - position?.let { checkInsAdapter.notifyItemChanged(position) } - } - - setOnCancelListener { + setNegativeButton(R.string.generic_action_abort) { _, _ -> } + setOnDismissListener { position?.let { checkInsAdapter.notifyItemChanged(position) } } }.show() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt index 9f89c87ea3221601957124d4f6b740dd8565a084..49ff5d5c58b886f892112fdbc136c6aa3a3cb786 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt @@ -20,8 +20,6 @@ import de.rki.coronawarnapp.util.coroutine.AppScope import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.flow.intervalFlow import de.rki.coronawarnapp.util.ui.SingleLiveEvent -import de.rki.coronawarnapp.util.ui.toLazyString -import de.rki.coronawarnapp.util.ui.toResolvingString import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory import kotlinx.coroutines.CoroutineScope @@ -85,7 +83,7 @@ class CheckInsViewModel @AssistedInject constructor( } fun onRemoveAllCheckIns() { - Timber.d("onRemovaAllCheckIns()") + Timber.d("onRemoveAllCheckIns()") events.postValue(CheckInEvent.ConfirmRemoveAll) } @@ -142,23 +140,15 @@ class CheckInsViewModel @AssistedInject constructor( } private fun verifyUri(uri: String) = launch { - try { - Timber.i("uri: $uri") - val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri) - when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) { - is TraceLocationVerifier.VerificationResult.Valid -> events.postValue( - if (cleanHistory) - CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation) - else - CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation) - ) - is TraceLocationVerifier.VerificationResult.Invalid -> - events.postValue(CheckInEvent.InvalidQrCode(verifyResult.errorTextRes.toResolvingString())) - } - } catch (e: Exception) { - Timber.d(e, "TraceLocation verification failed") - val msg = e.message ?: "QR-Code was invalid" - events.postValue(CheckInEvent.InvalidQrCode(msg.toLazyString())) + Timber.i("uri: $uri") + val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri) + when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) { + is TraceLocationVerifier.VerificationResult.Valid -> events.postValue( + if (cleanHistory) + CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation) + else + CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation) + ) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt index 509c638328ff2aeeb7b3fec897bbf35d89d3dfc7..df3550b21d692145182872c57759c9bfe0a73117 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/consent/CheckInsConsentFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -20,7 +20,7 @@ import javax.inject.Inject class CheckInsConsentFragment : Fragment(R.layout.check_ins_consent_fragment), AutoInject { - private val binding: CheckInsConsentFragmentBinding by viewBindingLazy() + private val binding: CheckInsConsentFragmentBinding by viewBinding() private val navArgs by navArgs<CheckInsConsentFragmentArgs>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/ActiveCheckInVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/ActiveCheckInVH.kt index 40af15182ecb798da9abffe633a558a51c13ba02..2ce414b1d3750b342259a51b8eb7bf45c9181857 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/ActiveCheckInVH.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/ActiveCheckInVH.kt @@ -1,12 +1,13 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView import de.rki.coronawarnapp.R import de.rki.coronawarnapp.contactdiary.util.getLocale import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsItemActiveBinding import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone -import de.rki.coronawarnapp.util.list.SwipeConsumer +import de.rki.coronawarnapp.util.list.Swipeable import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer import org.joda.time.Duration import org.joda.time.DurationFieldType @@ -20,7 +21,14 @@ class ActiveCheckInVH(parent: ViewGroup) : BaseCheckInVH<ActiveCheckInVH.Item, TraceLocationAttendeeCheckinsItemActiveBinding>( layoutRes = R.layout.trace_location_attendee_checkins_item_active, parent = parent - ) { + ), + Swipeable { + + private var latestItem: Item? = null + + override fun onSwipe(holder: RecyclerView.ViewHolder, direction: Int) { + latestItem?.let { it.onSwipeItem(it.checkin, holder.adapterPosition) } + } override val viewBinding: Lazy<TraceLocationAttendeeCheckinsItemActiveBinding> = lazy { TraceLocationAttendeeCheckinsItemActiveBinding.bind(itemView) @@ -35,6 +43,7 @@ class ActiveCheckInVH(parent: ViewGroup) : payloads: List<Any> ) -> Unit = { item, payloads -> val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item + latestItem = curItem val checkInStartUserTZ = curItem.checkin.checkInStart.toUserTimeZone() @@ -93,12 +102,10 @@ class ActiveCheckInVH(parent: ViewGroup) : val onRemoveItem: (CheckIn) -> Unit, val onCheckout: (CheckIn) -> Unit, val onSwipeItem: (CheckIn, Int) -> Unit, - ) : CheckInsItem, HasPayloadDiffer, SwipeConsumer { + ) : CheckInsItem, HasPayloadDiffer { override val stableId: Long = checkin.id override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null - - override fun onSwipe(position: Int, direction: Int) = onSwipeItem(checkin, position) } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/CameraPermissionVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/CameraPermissionVH.kt index 43d63e51f42d128ae92b3c135c45692a2dfde6ac..c0dd87bca11e3fa56ea0debb73223530043d023c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/CameraPermissionVH.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/CameraPermissionVH.kt @@ -3,14 +3,12 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items import android.view.ViewGroup import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsItemCameraBinding -import de.rki.coronawarnapp.util.list.Movable class CameraPermissionVH(parent: ViewGroup) : BaseCheckInVH<CameraPermissionVH.Item, TraceLocationAttendeeCheckinsItemCameraBinding>( layoutRes = R.layout.trace_location_attendee_checkins_item_camera, parent = parent - ), - Movable { + ) { override val viewBinding: Lazy<TraceLocationAttendeeCheckinsItemCameraBinding> = lazy { TraceLocationAttendeeCheckinsItemCameraBinding.bind(itemView) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/PastCheckInVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/PastCheckInVH.kt index 106b09f13341fddceb6265d968b8ab136b5ef922..67f8c43637de037742c57b5a894451b7f119659d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/PastCheckInVH.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/items/PastCheckInVH.kt @@ -1,18 +1,26 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsItemPastBinding import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.common.checkoutInfo -import de.rki.coronawarnapp.util.list.SwipeConsumer +import de.rki.coronawarnapp.util.list.Swipeable import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer class PastCheckInVH(parent: ViewGroup) : BaseCheckInVH<PastCheckInVH.Item, TraceLocationAttendeeCheckinsItemPastBinding>( layoutRes = R.layout.trace_location_attendee_checkins_item_past, parent = parent - ) { + ), + Swipeable { + + private var latestItem: Item? = null + + override fun onSwipe(holder: RecyclerView.ViewHolder, direction: Int) { + latestItem?.let { it.onSwipeItem(it.checkin, holder.adapterPosition) } + } override val viewBinding: Lazy<TraceLocationAttendeeCheckinsItemPastBinding> = lazy { TraceLocationAttendeeCheckinsItemPastBinding.bind(itemView) @@ -23,6 +31,8 @@ class PastCheckInVH(parent: ViewGroup) : payloads: List<Any> ) -> Unit = { item, payloads -> val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item + latestItem = curItem + description.text = curItem.checkin.description address.text = curItem.checkin.address @@ -46,11 +56,9 @@ class PastCheckInVH(parent: ViewGroup) : val onCardClicked: (CheckIn, Int) -> Unit, val onRemoveItem: (CheckIn) -> Unit, val onSwipeItem: (CheckIn, Int) -> Unit, - ) : CheckInsItem, HasPayloadDiffer, SwipeConsumer { + ) : CheckInsItem, HasPayloadDiffer { override val stableId: Long = checkin.id override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null - - override fun onSwipe(position: Int, direction: Int) = onSwipeItem(checkin, position) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/confirm/ConfirmCheckInFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/confirm/ConfirmCheckInFragment.kt index 5b234f97b41a933084d8494264450eb9bf9dfda3..7174a54959c7c4ec71590b375fd4682e795ca07e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/confirm/ConfirmCheckInFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/confirm/ConfirmCheckInFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.ui.durationpicker.DurationPicker import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import org.joda.time.Duration @@ -39,7 +39,7 @@ class ConfirmCheckInFragment : Fragment(R.layout.fragment_confirm_check_in), Aut returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) } - private val binding: FragmentConfirmCheckInBinding by viewBindingLazy() + private val binding: FragmentConfirmCheckInBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/edit/EditCheckInFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/edit/EditCheckInFragment.kt index af5a38c45f1298fd91d06ad4d4319e509eb331eb..8f79f71c671f4bf88707e9cadf23de90584128d9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/edit/EditCheckInFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/edit/EditCheckInFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.databinding.FragmentEditCheckInBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import org.joda.time.DateTimeZone @@ -44,7 +44,7 @@ class EditCheckInFragment : Fragment(R.layout.fragment_edit_check_in), AutoInjec sharedElementReturnTransition = MaterialContainerTransform() } - private val binding: FragmentEditCheckInBinding by viewBindingLazy() + private val binding: FragmentEditCheckInBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingFragment.kt index f7c9de003bf4ca062fb86dbb642040e63026da14..ea2cabae6a39c0f355eb7ffbc64d263126be2efe 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/onboarding/CheckInOnboardingFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -22,7 +22,7 @@ class CheckInOnboardingFragment : Fragment(R.layout.fragment_trace_location_onbo @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: CheckInOnboardingViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentTraceLocationOnboardingBinding by viewBindingLazy() + private val binding: FragmentTraceLocationOnboardingBinding by viewBinding() private val args by navArgs<CheckInOnboardingFragmentArgs>() override fun onCreate(savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt index 47ddf2f674d5fc0ba24113a654e00d04e7677198..c3e6e906af2b503c22819124958efafcb417404d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeFragment.kt @@ -8,6 +8,7 @@ import android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT import androidx.fragment.app.Fragment import androidx.navigation.NavOptions import androidx.navigation.fragment.findNavController +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.transition.MaterialContainerTransform import com.google.zxing.BarcodeFormat import com.journeyapps.barcodescanner.DefaultDecoderFactory @@ -17,9 +18,10 @@ import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.CheckInsFragmen import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.permission.CameraPermissionHelper +import de.rki.coronawarnapp.util.ui.LazyString import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import timber.log.Timber @@ -32,7 +34,7 @@ class ScanCheckInQrCodeFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: ScanCheckInQrCodeViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentScanQrCodeBinding by viewBindingLazy() + private val binding: FragmentScanQrCodeBinding by viewBinding() private var showsPermissionDialog = false override fun onCreate(savedInstanceState: Bundle?) { @@ -68,6 +70,7 @@ class ScanCheckInQrCodeFragment : .build() ) } + is ScanCheckInQrCodeNavigation.InvalidQrCode -> showInvalidQrCodeInformation(navEvent.errorText) } } } @@ -126,6 +129,20 @@ class ScanCheckInQrCodeFragment : DialogHelper.showDialog(permissionDeniedDialog) } + private fun showInvalidQrCodeInformation(lazyErrorText: LazyString) { + MaterialAlertDialogBuilder(requireContext()).apply { + val errorText = lazyErrorText.get(context) + setTitle(R.string.trace_location_attendee_invalid_qr_code_dialog_title) + setMessage(getString(R.string.trace_location_attendee_invalid_qr_code_dialog_message, errorText)) + setPositiveButton(R.string.trace_location_attendee_invalid_qr_code_dialog_positive_button) { _, _ -> + startDecode() + } + setNegativeButton(R.string.trace_location_attendee_invalid_qr_code_dialog_negative_button) { _, _ -> + popBackStack() + } + }.show() + } + private fun showCameraPermissionRationaleDialog() { val cameraPermissionRationaleDialogInstance = DialogHelper.DialogInstance( requireActivity(), diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt index 688adc324d9c5747fea6216fad480c5f1ba6eb77..89b0b0571f8fa499817d09f235d1649477d6274b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeNavigation.kt @@ -1,6 +1,9 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.scan +import de.rki.coronawarnapp.util.ui.LazyString + sealed class ScanCheckInQrCodeNavigation { object BackNavigation : ScanCheckInQrCodeNavigation() + data class InvalidQrCode(val errorText: LazyString) : ScanCheckInQrCodeNavigation() data class ScanResultNavigation(val uri: String) : ScanCheckInQrCodeNavigation() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt index c9227d4a526c385bb47403fa1e8a01c8b934c5b9..119e05465c7e07f5dc6deb40404804c7be2c8b17 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModel.kt @@ -3,25 +3,45 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.scan import com.journeyapps.barcodescanner.BarcodeResult import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QRCodeUriParser +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocationVerifier import de.rki.coronawarnapp.util.permission.CameraSettings import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.ui.toLazyString +import de.rki.coronawarnapp.util.ui.toResolvingString import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory import timber.log.Timber class ScanCheckInQrCodeViewModel @AssistedInject constructor( - private val cameraSettings: CameraSettings + private val qrCodeUriParser: QRCodeUriParser, + private val cameraSettings: CameraSettings, + private val traceLocationVerifier: TraceLocationVerifier ) : CWAViewModel() { val events = SingleLiveEvent<ScanCheckInQrCodeNavigation>() fun onNavigateUp() { - events.value = ScanCheckInQrCodeNavigation.BackNavigation + events.postValue(ScanCheckInQrCodeNavigation.BackNavigation) } - fun onScanResult(barcodeResult: BarcodeResult) { - events.value = ScanCheckInQrCodeNavigation.ScanResultNavigation( - barcodeResult.result.text - ) + fun onScanResult(barcodeResult: BarcodeResult) = launch { + try { + Timber.i("uri: $barcodeResult.result.text") + val qrCodePayload = qrCodeUriParser.getQrCodePayload(barcodeResult.result.text) + when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) { + is TraceLocationVerifier.VerificationResult.Invalid -> + events.postValue( + ScanCheckInQrCodeNavigation.InvalidQrCode( + verifyResult.errorTextRes.toResolvingString() + ) + ) + else -> events.postValue(ScanCheckInQrCodeNavigation.ScanResultNavigation(barcodeResult.result.text)) + } + } catch (e: Exception) { + Timber.d(e, "TraceLocation verification failed") + val msg = e.message ?: "QR-Code was invalid" + events.postValue(ScanCheckInQrCodeNavigation.InvalidQrCode(msg.toLazyString())) + } } fun setCameraDeniedPermanently(denied: Boolean) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/category/TraceLocationCategoryFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/category/TraceLocationCategoryFragment.kt index 99a29a46715e75433ab4a00e2dabcaf0d9ef1b87..c66bda5b1730b3586410e1b56feeaa1fe93d770e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/category/TraceLocationCategoryFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/category/TraceLocationCategoryFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -22,7 +22,7 @@ class TraceLocationCategoryFragment : Fragment(R.layout.trace_location_organizer @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: TraceLocationCategoryViewModel by cwaViewModels { viewModelFactory } - private val binding: TraceLocationOrganizerCategoryFragmentBinding by viewBindingLazy() + private val binding: TraceLocationOrganizerCategoryFragmentBinding by viewBinding() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) 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 64348cc5adb780b0d342e0caeaf8ab0d0c79c9b8..7777f7c6a95d1dac58eba7ac7bae4c72f97feb3e 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 @@ -22,7 +22,7 @@ import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import org.joda.time.DateTime @@ -33,7 +33,7 @@ import javax.inject.Inject class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_fragment), AutoInject { - private val binding: TraceLocationCreateFragmentBinding by viewBindingLazy() + private val binding: TraceLocationCreateFragmentBinding by viewBinding() private val navArgs by navArgs<TraceLocationCreateFragmentArgs>() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory 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 75a23ca0a641f20150d6bcdb8e1069279e34b03d..ee6f9e9bdcb47392f40db32fbeb99a23b408d74f 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 @@ -23,7 +23,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -42,7 +42,7 @@ class QrCodeDetailFragment : Fragment(R.layout.trace_location_organizer_qr_code_ } ) - private val binding: TraceLocationOrganizerQrCodeDetailFragmentBinding by viewBindingLazy() + private val binding: TraceLocationOrganizerQrCodeDetailFragmentBinding by viewBinding() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/TraceLocationsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/TraceLocationsFragment.kt index 05326b20bc1fc20fa88e1c8dcff56bef8cc053fd..ad212665966570326dbd4de14ac6b43da6fb138f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/TraceLocationsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/TraceLocationsFragment.kt @@ -20,15 +20,14 @@ import de.rki.coronawarnapp.ui.presencetracing.organizer.category.adapter.catego import de.rki.coronawarnapp.ui.presencetracing.organizer.details.QrCodeDetailFragmentArgs import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.list.isSwipeable -import de.rki.coronawarnapp.util.list.onSwipeItem +import de.rki.coronawarnapp.util.list.setupSwipe import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.onScroll import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import timber.log.Timber @@ -38,7 +37,7 @@ class TraceLocationsFragment : Fragment(R.layout.trace_location_organizer_trace_ @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: TraceLocationsViewModel by cwaViewModels { viewModelFactory } - private val binding: TraceLocationOrganizerTraceLocationsListFragmentBinding by viewBindingLazy() + private val binding: TraceLocationOrganizerTraceLocationsListFragmentBinding by viewBinding() private val traceLocationsAdapter = TraceLocationsAdapter() override fun onCreate(savedInstanceState: Bundle?) { @@ -58,12 +57,7 @@ class TraceLocationsFragment : Fragment(R.layout.trace_location_organizer_trace_ onScroll { onScrollChange(it) } - onSwipeItem(context = requireContext()) { position, direction -> - val traceLocationItem = traceLocationsAdapter.data[position] - if (traceLocationItem.isSwipeable()) { - traceLocationItem.onSwipe(position, direction) - } - } + setupSwipe(context = requireContext()) } binding.toolbar.setNavigationOnClickListener { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/items/TraceLocationVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/items/TraceLocationVH.kt index 8b1504fc242d79535e301a185a80fdaa9afd9c1e..a2a24e88483fcbb9e10c74824de1985ef1301118 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/items/TraceLocationVH.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/list/items/TraceLocationVH.kt @@ -3,19 +3,27 @@ package de.rki.coronawarnapp.ui.presencetracing.organizer.list.items import android.view.ViewGroup import androidx.core.view.isGone import androidx.core.view.isVisible +import androidx.recyclerview.widget.RecyclerView import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.TraceLocationOrganizerTraceLocationsItemBinding import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items.BaseCheckInVH.Companion.setupMenu import de.rki.coronawarnapp.ui.presencetracing.organizer.list.TraceLocationsAdapter -import de.rki.coronawarnapp.util.list.SwipeConsumer +import de.rki.coronawarnapp.util.list.Swipeable import org.joda.time.format.DateTimeFormat class TraceLocationVH(parent: ViewGroup) : TraceLocationsAdapter.ItemVH<TraceLocationVH.Item, TraceLocationOrganizerTraceLocationsItemBinding>( layoutRes = R.layout.trace_location_organizer_trace_locations_item, parent = parent - ) { + ), + Swipeable { + + private var latestItem: Item? = null + + override fun onSwipe(holder: RecyclerView.ViewHolder, direction: Int) { + latestItem?.let { it.onSwipeItem(it.traceLocation, holder.adapterPosition) } + } override val viewBinding: Lazy<TraceLocationOrganizerTraceLocationsItemBinding> = lazy { TraceLocationOrganizerTraceLocationsItemBinding.bind(itemView) @@ -25,6 +33,7 @@ class TraceLocationVH(parent: ViewGroup) : item: Item, payloads: List<Any> ) -> Unit = { item, _ -> + latestItem = item description.text = item.traceLocation.description address.text = item.traceLocation.address @@ -84,8 +93,7 @@ class TraceLocationVH(parent: ViewGroup) : val onDeleteItem: (TraceLocation) -> Unit, val onSwipeItem: (TraceLocation, Int) -> Unit, val onCardClicked: (TraceLocation, Int) -> Unit - ) : TraceLocationItem, SwipeConsumer { + ) : TraceLocationItem { override val stableId: Long = traceLocation.id.hashCode().toLong() - override fun onSwipe(position: Int, direction: Int) = onSwipeItem(traceLocation, position) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterFragment.kt index 0d7b28cd67eeb742ea1b1dec0b942821e4602ccf..afdc142039a312bd50ead5a4858ffe498f05732c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/poster/QrCodePosterFragment.kt @@ -23,7 +23,7 @@ import de.rki.coronawarnapp.ui.print.PrintingAdapter import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.files.FileSharing import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -43,7 +43,7 @@ class QrCodePosterFragment : Fragment(R.layout.qr_code_poster_fragment), AutoInj } ) - private val binding: QrCodePosterFragmentBinding by viewBindingLazy() + private val binding: QrCodePosterFragmentBinding by viewBinding() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/qrinfo/TraceLocationQRInfoFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/qrinfo/TraceLocationQRInfoFragment.kt index d69518a4d34a09bf371b7294266817ef224ef4e5..8a5ed871519dc5f60ad65e630b1dbd88b40f7533 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/qrinfo/TraceLocationQRInfoFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/organizer/qrinfo/TraceLocationQRInfoFragment.kt @@ -13,14 +13,14 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject class TraceLocationQRInfoFragment : Fragment(R.layout.trace_location_organizer_qr_code_info_fragment), AutoInject { - private val binding: TraceLocationOrganizerQrCodeInfoFragmentBinding by viewBindingLazy() + private val binding: TraceLocationOrganizerQrCodeInfoFragmentBinding by viewBinding() @Inject lateinit var settings: TraceLocationOrganizerSettings diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt index 6a6b7da8225f26112ede2cb0fa9b0cf6c9de2122..0f4420cc9b091306c0098b01842e93a780cf6cd3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/qrcode/fullscreen/QrCodeFullScreenFragment.kt @@ -21,7 +21,7 @@ import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentQrCodeFullScreenBinding import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -30,7 +30,7 @@ class QrCodeFullScreenFragment : Fragment(R.layout.fragment_qr_code_full_screen) @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val binding: FragmentQrCodeFullScreenBinding by viewBindingLazy() + private val binding: FragmentQrCodeFullScreenBinding by viewBinding() private val args by navArgs<QrCodeFullScreenFragmentArgs>() private val viewModel: QrCodeFullScreenViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt index b0ee388eac0b4e4f64d2a6cb3b84d329940b28fe..46044d20bc5dbb65f8bc999738322dc3bca5b629 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/SettingsResetFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -26,7 +26,7 @@ class SettingsResetFragment : Fragment(R.layout.fragment_settings_reset), AutoIn @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: SettingsResetViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSettingsResetBinding by viewBindingLazy() + private val binding: FragmentSettingsResetBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/analytics/SettingsPrivacyPreservingAnalyticsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/analytics/SettingsPrivacyPreservingAnalyticsFragment.kt index 1613ba258ef82499d699259d0592dab2ea57f958..128e5914c986c9679ae7f733794401d3e5e323a9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/analytics/SettingsPrivacyPreservingAnalyticsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/analytics/SettingsPrivacyPreservingAnalyticsFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -23,7 +23,7 @@ class SettingsPrivacyPreservingAnalyticsFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SettingsPrivacyPreservingAnalyticsViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSettingsPrivacyPreservingAnalyticsBinding by viewBindingLazy() + private val binding: FragmentSettingsPrivacyPreservingAnalyticsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/backgroundpriority/SettingsBackgroundPriorityFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/backgroundpriority/SettingsBackgroundPriorityFragment.kt index e4ae1166f822ebd64404d4962920936c232b4d32..96d83db8f091e4b72b3beef2cebfdb64cb76d830 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/backgroundpriority/SettingsBackgroundPriorityFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/backgroundpriority/SettingsBackgroundPriorityFragment.kt @@ -11,7 +11,7 @@ import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -25,7 +25,7 @@ class SettingsBackgroundPriorityFragment : Fragment(R.layout.fragment_settings_b @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: SettingsBackgroundPriorityFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSettingsBackgroundPriorityBinding by viewBindingLazy() + private val binding: FragmentSettingsBackgroundPriorityBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/notifications/NotificationSettingsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/notifications/NotificationSettingsFragment.kt index f5f75de0b1166b3b9144a1702a28cd4252b47fb0..e7db1b6b14cb3bc35b7f5d90c92a170c651c112a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/notifications/NotificationSettingsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/notifications/NotificationSettingsFragment.kt @@ -10,7 +10,7 @@ import de.rki.coronawarnapp.util.ExternalActionHelper.openAppNotificationSetting import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -27,7 +27,7 @@ class NotificationSettingsFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: NotificationSettingsFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSettingsNotificationsBinding by viewBindingLazy() + private val binding: FragmentSettingsNotificationsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsFragment.kt index e2c60ec83049bbe65c2fd4529019e658ff61badd..eb07d1e0b45d6f189dcf19893696a94c7449d0d7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsFragment.kt @@ -11,7 +11,7 @@ import de.rki.coronawarnapp.ui.doNavigate import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -24,7 +24,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), AutoInject { @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val vm: SettingsFragmentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSettingsBinding by viewBindingLazy() + private val binding: FragmentSettingsBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/deletionwarning/SubmissionDeletionWarningFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/deletionwarning/SubmissionDeletionWarningFragment.kt index 562c87cfc33584fcd0b33e0755fd53d514160cde..623f30a36ff938ee643c382133385a2ebe348b8c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/deletionwarning/SubmissionDeletionWarningFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/deletionwarning/SubmissionDeletionWarningFragment.kt @@ -21,7 +21,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -41,7 +41,7 @@ class SubmissionDeletionWarningFragment : Fragment(R.layout.fragment_submission_ factory.create(args.coronaTestQrCode, args.coronaTestTan, args.isConsentGiven) } ) - private val binding: FragmentSubmissionDeletionWarningBinding by viewBindingLazy() + private val binding: FragmentSubmissionDeletionWarningBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt index 7d6e8d04fd17a57cef8474283fc89e2ef550b1d1..00252e58418ebadef1067d786b7e5b756ed73fee 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionContactFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.linkifyPhoneNumbers import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -27,7 +27,7 @@ class SubmissionContactFragment : Fragment(R.layout.fragment_submission_contact) @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionContactViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionContactBinding by viewBindingLazy() + private val binding: FragmentSubmissionContactBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt index 11f7585630af3e8e2d67608088233528a34872d7..7c6f9a9b364ef1c3a76a61f3d7c602f9320ad202 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/fragment/SubmissionDispatcherFragment.kt @@ -13,7 +13,7 @@ import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import timber.log.Timber @@ -23,7 +23,7 @@ class SubmissionDispatcherFragment : Fragment(R.layout.fragment_submission_dispa @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionDispatcherViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionDispatcherBinding by viewBindingLazy() + private val binding: FragmentSubmissionDispatcherBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/consent/SubmissionConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/consent/SubmissionConsentFragment.kt index b25f5d6766251135ca06e8293e0890f6d1a9faf4..e5fd022f5390e06bdbdb6a4a1c91e76dcb3429e4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/consent/SubmissionConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/consent/SubmissionConsentFragment.kt @@ -24,7 +24,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -33,7 +33,7 @@ class SubmissionConsentFragment : Fragment(R.layout.fragment_submission_consent) @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionConsentViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionConsentBinding by viewBindingLazy() + private val binding: FragmentSubmissionConsentBinding by viewBinding() private val navArgs by navArgs<SubmissionConsentFragmentArgs>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt index 561cf45bf9a93b449f9876f9bee09a02abda8bdc..f77d17f363e3e104a40230fa53be8f44266578c3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanFragment.kt @@ -27,7 +27,7 @@ import de.rki.coronawarnapp.util.permission.CameraPermissionHelper import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -49,7 +49,7 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co } ) - private val binding: FragmentSubmissionQrCodeScanBinding by viewBindingLazy() + private val binding: FragmentSubmissionQrCodeScanBinding by viewBinding() private var showsPermissionDialog = false @Suppress("ComplexMethod") @@ -102,17 +102,7 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co ApiRequestState.STARTED -> View.VISIBLE else -> View.GONE } - - if (ApiRequestState.SUCCESS == state.apiRequestState) { - return@observe2 - } - - if (state.test == null) { - Timber.w("Successful API request, but test was null?") - return@observe2 - } - - when (state.test.testResult) { + when (state.test?.testResult) { CoronaTestResult.PCR_POSITIVE -> NavGraphDirections.actionToSubmissionTestResultAvailableFragment(testType = Type.PCR) @@ -132,6 +122,10 @@ class SubmissionQRCodeScanFragment : Fragment(R.layout.fragment_submission_qr_co CoronaTestResult.RAT_PENDING, CoronaTestResult.RAT_REDEEMED -> NavGraphDirections.actionSubmissionTestResultPendingFragment(testType = Type.RAPID_ANTIGEN) + null -> { + Timber.w("Successful API request, but test was null?") + return@observe2 + } }.run { doNavigate(this) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt index 93053d7e0a31f9c8cc8faeaebe68e6e95cac31c3..42d8a6a53e4751e7f8c5b2ecab01b468b9bea879 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import timber.log.Timber @@ -30,7 +30,7 @@ class SubmissionTestResultAvailableFragment : Fragment(R.layout.fragment_submiss @Inject lateinit var appShortcutsHelper: AppShortcutsHelper @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val binding: FragmentSubmissionTestResultAvailableBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultAvailableBinding by viewBinding() private lateinit var keyRetrievalProgress: SubmissionBlockingDialog private val navArgs by navArgs<SubmissionTestResultAvailableFragmentArgs>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt index a97360430793e8efc5c53c244cd9b7f3d9fdb888..46787962c48a5821e3c672b4f96a403328d90af7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -27,7 +27,7 @@ class SubmissionResultReadyFragment : Fragment(R.layout.fragment_submission_resu @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionResultReadyViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionResultReadyBinding by viewBindingLazy() + private val binding: FragmentSubmissionResultReadyBinding by viewBinding() private val navArgs by navArgs<CheckInsConsentFragmentArgs>() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt index 4c6ddaa7d8b92a557c33ca491eb82a26e68be719..95be3650085220ebc91717b577962634e7bfa0e8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/submissiondone/SubmissionDoneFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -32,7 +32,7 @@ class SubmissionDoneFragment : Fragment(R.layout.fragment_submission_done), Auto } ) - private val binding: FragmentSubmissionDoneBinding by viewBindingLazy() + private val binding: FragmentSubmissionDoneBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt index 5c2bac13584fa622a1306fa03cb0592c920e4e51..2cd5e961b224c51724e1b2a3900efc418b7ccac9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/calendar/SubmissionSymptomCalendarFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.formatter.formatSymptomBackgroundButtonStyleByS import de.rki.coronawarnapp.util.formatter.formatSymptomButtonTextStyleByState import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -36,7 +36,7 @@ class SubmissionSymptomCalendarFragment : } ) - private val binding: FragmentSubmissionSymptomCalendarBinding by viewBindingLazy() + private val binding: FragmentSubmissionSymptomCalendarBinding by viewBinding() private lateinit var uploadDialog: SubmissionBlockingDialog override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -57,6 +57,7 @@ class SubmissionSymptomCalendarFragment : } viewModel.routeToScreen.observe2(this) { + uploadDialog.setState(show = false) doNavigate(it) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt index 0a60e95c23b109d379d6031f0094186c53885056..34d64ce1cf03a955a85718ed3cd45f8b27235dd1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionFragment.kt @@ -17,7 +17,7 @@ import de.rki.coronawarnapp.util.formatter.formatSymptomBackgroundButtonStyleByS import de.rki.coronawarnapp.util.formatter.formatSymptomButtonTextStyleByState import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -40,7 +40,7 @@ class SubmissionSymptomIntroductionFragment : factory.create(navArgs.testType) } ) - private val binding: FragmentSubmissionSymptomIntroBinding by viewBindingLazy() + private val binding: FragmentSubmissionSymptomIntroBinding by viewBinding() private lateinit var uploadDialog: SubmissionBlockingDialog @@ -49,6 +49,7 @@ class SubmissionSymptomIntroductionFragment : uploadDialog = SubmissionBlockingDialog(requireContext()) viewModel.navigation.observe2(this) { + uploadDialog.setState(show = false) doNavigate(it) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt index eaad5f6f953b567e3e7ffa71353c81a6e9abfe9b..97ea51f53dcb69910aeda363e1097fbcf3f10aff 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/SubmissionTanFragment.kt @@ -19,7 +19,7 @@ import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack import de.rki.coronawarnapp.util.ui.setGone -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -32,7 +32,7 @@ class SubmissionTanFragment : Fragment(R.layout.fragment_submission_tan), AutoIn @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: SubmissionTanViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentSubmissionTanBinding by viewBindingLazy() + private val binding: FragmentSubmissionTanBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidFragment.kt index 2bdd5415916b8abee52858e0fe63fb66d25a1e9c..890ff33df0c95c9c6d6562db89d94008d5bd131a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/invalid/SubmissionTestResultInvalidFragment.kt @@ -4,9 +4,11 @@ import android.content.DialogInterface import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.navigation.fragment.navArgs import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.coronatest.type.CoronaTest import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultInvalidBinding import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat import de.rki.coronawarnapp.util.DialogHelper @@ -14,7 +16,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -32,7 +34,7 @@ class SubmissionTestResultInvalidFragment : Fragment(R.layout.fragment_submissio } ) - private val binding: FragmentSubmissionTestResultInvalidBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultInvalidBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -44,6 +46,20 @@ class SubmissionTestResultInvalidFragment : Fragment(R.layout.fragment_submissio submissionTestResultHeader.headerButtonBack.buttonIcon.setOnClickListener { popBackStack() } } + binding.apply { + + when (navArgs.testType) { + CoronaTest.Type.PCR -> { + testResultInvalidStepsPcrAdded.isVisible = true + testResultInvalidStepsRatAdded.isVisible = false + } + CoronaTest.Type.RAPID_ANTIGEN -> { + testResultInvalidStepsPcrAdded.isVisible = false + testResultInvalidStepsRatAdded.isVisible = true + } + } + } + viewModel.testResult.observe2(this) { binding.submissionTestResultSection.setTestResultSection(it.coronaTest) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt index a746633a5c8a6a7e5e164c9d7eeda49ce7d407f1..b3eb8f9bb14043d99eab30fe568aa671ef9f4a2f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/negative/SubmissionTestResultNegativeFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -32,7 +32,7 @@ class SubmissionTestResultNegativeFragment : Fragment(R.layout.fragment_submissi } ) - private val binding: FragmentSubmissionTestResultNegativeBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultNegativeBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/pending/SubmissionTestResultPendingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/pending/SubmissionTestResultPendingFragment.kt index 82ebb903ba099c6be85cddff61711e1e71a197ef..c855fe1ad3730a1794af90a10d4e90f42627bbfe 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/pending/SubmissionTestResultPendingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/pending/SubmissionTestResultPendingFragment.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityEvent import androidx.appcompat.app.AlertDialog +import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.navigation.fragment.navArgs @@ -21,15 +22,14 @@ import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.observeOnce import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.setInvisible -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject class SubmissionTestResultPendingFragment : Fragment(R.layout.fragment_submission_test_result_pending), AutoInject { - private val binding: FragmentSubmissionTestResultPendingBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultPendingBinding by viewBinding() private var errorDialog: AlertDialog? = null @@ -55,28 +55,19 @@ class SubmissionTestResultPendingFragment : Fragment(R.layout.fragment_submissio val hasResult = !result.coronaTest.isProcessing binding.apply { submissionTestResultSection.setTestResultSection(result.coronaTest) - submissionTestResultSpinner.setInvisible(hasResult) - submissionTestResultContent.setInvisible(!hasResult) - buttonContainer.setInvisible(!hasResult) + submissionTestResultSpinner.isInvisible = hasResult + submissionTestResultContent.isInvisible = !hasResult + buttonContainer.isInvisible = !hasResult } } binding.apply { + val isPcr = navArgs.testType == CoronaTest.Type.PCR + testResultPendingStepsWaitingAntigenResult.isVisible = !isPcr + testResultPendingStepsRatAdded.isVisible = !isPcr - when (navArgs.testType) { - CoronaTest.Type.PCR -> { - testResultPendingStepsWaitingPcrResult.isVisible = true - testResultPendingStepsPcrAdded.isVisible = true - testResultPendingStepsWaitingAntigenResult.isVisible = false - testResultPendingStepsRatAdded.isVisible = false - } - CoronaTest.Type.RAPID_ANTIGEN -> { - testResultPendingStepsWaitingAntigenResult.isVisible = true - testResultPendingStepsRatAdded.isVisible = true - testResultPendingStepsWaitingPcrResult.isVisible = false - testResultPendingStepsPcrAdded.isVisible = false - } - } + testResultPendingStepsWaitingPcrResult.isVisible = isPcr + testResultPendingStepsPcrAdded.isVisible = isPcr } binding.apply { @@ -86,11 +77,7 @@ class SubmissionTestResultPendingFragment : Fragment(R.layout.fragment_submissio } submissionTestResultButtonPendingRemoveTest.setOnClickListener { removeTestAfterConfirmation() } - - submissionTestResultHeader.headerButtonBack.buttonIcon.setOnClickListener { - navigateToMainScreen() - } - + submissionTestResultHeader.headerButtonBack.buttonIcon.setOnClickListener { navigateToMainScreen() } consentStatus.setOnClickListener { viewModel.onConsentClicked() } } @@ -105,24 +92,18 @@ class SubmissionTestResultPendingFragment : Fragment(R.layout.fragment_submissio DialogHelper.showDialog(dialog) } - viewModel.routeToScreen.observe2(this) { - it?.let { doNavigate(it) } ?: navigateToMainScreen() - } - viewModel.errorEvent.observe2(this) { - it.toErrorDialogBuilder(requireContext()).show() - } + viewModel.routeToScreen.observe2(this) { it?.let { doNavigate(it) } ?: navigateToMainScreen() } + viewModel.errorEvent.observe2(this) { it.toErrorDialogBuilder(requireContext()).show() } } override fun onResume() { super.onResume() binding.submissionTestResultContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT) - viewModel.cwaWebExceptionLiveData.observeOnce(this.viewLifecycleOwner) { exception -> - handleError(exception) - } + viewModel.cwaWebExceptionLiveData.observeOnce(viewLifecycleOwner) { handleError(it) } } override fun onPause() { - viewModel.cwaWebExceptionLiveData.removeObservers(this.viewLifecycleOwner) + viewModel.cwaWebExceptionLiveData.removeObservers(viewLifecycleOwner) errorDialog?.dismiss() super.onPause() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt index 2141e745ca2185d09e2a34968a8b909e7ad6dc80..e8cd9231be1b25e0ecf1523d2b3ee394e0b540c6 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultConsentGivenFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -38,7 +38,7 @@ class SubmissionTestResultConsentGivenFragment : } ) - private val binding: FragmentSubmissionTestResultConsentGivenBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultConsentGivenBinding by viewBinding() private lateinit var uploadDialog: SubmissionBlockingDialog diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultKeysSharedFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultKeysSharedFragment.kt index 92262272405a28a53c896286a3ad11a8c7c5f572..5276dbefe9261fdc5ed13289d35fa8410325df27 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultKeysSharedFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultKeysSharedFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -39,7 +39,7 @@ class SubmissionTestResultKeysSharedFragment : } ) - private val binding: FragmentSubmissionTestResultPositiveKeysSharedBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultPositiveKeysSharedBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentFragment.kt index 8e02c19bbb45f3c5d5f0904305424223699f2a40..4b01ad51f9b4ae8edae512d9a33995868cd95228 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/testresult/positive/SubmissionTestResultNoConsentFragment.kt @@ -14,7 +14,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -29,7 +29,7 @@ class SubmissionTestResultNoConsentFragment : @Inject lateinit var appShortcutsHelper: AppShortcutsHelper @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val binding: FragmentSubmissionTestResultPositiveNoConsentBinding by viewBindingLazy() + private val binding: FragmentSubmissionTestResultPositiveNoConsentBinding by viewBinding() private val viewModel: SubmissionTestResultNoConsentViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, constructorCall = { factory, _ -> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt index 7a4c5ce4b935e261eac2d14c461a7a738174dcea..ece7bce10c8df2502f50f62a5c5022265735413c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentFragment.kt @@ -15,7 +15,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.shortcuts.AppShortcutsHelper import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -39,7 +39,7 @@ class SubmissionResultPositiveOtherWarningNoConsentFragment : } ) - private val binding: FragmentSubmissionNoConsentPositiveOtherWarningBinding by viewBindingLazy() + private val binding: FragmentSubmissionNoConsentPositiveOtherWarningBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt index 6c0ba694a688232986ddc22069c15cdcd906d58f..66db5c93e568d58aec55b7caefd6959739092a0d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/yourconsent/SubmissionYourConsentFragment.kt @@ -12,7 +12,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import javax.inject.Inject @@ -32,7 +32,7 @@ class SubmissionYourConsentFragment : Fragment(R.layout.fragment_submission_your factory.create(navArgs.testType) } ) - private val binding: FragmentSubmissionYourConsentBinding by viewBindingLazy() + private val binding: FragmentSubmissionYourConsentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt index 0294876c153022b1f8065d42abd4c84f9edfdbdd..2dd7bb977224e27df6c25d50ba67eb73d1317373 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/TestResultSectionView.kt @@ -10,13 +10,13 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.withStyledAttributes import de.rki.coronawarnapp.R import de.rki.coronawarnapp.coronatest.type.CoronaTest +import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest import de.rki.coronawarnapp.databinding.ViewTestResultSectionBinding import de.rki.coronawarnapp.submission.toDeviceUIState import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUIFormat import de.rki.coronawarnapp.util.formatter.formatTestResult -import org.joda.time.Instant /** * The [TestResultSectionView] Displays the appropriate test result. @@ -58,7 +58,7 @@ constructor( .format(context.getString(R.string.submission_test_result_antigen_title)) } - testResultSectionRegisteredAtText.text = formatTestResultRegisteredAtText(coronaTest?.registeredAt) + testResultSectionRegisteredAtText.text = formatTestResultTimestampText(coronaTest) val testResultIcon = formatTestStatusIcon(coronaTest) testResultSectionStatusIcon.setImageDrawable(testResultIcon) testResultSectionContent.text = formatTestResultSectionContent(coronaTest) @@ -77,9 +77,18 @@ constructor( return context.getDrawableCompat(drawable) } - private fun formatTestResultRegisteredAtText(registeredAt: Instant?): String { - return context.getString(R.string.test_result_card_registered_at_text) - .format(registeredAt?.toDate()?.toUIFormat(context)) + private fun formatTestResultTimestampText(coronaTest: CoronaTest?): String { + return if (coronaTest is RACoronaTest) { + context.getString( + R.string.ag_homescreen_card_rapid_body_result_date, + coronaTest.testedAt.toDate()?.toUIFormat(context) + ) + } else { + context.getString( + R.string.test_result_card_registered_at_text, + coronaTest?.registeredAt?.toDate()?.toUIFormat(context) + ) + } } private fun formatTestResultSectionContent(coronaTest: CoronaTest?): Spannable { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt index 55b3107f616ba28a906790bd20e8feef339c4096..df7f430bbe48c42f64406e73b64ed417d2750c51 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt @@ -25,6 +25,7 @@ import de.rki.coronawarnapp.storage.TracingSettings import de.rki.coronawarnapp.submission.SubmissionRepository import de.rki.coronawarnapp.submission.SubmissionSettings import de.rki.coronawarnapp.ui.presencetracing.TraceLocationPreferences +import de.rki.coronawarnapp.vaccination.core.repository.ValueSetsRepository import de.rki.coronawarnapp.vaccination.core.VaccinationPreferences import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository import kotlinx.coroutines.sync.Mutex @@ -63,6 +64,7 @@ class DataReset @Inject constructor( private val traceWarningRepository: TraceWarningRepository, private val coronaTestRepository: CoronaTestRepository, private val ratProfileSettings: RATProfileSettings, + private val valueSetsRepository: ValueSetsRepository, private val vaccinationPreferences: VaccinationPreferences, private val vaccinationRepository: VaccinationRepository, ) { @@ -88,7 +90,6 @@ class DataReset @Inject constructor( riskLevelStorage.clear() contactDiaryPreferences.clear() traceLocationPreferences.clear() - cwaSettings.clear() surveySettings.clear() analyticsSettings.clear() @@ -110,6 +111,7 @@ class DataReset @Inject constructor( coronaTestRepository.clear() ratProfileSettings.deleteProfile() + valueSetsRepository.clear() vaccinationRepository.clear() vaccinationPreferences.clear() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt index 7392f5fe704fc4f757beaf782be685aef59b4293..52a1bd6ddbca830f8934326ea6c7e24763ec838a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt @@ -24,6 +24,7 @@ object TimeAndDateExtensions { private const val MS_TO_SECONDS = 1000 private val dayFormatter = DateTimeFormat.forPattern("dd.MM.yyyy") + private val dayFormatter2DigitYear = DateTimeFormat.forPattern("dd.MM.yy") fun getCurrentHourUTC(): Int = DateTime(Instant.now(), DateTimeZone.UTC).hourOfDay().get() @@ -117,6 +118,16 @@ object TimeAndDateExtensions { * Returns a readable date String with the format "dd.MM.yyyy" like 23.05.1989 of a LocalDate */ fun LocalDate.toDayFormat() = toString(dayFormatter) + + /** + * Returns a readable date String with the format "dd.MM.yy" like 23.05.89 of an Instant + */ + fun Instant.toShortDayFormat() = toString(dayFormatter2DigitYear) + + /** + * Returns a readable date String with the format "dd.MM.yy" like 23.05.89 of an LocalDate + */ + fun LocalDate.toShortDayFormat() = toString(dayFormatter2DigitYear) } typealias HourInterval = Long diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeConsumer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeConsumer.kt deleted file mode 100644 index 986be05ffb425c4993817464ef4cc01fdbff1193..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeConsumer.kt +++ /dev/null @@ -1,49 +0,0 @@ -package de.rki.coronawarnapp.util.list - -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.RecyclerView -import de.rki.coronawarnapp.util.lists.HasStableId -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract - -/** - * [RecyclerView] item data model should implement this contract to consume the swipe gestures - */ -interface SwipeConsumer { - /** - * On swipe callback - * @param position [Int] item position - * @param direction [Int] from [ItemTouchHelper] such as [ItemTouchHelper.RIGHT] - */ - fun onSwipe(position: Int, direction: Int) -} - -/** - * returns true if the item is as [SwipeConsumer] , false otherwise - * and helps with smart cast - */ - -@OptIn(ExperimentalContracts::class) -fun HasStableId?.isSwipeable(): Boolean { - contract { - returns(true) implies (this@isSwipeable is SwipeConsumer) - } - return this != null && this is SwipeConsumer -} - -/** - * Indicates whether [RecyclerView.ViewHolder]'s can be moved (Dragged, Swiped) or not - * by default movementFlags = ACTION_STATE_IDLE which indicates that the view does not move - * this behaviour can be overridden and provide any flag from [ItemTouchHelper] - */ -interface Movable { - val movementFlags: Int get() = ItemTouchHelper.ACTION_STATE_IDLE -} - -@OptIn(ExperimentalContracts::class) -fun RecyclerView.ViewHolder?.isMovable(): Boolean { - contract { - returns(true) implies (this@isMovable is Movable) - } - return this != null && this is Movable -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeExtension.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeExtension.kt index ed2b66642401ff3d7557d79c7a47b661e176e012..0201f5f6c70d29320e18b22ef31673779616442a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeExtension.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/SwipeExtension.kt @@ -18,20 +18,15 @@ import kotlin.math.min /** * On [RecyclerView] item swipe listener * @param context [Context] - * @param onSwipe on swipe callback. It passes item's position and swipe direction + * @param onSwipe if you want to override the swipe callback globally * - * Usage: - * ``` - * RecyclerView.onSwipeItem( - * context = requireContext() - * ) { position, direction -> - * // Do operation here - * } - * ``` + * After calling this on a recyclerview, every ViewHolder that implements [Swipeable] is swipeable. */ -fun RecyclerView.onSwipeItem( +fun RecyclerView.setupSwipe( context: Context, - onSwipe: (position: Int, direction: Int) -> Unit + onSwipe: (holder: RecyclerView.ViewHolder, direction: Int) -> Unit = { holder, direction -> + (holder as? Swipeable)?.let { holder.onSwipe(holder, direction) } + } ) { ItemTouchHelper( SwipeCallback( @@ -46,11 +41,10 @@ fun RecyclerView.onSwipeItem( */ private class SwipeCallback( context: Context, - private val action: (position: Int, direction: Int) -> Unit -) : ItemTouchHelper.SimpleCallback( - 0, - ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT -) { + private val action: (holder: RecyclerView.ViewHolder, direction: Int) -> Unit, + private val dragDirs: Int = 0, + private val swipeDirs: Int = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT, +) : ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs) { private val icon = context.getDrawableCompat(R.drawable.ic_delete)!! private val iconMargin = context.resources.getDimensionPixelSize(R.dimen.swipe_icon_margin) private val radius = context.resources.getDimensionPixelSize(R.dimen.radius_card).toFloat() @@ -69,7 +63,7 @@ private class SwipeCallback( ): Boolean = false override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - action(viewHolder.adapterPosition, direction) + action(viewHolder, direction) } override fun onChildDraw( @@ -102,9 +96,12 @@ private class SwipeCallback( } } - override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { - if (viewHolder.isMovable()) return viewHolder.movementFlags - return super.getMovementFlags(recyclerView, viewHolder) + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int = when (viewHolder) { + is Swipeable -> viewHolder.movementFlags ?: ItemTouchHelper.Callback.makeMovementFlags(dragDirs, swipeDirs) + else -> ItemTouchHelper.ACTION_STATE_IDLE } private fun onSwipeLeft( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/Swipeable.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/Swipeable.kt new file mode 100644 index 0000000000000000000000000000000000000000..2b9e42c8bc780f40bc28719cc0740638519c8553 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/list/Swipeable.kt @@ -0,0 +1,23 @@ +package de.rki.coronawarnapp.util.list + +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView + +/** + * [RecyclerView] item data model should implement this contract to consume the swipe gestures + */ +interface Swipeable { + /** + * Indicates whether [RecyclerView.ViewHolder]'s can be moved (Dragged, Swiped) or not + * by default movementFlags = ACTION_STATE_IDLE which indicates that the view does not move + * this behaviour can be overridden and provide any flag from [ItemTouchHelper] + */ + val movementFlags: Int? get() = null + + /** + * On swipe callback + * @param holder [RecyclerView.ViewHolder] that was swiped + * @param direction [Int] from [ItemTouchHelper] such as [ItemTouchHelper.RIGHT] + */ + fun onSwipe(holder: RecyclerView.ViewHolder, direction: Int) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt index 39453c07dd7c7d107d9ff63a03b041e0be721add..21b663e70d2ee6a4e9859658b1ae959827b7eb0d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt @@ -13,8 +13,8 @@ import timber.log.Timber import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty -inline fun <FragmentT : Fragment, reified BindingT : ViewBinding> FragmentT.viewBindingLazy() = - this.viewBindingLazy( +inline fun <reified BindingT : ViewBinding> Fragment.viewBinding() = + viewBinding( bindingProvider = { val bindingMethod = BindingT::class.java.getMethod("bind", View::class.java) val binding = bindingMethod(null, requireView()) as BindingT @@ -27,9 +27,9 @@ inline fun <FragmentT : Fragment, reified BindingT : ViewBinding> FragmentT.view ) @Suppress("unused") -fun <FragmentT : Fragment, BindingT : ViewBinding> FragmentT.viewBindingLazy( - bindingProvider: FragmentT.() -> BindingT, - lifecycleOwnerProvider: FragmentT.() -> LifecycleOwner +fun <BindingT : ViewBinding> Fragment.viewBinding( + bindingProvider: Fragment.() -> BindingT, + lifecycleOwnerProvider: Fragment.() -> LifecycleOwner ) = ViewBindingProperty(bindingProvider, lifecycleOwnerProvider) class ViewBindingProperty<ComponentT : LifecycleOwner, BindingT : ViewBinding>( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt index 51a1a760d12aad054e4cba319d86ac00a60dc835..9b0a15fd8dd03a5b47cab7299e3932a5b2930406 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPerson.kt @@ -37,6 +37,11 @@ data class VaccinatedPerson( val dateOfBirth: LocalDate get() = vaccinationCertificates.first().dateOfBirth + val getMostRecentVaccinationCertificate: VaccinationCertificate + get() = vaccinationCertificates.maxByOrNull { it.vaccinatedAt } ?: throw IllegalStateException( + "Every Vaccinated Person needs to have at least one vaccinationCertificate" + ) + fun getVaccinationStatus(nowUTC: Instant = Instant.now()): Status { val newestFullDose = vaccinationCertificates .filter { it.doseNumber == it.totalSeriesOfDoses } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt index 0663df8d042146b08b0fbf14a14ed1c9d9d69da0..aea20ab9b2e412ec1f7862b0bb8f12f8d1c710e3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifier.kt @@ -1,11 +1,12 @@ package de.rki.coronawarnapp.vaccination.core import de.rki.coronawarnapp.util.HashExtensions.toSHA256 +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode -import de.rki.coronawarnapp.vaccination.core.repository.errors.VaccinationDateOfBirthMissmatchException -import de.rki.coronawarnapp.vaccination.core.repository.errors.VaccinationNameMissmatchException import org.joda.time.LocalDate +import timber.log.Timber data class VaccinatedPersonIdentifier( val dateOfBirth: LocalDate, @@ -33,19 +34,16 @@ data class VaccinatedPersonIdentifier( fun requireMatch(other: VaccinatedPersonIdentifier) { if (lastNameStandardized != other.lastNameStandardized) { - throw VaccinationNameMissmatchException( - "Family name does not match, got ${other.lastNameStandardized}, expected $lastNameStandardized" - ) + Timber.d("Family name does not match, got ${other.lastNameStandardized}, expected $lastNameStandardized") + throw InvalidHealthCertificateException(ErrorCode.VC_NAME_MISMATCH) } if (firstNameStandardized != other.firstNameStandardized) { - throw VaccinationNameMissmatchException( - "Given name does not match, got ${other.firstNameStandardized}, expected $firstNameStandardized" - ) + Timber.d("Given name does not match, got ${other.firstNameStandardized}, expected $firstNameStandardized") + throw InvalidHealthCertificateException(ErrorCode.VC_NAME_MISMATCH) } if (dateOfBirth != other.dateOfBirth) { - throw VaccinationDateOfBirthMissmatchException( - "Date of birth does not match, got ${other.dateOfBirth}, expected $dateOfBirth" - ) + Timber.d("Date of birth does not match, got ${other.dateOfBirth}, expected $dateOfBirth") + throw InvalidHealthCertificateException(ErrorCode.VC_DOB_MISMATCH) } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt index 98c5018ec7464e0c8301d8cbc1f3287bba641d5e..c0110eb0b0cedcb3ffeb61287ea42431a4db197b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/VaccinationCertificate.kt @@ -1,6 +1,5 @@ package de.rki.coronawarnapp.vaccination.core -import de.rki.coronawarnapp.ui.Country import de.rki.coronawarnapp.vaccination.core.qrcode.QrCodeString import org.joda.time.Instant import org.joda.time.LocalDate @@ -20,7 +19,7 @@ interface VaccinationCertificate { val totalSeriesOfDoses: Int val certificateIssuer: String - val certificateCountry: Country + val certificateCountry: String val certificateId: String val personIdentifier: VaccinatedPersonIdentifier diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt index b4ab3e75377eb1e08946d52e27f01f3175155e9e..ae3065df399be47ee02e1d6fe5650ad3ea51b2a0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.vaccination.core.qrcode +import de.rki.coronawarnapp.bugreporting.censors.vaccination.CertificateQrCodeCensor import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor import de.rki.coronawarnapp.util.compression.inflate import de.rki.coronawarnapp.util.encoding.Base45Decoder @@ -22,6 +23,8 @@ class VaccinationQRCodeExtractor @Inject constructor( override fun canHandle(rawString: String): Boolean = rawString.startsWith(PREFIX) override fun extract(rawString: String): VaccinationCertificateQRCode { + CertificateQrCodeCensor.addQRCodeStringToCensor(rawString) + val parsedData = rawString .removePrefix(PREFIX) .decodeBase45() @@ -56,6 +59,8 @@ class VaccinationQRCodeExtractor @Inject constructor( header = headerParser.parse(cbor), certificate = bodyParser.parse(cbor) ).also { + CertificateQrCodeCensor.addCertificateToCensor(it) + }.also { Timber.v("Parsed vaccination certificate for %s", it.certificate.nameData.familyNameStandardized) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt index 84f1a745a2b2afbdb95d8396999e784f5bee4113..3e7f603962d7306ea8bde1da607008559c94c7c1 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeValidator.kt @@ -14,9 +14,11 @@ class VaccinationQRCodeValidator @Inject constructor( private val extractors = setOf(vaccinationQRCodeExtractor) fun validate(rawString: String): VaccinationCertificateQRCode { + // If there is more than one "extractor" in the future, check censoring again. + // CertificateQrCodeCensor.addQRCodeStringToCensor(rawString) return findExtractor(rawString) ?.extract(rawString) - ?.also { Timber.i("Extracted data from QR code is $it") } + ?.also { Timber.i("Extracted data from QR code is %s", it) } ?: throw InvalidHealthCertificateException(VC_PREFIX_INVALID) } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt index 1621f9eea96f84d4e1af2dcda9450efd73ab6fcc..ab3b35f4dfc2e3c48e4f5c94e586fcf66f7e6c6e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepository.kt @@ -9,6 +9,8 @@ import de.rki.coronawarnapp.util.flow.combine import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode import de.rki.coronawarnapp.vaccination.core.personIdentifier import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor @@ -24,7 +26,6 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.launch import kotlinx.coroutines.plus import timber.log.Timber import javax.inject.Inject @@ -93,13 +94,16 @@ class VaccinationRepository @Inject constructor( } } else { VaccinatedPerson( - data = VaccinatedPersonData( - vaccinations = emptySet() - ), + data = VaccinatedPersonData(), valueSet = null, ) } + if (originalPerson.data.vaccinations.any { it.certificateId == qrCode.uniqueCertificateIdentifier }) { + Timber.tag(TAG).e("Certificate is already registered: %s", qrCode.uniqueCertificateIdentifier) + throw InvalidHealthCertificateException(ErrorCode.VC_ALREADY_REGISTERED) + } + val newCertificate = qrCode.toVaccinationContainer( scannedAt = timeStamper.nowUTC, qrCodeExtractor = vaccinationQRCodeExtractor, @@ -154,25 +158,25 @@ class VaccinationRepository @Inject constructor( ) deletedVaccination = target.data.vaccinations.single { - it.certificateId != vaccinationCertificateId + it.certificateId == vaccinationCertificateId } - val newTarget = target.copy( - data = target.data.copy( - vaccinations = target.data.vaccinations.filter { - it.certificateId != vaccinationCertificateId - }.toSet() + val newTarget = if (target.data.vaccinations.size > 1) { + target.copy( + data = target.data.copy( + vaccinations = target.data.vaccinations.filter { it != deletedVaccination }.toSet() + ) ) - ) + } else { + Timber.tag(TAG).w("Person has no certificate after removal, removing person.") + null + } - this.map { - if (it != target) newTarget else it - }.toSet() + this.mapNotNull { if (it == target) newTarget else it }.toSet() } deletedVaccination?.let { - Timber.tag(TAG).i("Deleted vaccination was eligble for proof, refreshing: %s", deletedVaccination) - appScope.launch { refresh(it.personIdentifier) } + Timber.tag(TAG).i("Deleted vaccination certificate: %s", it.certificateId) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt index e3497c090778dcdf8079163b72f2bd4082338107..27de6bffab3d6d14dd588f322d370025b3efdb51 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepository.kt @@ -1,17 +1,73 @@ package de.rki.coronawarnapp.vaccination.core.repository -import de.rki.coronawarnapp.submission.server.SubmissionServer +import androidx.annotation.VisibleForTesting +import dagger.Reusable +import de.rki.coronawarnapp.util.coroutine.AppScope +import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage +import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationServer import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet - +import de.rki.coronawarnapp.vaccination.core.server.valueset.isEmpty +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch +import timber.log.Timber +import java.util.Locale import javax.inject.Inject -import javax.inject.Singleton -@Singleton +@Reusable class ValueSetsRepository @Inject constructor( - private val submissionServer: SubmissionServer + private val vaccinationServer: VaccinationServer, + private val valueSetsStorage: ValueSetsStorage, + @AppScope private val scope: CoroutineScope ) { - val latestValueSet: Flow<VaccinationValueSet?> = flowOf(null) + val latestValueSet: Flow<VaccinationValueSet> = valueSetsStorage.valueSet.flow.distinctUntilChanged() + + fun triggerUpdateValueSet(languageCode: Locale) = scope.launch { + Timber.d("triggerUpdateValueSet(languageCode=%s)", languageCode) + var valueSet = vaccinationServer.getVaccinationValueSets(languageCode = languageCode) + + if (valueSet == null && valueSetsStorage.valueSet.value.isEmpty()) { + Timber.d( + "Got no value set from server for %s and local value set is empty... " + + "Try fallback to value set for en", + languageCode.language + ) + valueSet = vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) + } + + valueSet + .also { Timber.d("Value set is %s", it) } + ?.let { newValueSet -> valueSetsStorage.valueSet.update { newValueSet.toStoredVaccinationValueSet() } } + } + + fun clear() { + Timber.d("Clearing value sets") + vaccinationServer.clear() + valueSetsStorage.clear() + } } + +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +fun VaccinationValueSet.toStoredVaccinationValueSet(): ValueSetsStorage.StoredVaccinationValueSet = + ValueSetsStorage.StoredVaccinationValueSet( + languageCode = languageCode, + vp = vp.toStoredValueSet(), + mp = mp.toStoredValueSet(), + ma = ma.toStoredValueSet() + ) + +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +fun VaccinationValueSet.ValueSet.toStoredValueSet(): ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet = + ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet( + items = items.map { it.toStoredItem() } + ) + +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +fun VaccinationValueSet.ValueSet.Item.toStoredItem(): + ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem = + ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem( + key = key, + displayText = displayText + ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationDateOfBirthMissmatchException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationDateOfBirthMissmatchException.kt deleted file mode 100644 index bedc695d22726250f93bcb4273b84dc17fc21430..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationDateOfBirthMissmatchException.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.rki.coronawarnapp.vaccination.core.repository.errors - -import de.rki.coronawarnapp.vaccination.core.VaccinationException - -class VaccinationDateOfBirthMissmatchException( - message: String -) : VaccinationException( - message = message, - cause = null -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationNameMissmatchException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationNameMissmatchException.kt deleted file mode 100644 index 3e27e652d6519f83fa9473c2a0e064c4b77e1411..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/errors/VaccinationNameMissmatchException.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.rki.coronawarnapp.vaccination.core.repository.errors - -import de.rki.coronawarnapp.vaccination.core.VaccinationException - -class VaccinationNameMissmatchException( - message: String -) : VaccinationException( - message = message, - cause = null -) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt index d5fea3bef653c4aef0e5b1670869a0fcd2ad50c3..06978d4907f11613336a3c1e85929a4228fa8021 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinatedPersonData.kt @@ -4,7 +4,7 @@ import com.google.gson.annotations.SerializedName import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier data class VaccinatedPersonData( - @SerializedName("vaccinationData") val vaccinations: Set<VaccinationContainer> + @SerializedName("vaccinationData") val vaccinations: Set<VaccinationContainer> = emptySet() ) { val identifier: VaccinatedPersonIdentifier get() = vaccinations.first().personIdentifier diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt index 76ca4e4b5c2840800c9f0c0c19be965abad73ba9..b76916194b49ab4bcb1090bedb3cea556db50694 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainer.kt @@ -2,7 +2,6 @@ package de.rki.coronawarnapp.vaccination.core.repository.storage import androidx.annotation.Keep import com.google.gson.annotations.SerializedName -import de.rki.coronawarnapp.ui.Country import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate import de.rki.coronawarnapp.vaccination.core.certificate.CoseCertificateHeader @@ -13,8 +12,10 @@ import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import de.rki.coronawarnapp.vaccination.core.server.valueset.getDisplayText import org.joda.time.Instant import org.joda.time.LocalDate +import java.util.Locale @Keep data class VaccinationContainer internal constructor( @@ -31,7 +32,7 @@ data class VaccinationContainer internal constructor( constructor() : this("", Instant.EPOCH) @delegate:Transient - private val certificateData: VaccinationCertificateData by lazy { + internal val certificateData: VaccinationCertificateData by lazy { preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode).parsedData } @@ -80,8 +81,11 @@ data class VaccinationContainer internal constructor( override val certificateIssuer: String get() = vaccination.certificateIssuer - override val certificateCountry: Country - get() = Country.values().singleOrNull { it.code == vaccination.countryOfVaccination } ?: Country.DE + override val certificateCountry: String + get() = Locale( + Locale.getDefault().language, + vaccination.countryOfVaccination.uppercase() + ).displayCountry override val certificateId: String get() = vaccination.uniqueCertificateIdentifier diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt index ee8d04c714deaf19c73b3d36dde07c43b3c7bd92..1424b943171378f04cc41ee44a398e0705afc95f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorage.kt @@ -36,9 +36,9 @@ class VaccinationStorage @Inject constructor( return@mapNotNull null } value as String - gson.fromJson<VaccinatedPersonData>(value).also { - Timber.tag(TAG).v("Person loaded: %s", it) - requireNotNull(it.identifier) + gson.fromJson<VaccinatedPersonData>(value).also { personData -> + Timber.tag(TAG).v("Person loaded: %s", personData) + requireNotNull(personData.identifier) } } return persons.toSet() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt new file mode 100644 index 0000000000000000000000000000000000000000..bb81b8a8261a55e8bfa6cdcba1ed2f20ecb86064 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorage.kt @@ -0,0 +1,70 @@ +package de.rki.coronawarnapp.vaccination.core.repository.storage + +import android.content.Context +import android.content.SharedPreferences +import androidx.annotation.Keep +import com.google.gson.Gson +import com.google.gson.annotations.SerializedName +import dagger.Reusable +import de.rki.coronawarnapp.util.di.AppContext +import de.rki.coronawarnapp.util.preferences.FlowPreference +import de.rki.coronawarnapp.util.preferences.clearAndNotify +import de.rki.coronawarnapp.util.preferences.createFlowPreference +import de.rki.coronawarnapp.util.serialization.BaseGson +import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import timber.log.Timber +import java.util.Locale +import javax.inject.Inject + +@Reusable +class ValueSetsStorage @Inject constructor( + @AppContext private val context: Context, + @BaseGson private val gson: Gson +) { + + private val prefs: SharedPreferences by lazy { + context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + } + + var valueSet: FlowPreference<StoredVaccinationValueSet> = prefs.createFlowPreference( + key = PKEY_VALUE_SETS_PREFIX, + reader = FlowPreference.gsonReader(gson = gson, createEmptyValueSet()), + writer = FlowPreference.gsonWriter(gson = gson) + ) + + fun clear() { + Timber.d("Clearing local storage") + prefs.clearAndNotify() + } + + private fun createEmptyValueSet() = StoredVaccinationValueSet( + languageCode = Locale.ENGLISH, + vp = StoredVaccinationValueSet.StoredValueSet(items = emptyList()), + mp = StoredVaccinationValueSet.StoredValueSet(items = emptyList()), + ma = StoredVaccinationValueSet.StoredValueSet(items = emptyList()) + ) + + @Keep + data class StoredVaccinationValueSet( + @SerializedName("languageCode") override val languageCode: Locale, + @SerializedName("vp") override val vp: StoredValueSet, + @SerializedName("mp") override val mp: StoredValueSet, + @SerializedName("ma") override val ma: StoredValueSet + ) : VaccinationValueSet { + + @Keep + data class StoredValueSet( + @SerializedName("items") override val items: List<StoredItem> + ) : VaccinationValueSet.ValueSet { + + @Keep + data class StoredItem( + @SerializedName("key") override val key: String, + @SerializedName("displayText") override val displayText: String + ) : VaccinationValueSet.ValueSet.Item + } + } +} + +private const val PREF_NAME = "valuesets_localdata" +private const val PKEY_VALUE_SETS_PREFIX = "valueset" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt new file mode 100644 index 0000000000000000000000000000000000000000..1962cf330dbe26a192497bc4eeaeeb0e052b00d9 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/DefaultVaccinationValueSet.kt @@ -0,0 +1,21 @@ +package de.rki.coronawarnapp.vaccination.core.server.valueset + +import java.util.Locale + +data class DefaultVaccinationValueSet( + override val languageCode: Locale, + override val vp: VaccinationValueSet.ValueSet, + override val mp: VaccinationValueSet.ValueSet, + override val ma: VaccinationValueSet.ValueSet +) : VaccinationValueSet { + + data class DefaultValueSet( + override val items: List<VaccinationValueSet.ValueSet.Item> + ) : VaccinationValueSet.ValueSet { + + data class DefaultItem( + override val key: String, + override val displayText: String + ) : VaccinationValueSet.ValueSet.Item + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt index cb64715a67d263d703c095a9e64ad11c925e006c..5e064692b159c9123f431138dbbc4520a33228f3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServer.kt @@ -1,8 +1,22 @@ package de.rki.coronawarnapp.vaccination.core.server.valueset +import androidx.annotation.VisibleForTesting +import dagger.Lazy import dagger.Reusable +import de.rki.coronawarnapp.server.protocols.internal.dgc.ValueSetsOuterClass +import de.rki.coronawarnapp.util.ZipHelper.readIntoMap +import de.rki.coronawarnapp.util.ZipHelper.unzip +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.security.SignatureValidation +import de.rki.coronawarnapp.vaccination.core.server.valueset.internal.ValueSetInvalidSignatureException +import de.rki.coronawarnapp.vaccination.core.server.valueset.internal.toVaccinationValueSet +import kotlinx.coroutines.withContext import okhttp3.Cache +import okhttp3.ResponseBody +import retrofit2.HttpException +import retrofit2.Response import timber.log.Timber +import java.io.InputStream import java.util.Locale import javax.inject.Inject @@ -11,11 +25,56 @@ import javax.inject.Inject */ @Reusable class VaccinationServer @Inject constructor( - @VaccinationValueSetHttpClient private val cache: Cache + @ValueSet private val cache: Cache, + private val apiV1: Lazy<VaccinationValueSetApiV1>, + private val dispatcherProvider: DispatcherProvider, + private val signatureValidation: SignatureValidation ) { - suspend fun getVaccinationValueSets(languageCode: Locale): VaccinationValueSet { - throw NotImplementedError() + suspend fun getVaccinationValueSets(languageCode: Locale): VaccinationValueSet? = + withContext(dispatcherProvider.Default) { + return@withContext try { + val response = requestValueSets(languageCode.language) + if (!response.isSuccessful) throw HttpException(response) + + val body = requireNotNull(response.body()) { "Body of response was null" } + val valueSetsProtobuf = body.parseBody() + valueSetsProtobuf.toVaccinationValueSet(languageCode = languageCode) + } catch (e: Exception) { + Timber.e(e, "Getting vaccination value sets from server failed cause: ${e.message}") + null + } + } + + private suspend fun requestValueSets(languageCode: String): Response<ResponseBody> = + withContext(dispatcherProvider.IO) { + Timber.d("Requesting value sets for language $languageCode from server") + apiV1.get().getValueSets(languageCode = languageCode) + } + + private fun ResponseBody.parseBody(): ValueSetsOuterClass.ValueSets = + parseBody(byteStream()) + + @VisibleForTesting + internal fun parseBody(inputStream: InputStream): ValueSetsOuterClass.ValueSets { + val fileMap = inputStream.unzip().readIntoMap() + + val exportBinary = fileMap[EXPORT_BINARY_FILE_NAME] + val exportSignature = fileMap[EXPORT_SIGNATURE_FILE_NAME] + + if (exportBinary == null || exportSignature == null) + throw ValueSetInvalidSignatureException(msg = "Unknown files ${fileMap.entries}") + + val hasValidSignature = signatureValidation.hasValidSignature( + toVerify = exportBinary, + signatureList = SignatureValidation.parseTEKStyleSignature(exportSignature) + ) + + if (!hasValidSignature) { + throw ValueSetInvalidSignatureException(msg = "Signature of value sets did not match") + } + + return ValueSetsOuterClass.ValueSets.parseFrom(exportBinary) } fun clear() { @@ -24,3 +83,6 @@ class VaccinationServer @Inject constructor( cache.evictAll() } } + +private const val EXPORT_BINARY_FILE_NAME = "export.bin" +private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt index 6bace45c474e8760501732e684653ab8c7360ea8..08618fc008c487cd471b334a15fe6df1d039a348 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSet.kt @@ -4,6 +4,26 @@ import java.util.Locale interface VaccinationValueSet { val languageCode: Locale + val vp: ValueSet + val mp: ValueSet + val ma: ValueSet - fun getDisplayText(key: String): String? + interface ValueSet { + val items: List<Item> + + // Use custom item instead of map to allow for future extensions + interface Item { + val key: String + val displayText: String + } + } } + +fun VaccinationValueSet.getDisplayText(key: String): String? = + vp.getDisplayText(key) ?: mp.getDisplayText(key) ?: ma.getDisplayText(key) + +fun VaccinationValueSet.ValueSet.getDisplayText(key: String): String? = items.find { key == it.key }?.displayText + +fun VaccinationValueSet.isEmpty(): Boolean = vp.isEmpty() && mp.isEmpty() && ma.isEmpty() + +fun VaccinationValueSet.ValueSet.isEmpty(): Boolean = items.isEmpty() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt index 1a4d73746910ef349635ffe3e5e95f0c1a0f0807..2b3413d14169f086392e7ab3df76a867f2acb57a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetModule.kt @@ -4,48 +4,68 @@ import android.content.Context import dagger.Module import dagger.Provides import dagger.Reusable -import de.rki.coronawarnapp.environment.vaccination.VaccinationCertificateCDNUrl -import de.rki.coronawarnapp.http.HttpClientDefault +import de.rki.coronawarnapp.environment.download.DownloadCDNHttpClient +import de.rki.coronawarnapp.environment.download.DownloadCDNServerUrl import de.rki.coronawarnapp.util.di.AppContext import okhttp3.Cache +import okhttp3.CacheControl +import okhttp3.Interceptor import okhttp3.OkHttpClient +import okhttp3.Response import retrofit2.Retrofit import java.io.File +import java.util.concurrent.TimeUnit @Module class VaccinationValueSetModule { @Reusable - @VaccinationValueSetHttpClient + @ValueSet @Provides fun cache( @AppContext context: Context ): Cache { - val cacheDir = File(context.cacheDir, "vaccination_value") - val cacheFile = File(cacheDir, "http_cache") - return Cache(cacheFile, CACHE_SIZE_5MB) + val vaccDir = File(context.cacheDir, "vaccination") + val cacheDir = File(vaccDir, "valueset_httpcache") + return Cache(cacheDir, CACHE_SIZE_5MB) } - @Reusable - @VaccinationValueSetHttpClient - @Provides - fun httpClient( - @HttpClientDefault defaultHttpClient: OkHttpClient, - @VaccinationValueSetHttpClient cache: Cache - ): OkHttpClient = defaultHttpClient.newBuilder() - .cache(cache) - .build() - @Reusable @Provides fun api( - @VaccinationValueSetHttpClient httpClient: OkHttpClient, - @VaccinationCertificateCDNUrl url: String - ): VaccinationValueSetApiV1 = Retrofit.Builder() - .client(httpClient) - .baseUrl(url) - .build() - .create(VaccinationValueSetApiV1::class.java) + @DownloadCDNHttpClient httpClient: OkHttpClient, + @DownloadCDNServerUrl url: String, + @ValueSet cache: Cache + ): VaccinationValueSetApiV1 { + val client = httpClient.newBuilder() + .addNetworkInterceptor(CacheInterceptor()) + .cache(cache) + .build() + + return Retrofit.Builder() + .client(client) + .baseUrl(url) + .build() + .create(VaccinationValueSetApiV1::class.java) + } + + private class CacheInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val response = chain.proceed(chain.request()) + + val cacheControl = CacheControl.Builder() + .maxAge(300, TimeUnit.SECONDS) + .build() + + // We cache as we please + val cacheHeader = "Cache-Control" + return response.newBuilder() + .removeHeader("Pragma") + .removeHeader(cacheHeader) + .addHeader(cacheHeader, cacheControl.toString()) + .build() + } + } companion object { private const val CACHE_SIZE_5MB = 5 * 1024 * 1024L // 5MB diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetHttpClient.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/ValueSet.kt similarity index 77% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetHttpClient.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/ValueSet.kt index 1650bcb5f61039656a1cc3e51485dacf03e5317b..1300c045c0d8f448781ddcaa327bb7f2959fe09f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationValueSetHttpClient.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/ValueSet.kt @@ -5,4 +5,4 @@ import javax.inject.Qualifier @Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) -annotation class VaccinationValueSetHttpClient +annotation class ValueSet diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/VaccinationValueSetMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/VaccinationValueSetMapper.kt new file mode 100644 index 0000000000000000000000000000000000000000..ad13f40aace7a84a4d73ac99b0d5b836fa8a2185 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/VaccinationValueSetMapper.kt @@ -0,0 +1,28 @@ +package de.rki.coronawarnapp.vaccination.core.server.valueset.internal + +import de.rki.coronawarnapp.server.protocols.internal.dgc.ValueSetsOuterClass +import de.rki.coronawarnapp.vaccination.core.server.valueset.DefaultVaccinationValueSet +import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import timber.log.Timber +import java.util.Locale + +internal fun ValueSetsOuterClass.ValueSets.toVaccinationValueSet(languageCode: Locale): VaccinationValueSet { + Timber.d("toVaccinationValueSet(valueSets=%s, languageCode=%s)", this, languageCode) + return DefaultVaccinationValueSet( + languageCode = languageCode, + vp = vp.toValueSet(), + mp = mp.toValueSet(), + ma = ma.toValueSet() + ).also { Timber.tag(TAG).d("Created %s", it) } +} + +internal fun ValueSetsOuterClass.ValueSet.toValueSet(): VaccinationValueSet.ValueSet = + DefaultVaccinationValueSet.DefaultValueSet(items = itemsList.map { it.toItem() }) + +internal fun ValueSetsOuterClass.ValueSetItem.toItem(): VaccinationValueSet.ValueSet.Item = + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = key, + displayText = displayText + ) + +private const val TAG: String = "ValueSetMapper" diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/ValueSetInvalidSignatureException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/ValueSetInvalidSignatureException.kt new file mode 100644 index 0000000000000000000000000000000000000000..6de24adafb228da191c3f7d076ef1729b8ad3540 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/server/valueset/internal/ValueSetInvalidSignatureException.kt @@ -0,0 +1,9 @@ +package de.rki.coronawarnapp.vaccination.core.server.valueset.internal + +import de.rki.coronawarnapp.exception.reporting.ErrorCodes +import de.rki.coronawarnapp.util.security.InvalidSignatureException + +class ValueSetInvalidSignatureException(msg: String) : InvalidSignatureException( + code = ErrorCodes.APPLICATION_CONFIGURATION_INVALID.code, + message = msg +) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt index f19f6ed848a1f5e8af99f7b14f9f317fed5b9bb0..8d748c1ea091392fb40c6c762290a38c86e3c5bd 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/consent/VaccinationConsentFragment.kt @@ -6,11 +6,10 @@ import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.VaccinationConsentFragmentBinding import de.rki.coronawarnapp.util.di.AutoInject -import de.rki.coronawarnapp.util.setUrl import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.observe2 import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -20,16 +19,11 @@ class VaccinationConsentFragment : Fragment(R.layout.vaccination_consent_fragmen @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: VaccinationConsentViewModel by cwaViewModels { viewModelFactory } - private val binding: VaccinationConsentFragmentBinding by viewBindingLazy() + private val binding: VaccinationConsentFragmentBinding by viewBinding() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { with(binding) { toolbar.setNavigationOnClickListener { popBackStack() } - vaccinationConsentInfoSubtitle.setUrl( - R.string.vaccination_consent_info_subtitle_text, - R.string.vaccination_consent_info_subtitle_text_link_label, - R.string.vaccination_consent_faq_url // TODO: URL is not final - ) vaccinationConsentPrivacyInformation.setOnClickListener { viewModel.onDataPrivacyClick() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt index c944d7dde805f80855af63332095e61fedb3b9ad..b0dd687788c06031dd2e93bb8bb81e1a485a2ead 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/details/VaccinationDetailsFragment.kt @@ -17,7 +17,7 @@ import de.rki.coronawarnapp.ui.view.onOffsetChange import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate @@ -29,7 +29,7 @@ class VaccinationDetailsFragment : Fragment(R.layout.fragment_vaccination_detail @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val args by navArgs<VaccinationDetailsFragmentArgs>() - private val binding: FragmentVaccinationDetailsBinding by viewBindingLazy() + private val binding: FragmentVaccinationDetailsBinding by viewBinding() private val viewModel: VaccinationDetailsViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, constructorCall = { factory, _ -> @@ -59,11 +59,16 @@ class VaccinationDetailsFragment : Fragment(R.layout.fragment_vaccination_detail } setToolbarOverlay() - viewModel.errors.observe(viewLifecycleOwner) { it.toErrorDialogBuilder(requireContext()).show() } - viewModel.qrCode.observe(viewLifecycleOwner) { + viewModel.errors.observe(viewLifecycleOwner) { qrCodeCard.progressBar.hide() + it.toErrorDialogBuilder(requireContext()).show() + } + viewModel.qrCode.observe(viewLifecycleOwner) { qrCodeCard.image.setImageBitmap(it) - it?.let { qrCodeCard.image.setOnClickListener { viewModel.openFullScreen() } } + it?.let { + qrCodeCard.image.setOnClickListener { viewModel.openFullScreen() } + qrCodeCard.progressBar.hide() + } } viewModel.events.observe(viewLifecycleOwner) { event -> @@ -92,7 +97,7 @@ class VaccinationDetailsFragment : Fragment(R.layout.fragment_vaccination_detail vaccineManufacturer.text = certificate.vaccineManufacturer medicalProductName.text = certificate.medicalProductName certificateIssuer.text = certificate.certificateIssuer - certificateCountry.text = certificate.certificateCountry.getLabel(requireContext()) + certificateCountry.text = certificate.certificateCountry certificateId.text = certificate.certificateId title.text = getString( R.string.vaccination_details_title, @@ -101,12 +106,12 @@ class VaccinationDetailsFragment : Fragment(R.layout.fragment_vaccination_detail ) // QrCode details qrCodeCard.title.text = getString( - R.string.vaccination_qr_code_card_title, + R.string.vaccination_qrcode_card_title, certificate.doseNumber, certificate.totalSeriesOfDoses ) qrCodeCard.subtitle.text = getString( - R.string.vaccination_qr_code_card_subtitle, + R.string.vaccination_qrcode_card_subtitle, certificate.vaccinatedAt.toString(format), certificate.expiresAt.toString(format) ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/CompleteVaccinationHomeCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/ImmuneVaccinationHomeCard.kt similarity index 70% rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/CompleteVaccinationHomeCard.kt rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/ImmuneVaccinationHomeCard.kt index f64b6f3fdaac4f755b4df64958c486619b5b135f..c8da550d4c2f1aad55f97a94d79daf1b57c59029 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/CompleteVaccinationHomeCard.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/ImmuneVaccinationHomeCard.kt @@ -2,22 +2,22 @@ package de.rki.coronawarnapp.vaccination.ui.homecard import android.view.ViewGroup import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.VaccinationHomeCompleteCardBinding +import de.rki.coronawarnapp.databinding.VaccinationHomeImmuneCardBinding import de.rki.coronawarnapp.ui.main.home.HomeAdapter import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson -class CompleteVaccinationHomeCard(parent: ViewGroup) : - HomeAdapter.HomeItemVH<CompleteVaccinationHomeCard.Item, VaccinationHomeCompleteCardBinding>( +class ImmuneVaccinationHomeCard(parent: ViewGroup) : + HomeAdapter.HomeItemVH<ImmuneVaccinationHomeCard.Item, VaccinationHomeImmuneCardBinding>( R.layout.home_card_container_layout, parent ) { override val viewBinding = lazy { - VaccinationHomeCompleteCardBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true) + VaccinationHomeImmuneCardBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true) } - override val onBindData: VaccinationHomeCompleteCardBinding.( + override val onBindData: VaccinationHomeImmuneCardBinding.( item: Item, payloads: List<Any> ) -> Unit = { item, payloads -> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/IncompleteVaccinationHomeCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/IncompleteVaccinationHomeCard.kt deleted file mode 100644 index 915eb6d6802170e12083d67b394a2b7cf623e55d..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/IncompleteVaccinationHomeCard.kt +++ /dev/null @@ -1,38 +0,0 @@ -package de.rki.coronawarnapp.vaccination.ui.homecard - -import android.view.ViewGroup -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.VaccinationHomeIncompleteCardBinding -import de.rki.coronawarnapp.ui.main.home.HomeAdapter -import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer -import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson - -class IncompleteVaccinationHomeCard(parent: ViewGroup) : - HomeAdapter.HomeItemVH<IncompleteVaccinationHomeCard.Item, VaccinationHomeIncompleteCardBinding>( - R.layout.home_card_container_layout, - parent - ) { - - override val viewBinding = lazy { - VaccinationHomeIncompleteCardBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true) - } - - override val onBindData: VaccinationHomeIncompleteCardBinding.( - item: Item, - payloads: List<Any> - ) -> Unit = { item, payloads -> - val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item - - personName.text = curItem.vaccinatedPerson.fullName - - itemView.setOnClickListener { curItem.onClickAction(item) } - } - - data class Item( - override val vaccinatedPerson: VaccinatedPerson, - val onClickAction: (Item) -> Unit, - ) : VaccinationStatusItem, HasPayloadDiffer { - - override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/VaccinationHomeCard.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/VaccinationHomeCard.kt new file mode 100644 index 0000000000000000000000000000000000000000..659ff1786ddb927820fad67fc1d670fe14606296 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/homecard/VaccinationHomeCard.kt @@ -0,0 +1,52 @@ +package de.rki.coronawarnapp.vaccination.ui.homecard + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationHomeCardBinding +import de.rki.coronawarnapp.ui.main.home.HomeAdapter +import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson + +class VaccinationHomeCard(parent: ViewGroup) : + HomeAdapter.HomeItemVH<VaccinationHomeCard.Item, VaccinationHomeCardBinding>( + R.layout.home_card_container_layout, + parent + ) { + + override val viewBinding = lazy { + VaccinationHomeCardBinding.inflate(layoutInflater, itemView.findViewById(R.id.card_container), true) + } + + override val onBindData: VaccinationHomeCardBinding.( + item: Item, + payloads: List<Any> + ) -> Unit = { item, payloads -> + val curItem = payloads.filterIsInstance<Item>().singleOrNull() ?: item + + personName.text = curItem.vaccinatedPerson.fullName + when (curItem.vaccinatedPerson.getVaccinationStatus()) { + VaccinatedPerson.Status.COMPLETE -> { + val days = curItem.vaccinatedPerson.getTimeUntilImmunity()!!.standardDays.toInt() + vaccinationState.text = context.resources.getQuantityString( + R.plurals.vaccination_card_status_vaccination_complete, + days, + days + ) + icon.setImageResource(R.drawable.vaccination_card_icon_complete) + } + else -> { + vaccinationState.setText(R.string.vaccination_card_status_vaccination_incomplete) + icon.setImageResource(R.drawable.vaccination_card_icon_incomplete) + } + } + itemView.setOnClickListener { curItem.onClickAction(item) } + } + + data class Item( + override val vaccinatedPerson: VaccinatedPerson, + val onClickAction: (Item) -> Unit, + ) : VaccinationStatusItem, HasPayloadDiffer { + + override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt index 5e6de31fa480a5465e2da18339975e3cac22e2ec..9c3768891b87a83378c714760d5f9f1949dc9b9f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt @@ -3,25 +3,33 @@ package de.rki.coronawarnapp.vaccination.ui.list import android.os.Bundle import android.view.View import android.widget.LinearLayout -import android.widget.Toast import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.net.toUri -import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.navigation.fragment.FragmentNavigatorExtras +import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.imageview.ShapeableImageView import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder import de.rki.coronawarnapp.databinding.FragmentVaccinationListBinding +import de.rki.coronawarnapp.ui.qrcode.fullscreen.QrCodeFullScreenFragmentArgs import de.rki.coronawarnapp.ui.view.onOffsetChange import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.list.setupSwipe import de.rki.coronawarnapp.util.lists.diffutil.update import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.DeleteVaccinationEvent +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateBack import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationCertificateDetails +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationQrCodeScanScreen import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter import javax.inject.Inject @@ -30,7 +38,7 @@ class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), Au @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val args by navArgs<VaccinationListFragmentArgs>() - private val binding: FragmentVaccinationListBinding by viewBindingLazy() + private val binding: FragmentVaccinationListBinding by viewBinding() private val viewModel: VaccinationListViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, constructorCall = { factory, _ -> @@ -41,7 +49,7 @@ class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), Au } ) - private val adapter = VaccinationListAdapter() + private val vaccinationListAdapter = VaccinationListAdapter() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -51,7 +59,10 @@ class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), Au popBackStack() } - recyclerViewVaccinationList.adapter = adapter + recyclerViewVaccinationList.apply { + adapter = vaccinationListAdapter + setupSwipe(requireContext()) + } viewModel.uiState.observe(viewLifecycleOwner) { uiState -> bindViews(uiState) @@ -63,30 +74,48 @@ class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), Au VaccinationListFragmentDirections .actionVaccinationListFragmentToVaccinationDetailsFragment(event.vaccinationCertificateId) ) - is VaccinationListViewModel.Event.NavigateToVaccinationQrCodeScanScreen -> doNavigate( + is NavigateToVaccinationQrCodeScanScreen -> doNavigate( VaccinationListFragmentDirections.actionVaccinationListFragmentToVaccinationQrCodeScanFragment() ) + is VaccinationListViewModel.Event.NavigateToQrCodeFullScreen -> { + val navigatorExtras = + binding.recyclerViewVaccinationList.layoutManager?.findViewByPosition(event.positionInList) + ?.run { + val image = findViewById<ShapeableImageView>(R.id.image) + FragmentNavigatorExtras(image to image.transitionName) + } + findNavController().navigate( + R.id.action_global_qrCodeFullScreenFragment, + QrCodeFullScreenFragmentArgs(event.qrCode).toBundle(), + null, + navigatorExtras + ) + } + is DeleteVaccinationEvent -> + showDeleteVaccinationDialog(event.vaccinationCertificateId, event.position) + is NavigateBack -> popBackStack() } } - registerNewVaccinationButton.setOnClickListener { - viewModel.onRegisterNewVaccinationClick() + viewModel.errors.observe(viewLifecycleOwner) { error -> + error.toErrorDialogBuilder(requireContext()).show() } - refreshButton.setOnClickListener { - Toast.makeText(requireContext(), "TODO \uD83D\uDEA7", Toast.LENGTH_LONG).show() + registerNewVaccinationButton.setOnClickListener { + viewModel.onRegisterNewVaccinationClick() } } } private fun FragmentVaccinationListBinding.bindViews(uiState: VaccinationListViewModel.UiState) = with(uiState) { - val isVaccinationComplete = vaccinationStatus == VaccinatedPerson.Status.COMPLETE - setToolbarOverlay(isVaccinationComplete) + val hasImmunity = uiState.vaccinationStatus == VaccinatedPerson.Status.IMMUNITY + + setToolbarOverlay() - adapter.update(listItems) + vaccinationListAdapter.update(listItems) - val background = if (isVaccinationComplete) { + val background = if (hasImmunity) { R.drawable.vaccination_compelete_gradient } else { R.drawable.vaccination_incomplete @@ -94,35 +123,44 @@ class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), Au expandedImage.setImageResource(background) - subtitle.isVisible = isVaccinationComplete - appBarLayout.onOffsetChange { titleAlpha, subtitleAlpha -> title.alpha = titleAlpha subtitle.alpha = subtitleAlpha } } - private fun setToolbarOverlay(isVaccinationComplete: Boolean) { - - // subtitle is only visible when vaccination is complete - val bottomTextView = if (isVaccinationComplete) binding.subtitle else binding.title + private fun setToolbarOverlay() { val deviceWidth = requireContext().resources.displayMetrics.widthPixels val layoutParamsRecyclerView: CoordinatorLayout.LayoutParams = binding.recyclerViewVaccinationList.layoutParams as (CoordinatorLayout.LayoutParams) - val textParams = bottomTextView.layoutParams as (LinearLayout.LayoutParams) + val textParams = binding.subtitle.layoutParams as (LinearLayout.LayoutParams) - val divider = if (isVaccinationComplete) 2 else 3 + val divider = 2 textParams.bottomMargin = (deviceWidth / divider) - 24 /* 24 is space between screen border and Card */ - bottomTextView.requestLayout() + binding.subtitle.requestLayout() val behavior: AppBarLayout.ScrollingViewBehavior = layoutParamsRecyclerView.behavior as (AppBarLayout.ScrollingViewBehavior) behavior.overlayTop = (deviceWidth / divider) - 24 } + private fun showDeleteVaccinationDialog(vaccinationCertificateId: String, position: Int?) { + MaterialAlertDialogBuilder(requireContext()).apply { + setTitle(R.string.vaccination_list_deletion_dialog_title) + setMessage(R.string.vaccination_list_deletion_dialog_message) + setPositiveButton(R.string.vaccination_list_deletion_dialog_positive_button) { _, _ -> + viewModel.deleteVaccination(vaccinationCertificateId) + } + setNegativeButton(R.string.vaccination_list_deletion_dialog_negative_button) { _, _ -> } + setOnDismissListener { + position?.let { vaccinationListAdapter.notifyItemChanged(it) } + } + }.show() + } + companion object { fun navigationUri(personIdentifierCodeSha256: String) = "coronawarnapp://vaccination-list/$personIdentifierCodeSha256".toUri() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt index 0ed0550a991257e869ab11c699eacc6153f71707..a4e200153ccea27b40c5e3422cd31964e594ff8f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt @@ -1,79 +1,161 @@ package de.rki.coronawarnapp.vaccination.ui.list +import android.content.Context +import android.graphics.Bitmap import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.contactdiary.util.getLocale +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat +import de.rki.coronawarnapp.util.coroutine.AppScope +import de.rki.coronawarnapp.util.di.AppContext import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson -import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository +import de.rki.coronawarnapp.vaccination.core.repository.ValueSetsRepository import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH.VaccinationListIncompleteTopCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.transform +import timber.log.Timber class VaccinationListViewModel @AssistedInject constructor( - vaccinationRepository: VaccinationRepository, + private val vaccinationRepository: VaccinationRepository, + valueSetsRepository: ValueSetsRepository, + @AppContext context: Context, + @AppScope private val appScope: CoroutineScope, + private val qrCodeGenerator: QrCodeGenerator, @Assisted private val personIdentifierCodeSha256: String ) : CWAViewModel() { + init { + valueSetsRepository.triggerUpdateValueSet(languageCode = context.getLocale()) + } + val events = SingleLiveEvent<Event>() + val errors = SingleLiveEvent<Throwable>() private val vaccinatedPersonFlow = vaccinationRepository.vaccinationInfos.map { vaccinatedPersonSet -> vaccinatedPersonSet.single { it.identifier.codeSHA256 == personIdentifierCodeSha256 } } - val uiState: LiveData<UiState> = vaccinatedPersonFlow.map { vaccinatedPerson -> + private val vaccinationQrCodeFlow: Flow<Bitmap?> = vaccinatedPersonFlow.transform { + // emit null initially, so that the UI can show the list with a loading indicator for the qrcode + // immediately ... + emit(null) + // ... and after the QR code was generated, it is emitted + emit(qrCodeGenerator.createQrCode(it.getMostRecentVaccinationCertificate.vaccinationQrCodeString)) + } + + val uiState: LiveData<UiState> = combine(vaccinatedPersonFlow, vaccinationQrCodeFlow) { vaccinatedPerson, qrCode -> UiState( - listItems = assembleItemList(vaccinatedPerson = vaccinatedPerson), + listItems = assembleItemList(vaccinatedPerson = vaccinatedPerson, qrCode), vaccinationStatus = vaccinatedPerson.getVaccinationStatus() ) - }.catch { - // TODO Error Handling in an upcoming subtask + }.catch { exception -> + when (exception) { + is NoSuchElementException -> { + Timber.d(exception, "Seems like all vaccination certificates got deleted. Navigate back ...") + events.postValue(Event.NavigateBack) + } + else -> { + Timber.e(exception, "Something unexpected went wrong... Let's navigate back...") + events.postValue(Event.NavigateBack) + } + } }.asLiveData() - private fun assembleItemList(vaccinatedPerson: VaccinatedPerson) = mutableListOf<VaccinationListItem>().apply { - if (vaccinatedPerson.getVaccinationStatus() == COMPLETE) { - // Tbd what to show on complete vaccination - the proof certificate is now obsolete - } else { - add(VaccinationListIncompleteTopCardItem) - } - add( - VaccinationListNameCardItem( - fullName = "${vaccinatedPerson.firstName} ${vaccinatedPerson.lastName}", - dayOfBirth = vaccinatedPerson.dateOfBirth.toDayFormat() + private fun assembleItemList(vaccinatedPerson: VaccinatedPerson, qrCode: Bitmap?) = + mutableListOf<VaccinationListItem>().apply { + + val vaccinationCertificate = vaccinatedPerson.getMostRecentVaccinationCertificate + + add( + VaccinationListQrCodeCardItem( + qrCode = qrCode, + doseNumber = vaccinationCertificate.doseNumber, + totalSeriesOfDoses = vaccinationCertificate.totalSeriesOfDoses, + vaccinatedAt = vaccinatedPerson.getMostRecentVaccinationCertificate.vaccinatedAt, + expiresAt = vaccinatedPerson.getMostRecentVaccinationCertificate.expiresAt, + onQrCodeClick = { + events.postValue( + Event.NavigateToQrCodeFullScreen( + qrCode = vaccinatedPerson.getMostRecentVaccinationCertificate.vaccinationQrCodeString, + positionInList = 0 + ) + ) + } + ) ) - ) - vaccinatedPerson.vaccinationCertificates.forEach { vaccinationCertificate -> - with(vaccinationCertificate) { - add( - VaccinationListVaccinationCardItem( - vaccinationCertificateId = certificateId, - doseNumber = doseNumber.toString(), - totalSeriesOfDoses = totalSeriesOfDoses.toString(), - vaccinatedAt = vaccinatedAt.toDayFormat(), - vaccinationStatus = vaccinatedPerson.getVaccinationStatus(), - isFinalVaccination = doseNumber == totalSeriesOfDoses, - onCardClick = { certificateId -> - events.postValue(Event.NavigateToVaccinationCertificateDetails(certificateId)) - } - ) + + add( + VaccinationListNameCardItem( + fullName = vaccinatedPerson.fullName, + dayOfBirth = vaccinatedPerson.dateOfBirth.toDayFormat() ) + ) + + if (vaccinatedPerson.getVaccinationStatus() == VaccinatedPerson.Status.COMPLETE) { + val timeUntilImmunity = vaccinatedPerson.getTimeUntilImmunity() + if (timeUntilImmunity != null) { + add( + VaccinationListImmunityInformationCardItem(timeUntilImmunity) + ) + } } - } - }.toList() + + vaccinatedPerson.vaccinationCertificates.sortedBy { it.vaccinatedAt }.forEach { vaccinationCertificate -> + with(vaccinationCertificate) { + add( + VaccinationListVaccinationCardItem( + vaccinationCertificateId = certificateId, + doseNumber = doseNumber, + totalSeriesOfDoses = totalSeriesOfDoses, + vaccinatedAt = vaccinatedAt.toDayFormat(), + vaccinationStatus = vaccinatedPerson.getVaccinationStatus(), + isFinalVaccination = doseNumber == totalSeriesOfDoses, + onCardClick = { certificateId -> + events.postValue(Event.NavigateToVaccinationCertificateDetails(certificateId)) + }, + onDeleteClick = { certificateId -> + events.postValue(Event.DeleteVaccinationEvent(certificateId)) + }, + onSwipeToDelete = { certificateId, position -> + events.postValue(Event.DeleteVaccinationEvent(certificateId, position)) + } + ) + ) + } + } + }.toList() fun onRegisterNewVaccinationClick() { events.postValue(Event.NavigateToVaccinationQrCodeScanScreen) } + fun deleteVaccination(vaccinationCertificateId: String) { + launch(scope = appScope) { + try { + vaccinationRepository.deleteVaccinationCertificate(vaccinationCertificateId) + } catch (exception: Exception) { + errors.postValue(exception) + Timber.e(exception, "Something went wrong when trying to delete a vaccination certificate.") + } + } + } + data class UiState( val listItems: List<VaccinationListItem>, val vaccinationStatus: VaccinatedPerson.Status @@ -82,6 +164,9 @@ class VaccinationListViewModel @AssistedInject constructor( sealed class Event { data class NavigateToVaccinationCertificateDetails(val vaccinationCertificateId: String) : Event() object NavigateToVaccinationQrCodeScanScreen : Event() + data class NavigateToQrCodeFullScreen(val qrCode: String, val positionInList: Int) : Event() + data class DeleteVaccinationEvent(val vaccinationCertificateId: String, val position: Int? = null) : Event() + object NavigateBack : Event() } @AssistedFactory diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt index e152edbe93f9e2b9831784520bd909d3df61aa0d..0bca114ae463ddd046ecd17410c90d4a6a11d794 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt @@ -11,12 +11,12 @@ import de.rki.coronawarnapp.util.lists.modular.ModularAdapter import de.rki.coronawarnapp.util.lists.modular.mods.DataBinderMod import de.rki.coronawarnapp.util.lists.modular.mods.StableIdMod import de.rki.coronawarnapp.util.lists.modular.mods.TypedVHCreatorMod -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListCertificateCardItemVH -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListCertificateCardItemVH.VaccinationListCertificateCardItem -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH.VaccinationListIncompleteTopCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem @@ -31,17 +31,17 @@ class VaccinationListAdapter : listOf( StableIdMod(data), DataBinderMod<VaccinationListItem, ItemVH<VaccinationListItem, ViewBinding>>(data), - TypedVHCreatorMod({ data[it] is VaccinationListIncompleteTopCardItem }) { - VaccinationListIncompleteTopCardItemVH(it) - }, TypedVHCreatorMod({ data[it] is VaccinationListNameCardItem }) { VaccinationListNameCardItemVH(it) }, + TypedVHCreatorMod({ data[it] is VaccinationListImmunityInformationCardItem }) { + VaccinationListImmunityInformationCardItemVH(it) + }, TypedVHCreatorMod({ data[it] is VaccinationListVaccinationCardItem }) { VaccinationListVaccinationCardItemVH(it) }, - TypedVHCreatorMod({ data[it] is VaccinationListCertificateCardItem }) { - VaccinationListCertificateCardItemVH(it) + TypedVHCreatorMod({ data[it] is VaccinationListQrCodeCardItem }) { + VaccinationListQrCodeCardItemVH(it) } ) ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt deleted file mode 100644 index 1ccc74b28287669d2e997d56034cb10b8ef8331a..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt +++ /dev/null @@ -1,46 +0,0 @@ -package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder - -import android.graphics.Bitmap -import android.view.ViewGroup -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.VaccinationListCertificateCardBinding -import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter -import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListCertificateCardItemVH.VaccinationListCertificateCardItem - -class VaccinationListCertificateCardItemVH(parent: ViewGroup) : - VaccinationListAdapter.ItemVH<VaccinationListCertificateCardItem, VaccinationListCertificateCardBinding>( - layoutRes = R.layout.vaccination_list_certificate_card, - parent = parent - ) { - - override val viewBinding: Lazy<VaccinationListCertificateCardBinding> = lazy { - VaccinationListCertificateCardBinding.bind(itemView) - } - - override val onBindData: VaccinationListCertificateCardBinding.( - item: VaccinationListCertificateCardItem, - payloads: List<Any> - ) -> Unit = - { item, _ -> - when (item.qrCode) { - null -> progressBar.show() - else -> { - image.setImageBitmap(item.qrCode) - progressBar.hide() - } - } - subtitle.text = context.getString( - R.string.vaccination_list_certificate_card_subtitle, - item.remainingValidityInDays - ) - } - - data class VaccinationListCertificateCardItem( - val qrCode: Bitmap?, - val remainingValidityInDays: Int - ) : - VaccinationListItem { - override val stableId = this.hashCode().toLong() - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt new file mode 100644 index 0000000000000000000000000000000000000000..f6824b79b04a1ca22d84eb29a73a7871ff0bc2d0 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListImmunityInformationCardItemVH.kt @@ -0,0 +1,35 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationListImmunityCardBinding +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListImmunityInformationCardItemVH.VaccinationListImmunityInformationCardItem +import org.joda.time.Duration + +class VaccinationListImmunityInformationCardItemVH(parent: ViewGroup) : + VaccinationListAdapter.ItemVH<VaccinationListImmunityInformationCardItem, VaccinationListImmunityCardBinding>( + layoutRes = R.layout.vaccination_list_immunity_card, + parent = parent + ) { + + override val viewBinding: Lazy<VaccinationListImmunityCardBinding> = lazy { + VaccinationListImmunityCardBinding.bind(itemView) + } + + override val onBindData: VaccinationListImmunityCardBinding + .(item: VaccinationListImmunityInformationCardItem, payloads: List<Any>) -> Unit = { item, _ -> + val daysUntilImmunity = item.timeUntilImmunity.standardDays.toInt() + body.text = + context.resources.getQuantityString( + R.plurals.vaccination_list_immunity_card_body, + daysUntilImmunity, + daysUntilImmunity + ) + } + + data class VaccinationListImmunityInformationCardItem(val timeUntilImmunity: Duration) : VaccinationListItem { + override val stableId = VaccinationListImmunityInformationCardItem::class.java.name.hashCode().toLong() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt deleted file mode 100644 index dd9ec7bbad1078c76c6c71fb7024451a82165389..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt +++ /dev/null @@ -1,27 +0,0 @@ -package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder - -import android.view.ViewGroup -import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.databinding.VaccinationListIncompleteTopCardBinding -import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter -import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem -import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH.VaccinationListIncompleteTopCardItem - -class VaccinationListIncompleteTopCardItemVH(parent: ViewGroup) : - VaccinationListAdapter.ItemVH<VaccinationListIncompleteTopCardItem, VaccinationListIncompleteTopCardBinding>( - layoutRes = R.layout.vaccination_list_incomplete_top_card, - parent = parent - ) { - - override val viewBinding: Lazy<VaccinationListIncompleteTopCardBinding> = lazy { - VaccinationListIncompleteTopCardBinding.bind(itemView) - } - - override val onBindData: VaccinationListIncompleteTopCardBinding - .(item: VaccinationListIncompleteTopCardItem, payloads: List<Any>) -> Unit = { _, _ -> // NOOP - } - - object VaccinationListIncompleteTopCardItem : VaccinationListItem { - override val stableId = this.hashCode().toLong() - } -} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt new file mode 100644 index 0000000000000000000000000000000000000000..f5741bd7abbf24b72d689b4c618a6359d67d462d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListQrCodeCardItemVH.kt @@ -0,0 +1,56 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder + +import android.graphics.Bitmap +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationListQrcodeCardBinding +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListQrCodeCardItemVH.VaccinationListQrCodeCardItem +import org.joda.time.Instant +import org.joda.time.LocalDate + +class VaccinationListQrCodeCardItemVH(parent: ViewGroup) : + VaccinationListAdapter.ItemVH<VaccinationListQrCodeCardItem, VaccinationListQrcodeCardBinding>( + layoutRes = R.layout.vaccination_list_qrcode_card, + parent = parent + ) { + + override val viewBinding: Lazy<VaccinationListQrcodeCardBinding> = lazy { + VaccinationListQrcodeCardBinding.bind(itemView) + } + + override val onBindData: VaccinationListQrcodeCardBinding + .(item: VaccinationListQrCodeCardItem, payloads: List<Any>) -> Unit = + { item, _ -> + image.setImageBitmap(item.qrCode) + item.qrCode?.let { + image.setOnClickListener { item.onQrCodeClick.invoke() } + progressBar.hide() + } + title.text = context.getString( + R.string.vaccination_qrcode_card_title, + item.doseNumber, + item.totalSeriesOfDoses + ) + subtitle.text = + context.getString( + R.string.vaccination_qrcode_card_subtitle, + item.vaccinatedAt.toShortDayFormat(), + item.expiresAt.toShortDayFormat() + ) + } + + data class VaccinationListQrCodeCardItem( + val qrCode: Bitmap?, + val doseNumber: Int, + val totalSeriesOfDoses: Int, + val vaccinatedAt: LocalDate, + val expiresAt: Instant, + val onQrCodeClick: () -> Unit + ) : + VaccinationListItem { + override val stableId = this.hashCode().toLong() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt index 455beedf1b9a02a3b57d8c21ba385dd460c23542..82f2a8388585b70ba8f570710b5728f9f1f91889 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt @@ -1,8 +1,12 @@ package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder +import android.view.Gravity import android.view.ViewGroup +import androidx.appcompat.widget.PopupMenu +import androidx.recyclerview.widget.RecyclerView import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.VaccinationListVaccinationCardBinding +import de.rki.coronawarnapp.util.list.Swipeable import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.IMMUNITY @@ -12,13 +16,18 @@ import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem import java.util.Objects -class VaccinationListVaccinationCardItemVH( - parent: ViewGroup, -) : +class VaccinationListVaccinationCardItemVH(parent: ViewGroup) : VaccinationListAdapter.ItemVH<VaccinationListVaccinationCardItem, VaccinationListVaccinationCardBinding>( layoutRes = R.layout.vaccination_list_vaccination_card, parent = parent - ) { + ), + Swipeable { + + private var latestItem: VaccinationListVaccinationCardItem? = null + + override fun onSwipe(holder: RecyclerView.ViewHolder, direction: Int) { + latestItem?.let { it.onSwipeToDelete(it.vaccinationCertificateId, holder.adapterPosition) } + } override val viewBinding: Lazy<VaccinationListVaccinationCardBinding> = lazy { VaccinationListVaccinationCardBinding.bind(itemView) @@ -27,6 +36,8 @@ class VaccinationListVaccinationCardItemVH( item: VaccinationListVaccinationCardItem, payloads: List<Any> ) -> Unit = { item, _ -> + latestItem = item + item.apply { root.setOnClickListener { onCardClick.invoke(vaccinationCertificateId) @@ -42,36 +53,43 @@ class VaccinationListVaccinationCardItemVH( ) val iconRes = when (vaccinationStatus) { - INCOMPLETE -> { - if (isFinalVaccination) { - R.drawable.ic_vaccination_incomplete_final - } else { - R.drawable.ic_vaccination_incomplete - } + INCOMPLETE, COMPLETE -> { + R.drawable.ic_vaccination_incomplete } - COMPLETE -> { + IMMUNITY -> { if (isFinalVaccination) { R.drawable.ic_vaccination_complete_final } else { R.drawable.ic_vaccination_complete } } - IMMUNITY -> { - throw NotImplementedError() - } } vaccinationIcon.setImageResource(iconRes) + + val menu = PopupMenu(context, overflowMenu, Gravity.TOP or Gravity.END).apply { + inflate(R.menu.menu_vaccination_item) + setOnMenuItemClickListener { + when (it.itemId) { + R.id.menu_delete -> item.onDeleteClick(item.vaccinationCertificateId).let { true } + else -> false + } + } + } + + overflowMenu.setOnClickListener { menu.show() } } } data class VaccinationListVaccinationCardItem( val vaccinationCertificateId: String, - val doseNumber: String, - val totalSeriesOfDoses: String, + val doseNumber: Int, + val totalSeriesOfDoses: Int, val vaccinatedAt: String, val vaccinationStatus: VaccinatedPerson.Status, val isFinalVaccination: Boolean, - val onCardClick: (String) -> Unit + val onCardClick: (String) -> Unit, + val onDeleteClick: (String) -> Unit, + val onSwipeToDelete: (String, Int) -> Unit ) : VaccinationListItem { override val stableId: Long = Objects.hash( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt index 55cc22525a4233756deeaf92d3bcc21b90792387..48a09d1257473491fbe4bd5167242d3af602a449 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt @@ -16,7 +16,7 @@ import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.permission.CameraPermissionHelper import de.rki.coronawarnapp.util.ui.doNavigate import de.rki.coronawarnapp.util.ui.popBackStack -import de.rki.coronawarnapp.util.ui.viewBindingLazy +import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import javax.inject.Inject @@ -28,7 +28,7 @@ class VaccinationQrCodeScanFragment : @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory private val viewModel: VaccinationQrCodeScanViewModel by cwaViewModels { viewModelFactory } - private val binding: FragmentScanQrCodeBinding by viewBindingLazy() + private val binding: FragmentScanQrCodeBinding by viewBinding() private var showsPermissionDialog = false override fun onViewCreated( diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml deleted file mode 100644 index 40001f61b41bcc20118ae570253dd3b25a46ed85..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml +++ /dev/null @@ -1,10 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="19dp" - android:height="16dp" - android:viewportWidth="19" - android:viewportHeight="16"> - <path - android:pathData="M11.9186,0.7474L10.4286,2.3179L14.9685,7.103H0.9918V9.197H14.9685L10.4286,13.9821L11.9186,15.5525L18.9419,8.15L11.9186,0.7474Z" - android:fillColor="#A7A7A7" - android:fillType="evenOdd"/> -</vector> diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_register_test_illustration.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_register_test_illustration.xml new file mode 100644 index 0000000000000000000000000000000000000000..56b012fcbb4ab820712b6b277fa727520d618a6a --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_register_test_illustration.xml @@ -0,0 +1,1565 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="260dp" + android:height="159dp" + android:viewportWidth="260" + android:viewportHeight="159"> + <path + android:pathData="M48,26C32,58 21.028,40.688 6,66C-8.549,90.45 10.5,117.218 10.5,117.218L235.781,118.033C235.781,118.033 258.63,81.018 252.678,53.042C248.068,29.225 217.724,13.344 201.977,21.414C161.09,42.24 153.395,12.318 133,6.5C93.589,-4.685 67,0.5 48,26Z" + android:fillColor="#2D2D2F" + android:fillType="evenOdd"/> + <path + android:pathData="M138.909,28.334L214.431,10.899A4,4 121.394,0 1,219.228 13.897L242.356,114.07A4,4 121.394,0 1,239.358 118.867L163.837,136.302A4,4 121.394,0 1,159.039 133.304L135.912,33.131A4,4 121.394,0 1,138.909 28.334z" + android:fillColor="#3F3F43"/> + <path + android:pathData="M161.342,105.56L229.356,89.858A0.436,0.436 119.383,0 1,229.879 90.185L229.879,90.185A0.436,0.436 119.383,0 1,229.552 90.708L161.538,106.41A0.436,0.436 119.383,0 1,161.015 106.083L161.015,106.083A0.436,0.436 119.383,0 1,161.342 105.56z" + android:fillColor="#657888"/> + <path + android:pathData="M163.039,112.204L213.199,100.624A0.436,0.436 121.396,0 1,213.722 100.951L213.722,100.951A0.436,0.436 121.396,0 1,213.395 101.474L163.235,113.054A0.436,0.436 121.396,0 1,162.712 112.727L162.712,112.727A0.436,0.436 121.396,0 1,163.039 112.204z" + android:fillColor="#657888"/> + <path + android:pathData="M164.918,118.619L225.28,104.684A0.436,0.436 119.383,0 1,225.803 105.011L225.803,105.011A0.436,0.436 119.383,0 1,225.476 105.534L165.114,119.469A0.436,0.436 119.383,0 1,164.591 119.142L164.591,119.142A0.436,0.436 119.383,0 1,164.918 118.619z" + android:fillColor="#657888"/> + <path + android:pathData="M194.251,40.848L193.099,41.11L192.838,39.958L193.991,39.696L194.251,40.848Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.402,40.59L194.25,40.85L193.988,39.699L195.14,39.438L195.402,40.59Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.556,40.328L195.404,40.589L195.143,39.438L196.296,39.176L196.556,40.328Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.706,40.065L196.554,40.325L196.293,39.175L197.445,38.913L197.706,40.065Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.86,39.807L197.708,40.068L197.446,38.916L198.599,38.655L198.86,39.807Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.013,39.544L198.861,39.804L198.6,38.653L199.753,38.392L200.013,39.544Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.161,39.283L200.009,39.544L199.748,38.392L200.9,38.131L201.161,39.283Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.424,40.438L200.272,40.698L200.011,39.548L201.164,39.286L201.424,40.438Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.685,41.588L200.533,41.849L200.271,40.697L201.423,40.437L201.685,41.588Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.945,42.739L200.793,43L200.531,41.849L201.684,41.587L201.945,42.739Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.206,43.89L201.054,44.15L200.793,43L201.946,42.738L202.206,43.89Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.467,45.045L201.315,45.306L201.054,44.154L202.206,43.893L202.467,45.045Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.727,46.196L201.575,46.457L201.313,45.306L202.467,45.044L202.727,46.196Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.784,45.94L172.936,45.678L172.674,44.526L171.522,44.788L171.784,45.94Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M170.631,46.195L171.783,45.935L171.522,44.781L170.371,45.043L170.631,46.195Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M169.482,46.458L170.634,46.196L170.373,45.044L169.221,45.306L169.482,46.458Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M168.329,46.719L169.481,46.459L169.219,45.306L168.067,45.567L168.329,46.719Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M167.173,46.98L168.325,46.719L168.064,45.567L166.913,45.828L167.173,46.98Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M166.024,47.244L167.176,46.983L166.915,45.83L165.763,46.092L166.024,47.244Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M164.872,47.502L166.023,47.24L165.762,46.089L164.611,46.35L164.872,47.502Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.133,48.655L166.284,48.395L166.023,47.242L164.871,47.503L165.133,48.655Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.391,49.803L166.543,49.542L166.282,48.39L165.131,48.651L165.391,49.803Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.655,50.958L166.807,50.698L166.545,49.545L165.394,49.806L165.655,50.958Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.916,52.109L167.068,51.848L166.807,50.695L165.656,50.957L165.916,52.109Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M166.174,53.264L167.326,53.002L167.066,51.85L165.914,52.112L166.174,53.264Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M166.437,54.414L167.589,54.153L167.328,53L166.176,53.262L166.437,54.414Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.011,75.12L200.859,75.382L201.12,76.534L202.271,76.272L202.011,75.12Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M203.168,74.862L202.016,75.122L202.277,76.275L203.429,76.014L203.168,74.862Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M204.316,74.603L203.164,74.864L203.425,76.016L204.576,75.755L204.316,74.603Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M205.469,74.341L204.317,74.601L204.579,75.754L205.731,75.493L205.469,74.341Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M206.623,74.08L205.471,74.341L205.732,75.493L206.884,75.231L206.623,74.08Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.771,73.816L206.619,74.077L206.881,75.23L208.031,74.968L207.771,73.816Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.927,73.558L207.775,73.818L208.037,74.972L209.189,74.71L208.927,73.558Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.665,72.404L207.513,72.664L207.774,73.818L208.925,73.556L208.665,72.404Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.402,71.253L207.25,71.515L207.511,72.667L208.663,72.405L208.402,71.253Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.145,70.102L206.993,70.362L207.255,71.515L208.405,71.254L208.145,70.102Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.882,68.947L206.73,69.208L206.992,70.36L208.144,70.099L207.882,68.947Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.621,67.796L206.469,68.056L206.73,69.209L207.881,68.948L207.621,67.796Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.358,66.642L206.206,66.902L206.467,68.055L207.619,67.794L207.358,66.642Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.547,80.212L180.699,79.951L180.96,81.103L179.808,81.364L179.547,80.212Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.396,80.472L179.547,80.212L179.809,81.364L178.656,81.624L178.396,80.472Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.24,80.732L178.392,80.47L178.654,81.622L177.502,81.883L177.24,80.732Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.092,80.993L177.244,80.733L177.505,81.884L176.352,82.145L176.092,80.993Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.938,81.253L176.089,80.991L176.351,82.143L175.198,82.405L174.938,81.253Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.787,81.514L174.939,81.254L175.2,82.404L174.049,82.666L173.787,81.514Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.636,81.777L173.788,81.515L174.049,82.667L172.896,82.929L172.636,81.777Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.373,80.621L173.525,80.361L173.786,81.511L172.634,81.773L172.373,80.621Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.113,79.47L173.265,79.209L173.527,80.361L172.373,80.622L172.113,79.47Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.854,78.317L173.005,78.056L173.267,79.207L172.115,79.469L171.854,78.317Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.591,77.168L172.743,76.908L173.004,78.058L171.851,78.32L171.591,77.168Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.331,76.016L172.483,75.755L172.744,76.907L171.592,77.168L171.331,76.016Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.069,74.863L172.221,74.603L172.483,75.754L171.33,76.015L171.069,74.863Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.015,47.932L179.863,48.194L179.602,47.042L180.755,46.78L181.015,47.932Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.473,47.15L183.321,47.41L183.06,46.26L184.213,45.998L184.473,47.15Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.431,48.826L181.279,49.087L181.018,47.935L182.171,47.674L182.431,48.826Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.889,48.039L184.737,48.301L184.476,47.149L185.629,46.887L185.889,48.039Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.191,47.522L187.039,47.784L186.777,46.632L187.93,46.37L188.191,47.522Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.844,49.714L182.692,49.974L182.431,48.822L183.584,48.562L183.844,49.714Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.45,48.673L187.299,48.933L187.037,47.783L188.189,47.521L188.45,48.673Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.802,51.389L180.65,51.651L180.389,50.499L181.541,50.237L181.802,51.389Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.107,50.868L182.955,51.13L182.693,49.978L183.845,49.717L184.107,50.868Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.408,50.345L185.257,50.606L184.995,49.454L186.148,49.193L186.408,50.345Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.562,50.086L186.41,50.346L186.148,49.195L187.3,48.934L187.562,50.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.06,52.54L180.908,52.8L180.646,51.65L181.8,51.388L182.06,52.54Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.213,52.279L182.061,52.541L181.8,51.389L182.952,51.127L183.213,52.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.475,53.431L182.323,53.692L182.062,52.541L183.215,52.279L183.475,53.431Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.626,53.17L183.474,53.431L183.213,52.28L184.365,52.018L184.626,53.17Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.084,52.391L186.932,52.652L186.671,51.501L187.823,51.239L188.084,52.391Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.233,52.128L188.081,52.389L187.819,51.237L188.972,50.976L189.233,52.128Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.584,54.845L181.432,55.105L181.171,53.955L182.324,53.694L182.584,54.845Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.037,54.062L184.885,54.322L184.624,53.17L185.776,52.91L186.037,54.062Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.844,56L181.692,56.26L181.431,55.108L182.583,54.848L182.844,56Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.995,55.737L182.843,55.999L182.582,54.847L183.735,54.585L183.995,55.737Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.3,55.213L185.148,55.475L184.887,54.323L186.04,54.062L186.3,55.213Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.604,54.693L187.452,54.954L187.19,53.802L188.342,53.541L188.604,54.693Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.755,54.431L188.603,54.691L188.342,53.54L189.495,53.279L189.755,54.431Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.236,45.847L189.084,46.107L188.822,44.956L189.975,44.695L190.236,45.847Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.497,46.998L189.345,47.26L189.084,46.108L190.236,45.846L190.497,46.998Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.757,48.152L189.605,48.412L189.344,47.262L190.497,47L190.757,48.152Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.062,47.628L191.91,47.888L191.648,46.738L192.802,46.476L193.062,47.628Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.215,47.366L193.063,47.627L192.802,46.475L193.954,46.214L194.215,47.366Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.364,47.107L194.213,47.367L193.951,46.216L195.104,45.955L195.364,47.107Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.518,46.845L195.366,47.106L195.104,45.954L196.258,45.693L196.518,46.845Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.017,49.3L189.865,49.562L189.604,48.41L190.755,48.148L191.017,49.3Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.324,48.783L192.173,49.044L191.911,47.892L193.063,47.631L193.324,48.783Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.475,48.519L193.323,48.779L193.062,47.629L194.215,47.367L194.475,48.519Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.626,48.258L194.474,48.519L194.213,47.368L195.365,47.106L195.626,48.258Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.778,47.995L195.626,48.255L195.364,47.104L196.516,46.843L196.778,47.995Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.28,50.453L190.128,50.713L189.866,49.562L191.019,49.301L191.28,50.453Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.581,49.934L192.429,50.195L192.168,49.043L193.321,48.782L193.581,49.934Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.736,49.671L193.584,49.932L193.322,48.78L194.474,48.52L194.736,49.671Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.887,49.412L194.735,49.674L194.474,48.522L195.627,48.261L195.887,49.412Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.039,49.15L195.887,49.41L195.626,48.258L196.779,47.998L197.039,49.15Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.54,51.605L190.388,51.865L190.127,50.713L191.28,50.453L191.54,51.605Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.844,51.084L192.692,51.344L192.431,50.194L193.583,49.932L193.844,51.084Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.995,50.822L193.843,51.083L193.582,49.931L194.735,49.67L194.995,50.822Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.147,50.564L194.995,50.824L194.733,49.674L195.885,49.412L196.147,50.564Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.297,50.301L196.145,50.563L195.884,49.411L197.037,49.149L197.297,50.301Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.802,52.759L190.65,53.02L190.389,51.868L191.541,51.607L191.802,52.759Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.386,45.584L190.234,45.846L189.973,44.694L191.125,44.432L191.386,45.584Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.537,45.322L191.385,45.583L191.124,44.431L192.277,44.171L192.537,45.322Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.691,45.061L192.539,45.322L192.277,44.17L193.429,43.909L193.691,45.061Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.844,44.802L193.692,45.063L193.431,43.912L194.583,43.651L194.844,44.802Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.995,44.543L194.843,44.805L194.582,43.653L195.735,43.392L195.995,44.543Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.146,44.28L195.994,44.54L195.732,43.39L196.884,43.128L197.146,44.28Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.297,44.019L197.145,44.281L196.884,43.129L198.037,42.868L198.297,44.019Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.56,45.174L197.408,45.434L197.146,44.283L198.298,44.022L198.56,45.174Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.823,46.325L197.671,46.585L197.409,45.433L198.562,45.173L198.823,46.325Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.082,47.474L197.93,47.735L197.669,46.583L198.821,46.322L199.082,47.474Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.342,48.626L198.19,48.886L197.929,47.736L199.082,47.474L199.342,48.626Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.605,49.78L198.453,50.042L198.191,48.89L199.343,48.628L199.605,49.78Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.864,50.931L198.713,51.192L198.451,50.041L199.604,49.779L199.864,50.931Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.062,53.91L190.91,54.17L190.648,53.02L191.802,52.758L192.062,53.91Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.213,53.652L192.061,53.914L191.8,52.762L192.953,52.5L193.213,53.652Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.364,53.389L193.213,53.649L192.951,52.498L194.103,52.237L194.364,53.389Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.518,53.128L194.366,53.389L194.104,52.237L195.258,51.976L195.518,53.128Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.671,52.866L195.519,53.126L195.258,51.975L196.41,51.714L196.671,52.866Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.823,52.603L196.671,52.864L196.409,51.712L197.562,51.451L197.823,52.603Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.976,52.345L197.824,52.605L197.562,51.454L198.716,51.193L198.976,52.345Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.124,52.086L198.972,52.346L198.711,51.194L199.863,50.934L200.124,52.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M170.651,50.281L169.499,50.541L169.237,49.389L170.389,49.129L170.651,50.281Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.801,50.02L170.649,50.281L170.388,49.13L171.541,48.868L171.801,50.02Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.952,49.757L171.8,50.017L171.539,48.865L172.692,48.605L172.952,49.757Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.104,49.499L172.952,49.76L172.69,48.608L173.842,48.347L174.104,49.499Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.257,49.241L174.105,49.501L173.844,48.349L174.997,48.089L175.257,49.241Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.41,48.978L175.258,49.24L174.997,48.088L176.149,47.826L176.41,48.978Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.562,48.717L176.41,48.977L176.148,47.826L177.302,47.565L177.562,48.717Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.713,48.453L177.561,48.715L177.3,47.563L178.453,47.302L178.713,48.453Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M170.91,51.432L169.758,51.694L169.497,50.542L170.65,50.28L170.91,51.432Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.975,49.608L177.823,49.868L177.562,48.718L178.713,48.456L178.975,49.608Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.172,52.587L170.02,52.847L169.759,51.696L170.911,51.435L171.172,52.587Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.472,52.063L172.32,52.323L172.059,51.172L173.212,50.911L173.472,52.063Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.628,51.805L173.476,52.066L173.215,50.914L174.367,50.653L174.628,51.805Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.78,51.542L174.628,51.802L174.366,50.651L175.519,50.39L175.78,51.542Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.93,51.28L175.778,51.541L175.517,50.389L176.669,50.128L176.93,51.28Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.235,50.759L178.083,51.021L177.821,49.869L178.974,49.607L179.235,50.759Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.433,53.738L170.281,53.999L170.02,52.847L171.173,52.586L171.433,53.738Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.735,53.216L172.583,53.478L172.321,52.326L173.474,52.064L173.735,53.216Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.888,52.956L173.736,53.216L173.475,52.065L174.628,51.804L174.888,52.956Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.042,52.693L174.89,52.954L174.629,51.802L175.781,51.541L176.042,52.693Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.193,52.435L176.041,52.695L175.779,51.544L176.932,51.283L177.193,52.435Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.494,51.91L178.342,52.172L178.081,51.02L179.233,50.758L179.494,51.91Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.693,54.889L170.541,55.149L170.279,53.999L171.431,53.737L171.693,54.889Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.997,54.364L172.845,54.624L172.584,53.473L173.736,53.212L173.997,54.364Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.151,54.11L173.999,54.37L173.737,53.218L174.889,52.958L175.151,54.11Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.299,53.847L175.147,54.109L174.886,52.957L176.039,52.695L176.299,53.847Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.452,53.585L176.3,53.846L176.039,52.694L177.191,52.434L177.452,53.585Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.757,53.064L178.605,53.325L178.344,52.174L179.497,51.912L179.757,53.064Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.955,56.043L170.803,56.303L170.542,55.151L171.695,54.891L171.955,56.043Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.259,55.519L173.107,55.779L172.846,54.627L173.999,54.367L174.259,55.519Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.41,55.258L174.258,55.519L173.997,54.367L175.15,54.106L175.41,55.258Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.562,54.998L175.41,55.258L175.148,54.108L176.3,53.846L176.562,54.998Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.715,54.739L176.563,55.001L176.302,53.849L177.455,53.588L177.715,54.739Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.02,54.215L178.868,54.477L178.606,53.325L179.76,53.064L180.02,54.215Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.215,57.194L171.063,57.456L170.802,56.304L171.954,56.042L172.215,57.194Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.278,55.37L179.126,55.63L178.864,54.48L180.016,54.218L180.278,55.37Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.477,58.349L171.325,58.609L171.063,57.458L172.217,57.197L172.477,58.349Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.628,58.086L172.476,58.347L172.215,57.195L173.367,56.934L173.628,58.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.78,57.824L173.628,58.084L173.366,56.934L174.519,56.672L174.78,57.824Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.933,57.562L174.781,57.824L174.52,56.672L175.671,56.41L175.933,57.562Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.081,57.304L175.929,57.564L175.668,56.414L176.82,56.152L177.081,57.304Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.236,57.04L177.084,57.302L176.822,56.15L177.975,55.889L178.236,57.04Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.391,56.779L178.239,57.04L177.978,55.889L179.129,55.627L179.391,56.779Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.539,56.518L179.387,56.78L179.126,55.628L180.279,55.366L180.539,56.518Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.084,69.868L173.932,70.129L173.671,68.978L174.823,68.716L175.084,69.868Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.236,69.607L175.084,69.868L174.822,68.716L175.975,68.455L176.236,69.607Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.389,69.344L176.237,69.604L175.976,68.453L177.129,68.192L177.389,69.344Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.542,69.086L177.39,69.348L177.129,68.196L178.281,67.934L178.542,69.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.691,68.823L178.539,69.083L178.277,67.933L179.43,67.671L179.691,68.823Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.844,68.561L179.692,68.823L179.431,67.671L180.583,67.409L180.844,68.561Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.997,68.298L180.845,68.559L180.584,67.408L181.737,67.146L181.997,68.298Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.149,68.04L181.997,68.302L181.735,67.15L182.888,66.888L183.149,68.04Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.347,71.019L174.195,71.28L173.934,70.129L175.087,69.867L175.347,71.019Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.408,69.191L182.257,69.453L181.995,68.301L183.147,68.039L183.408,69.191Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.607,72.17L174.455,72.43L174.193,71.28L175.345,71.018L175.607,72.17Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.911,71.649L176.759,71.91L176.498,70.759L177.65,70.497L177.911,71.649Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.063,71.391L177.911,71.651L177.649,70.499L178.801,70.239L179.063,71.391Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.216,71.128L179.064,71.39L178.803,70.238L179.956,69.976L180.216,71.128Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.366,70.868L180.215,71.128L179.953,69.976L181.105,69.716L181.366,70.868Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.671,70.346L182.519,70.606L182.258,69.455L183.411,69.194L183.671,70.346Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.867,73.325L174.716,73.585L174.454,72.433L175.607,72.173L175.867,73.325Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.171,72.801L177.019,73.061L176.758,71.909L177.911,71.649L178.171,72.801Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.325,72.538L178.174,72.799L177.912,71.648L179.065,71.386L179.325,72.538Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.474,72.279L179.322,72.539L179.061,71.388L180.212,71.127L180.474,72.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.627,72.016L180.475,72.278L180.214,71.126L181.367,70.865L181.627,72.016Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.932,71.497L182.78,71.758L182.519,70.606L183.672,70.345L183.932,71.497Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.129,74.476L174.977,74.737L174.716,73.585L175.868,73.324L176.129,74.476Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.434,73.954L177.282,74.216L177.021,73.064L178.172,72.803L178.434,73.954Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.585,73.692L178.433,73.952L178.172,72.802L179.325,72.54L179.585,73.692Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.736,73.43L179.584,73.692L179.322,72.54L180.475,72.278L180.736,73.43Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.889,73.168L180.737,73.428L180.476,72.277L181.627,72.016L181.889,73.168Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.192,72.652L183.04,72.912L182.778,71.761L183.93,71.5L184.192,72.652Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.392,75.63L175.24,75.89L174.979,74.74L176.132,74.478L176.392,75.63Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.692,75.106L177.54,75.366L177.278,74.216L178.431,73.954L178.692,75.106Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.845,74.844L178.693,75.105L178.432,73.953L179.584,73.692L179.845,74.844Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.998,74.585L179.846,74.845L179.585,73.695L180.737,73.433L180.998,74.585Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.15,74.322L180.998,74.583L180.736,73.432L181.889,73.17L182.15,74.322Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.451,73.798L183.299,74.059L183.038,72.907L184.191,72.646L184.451,73.798Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.649,76.777L175.497,77.038L175.235,75.886L176.387,75.625L176.649,76.777Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.713,74.952L183.561,75.213L183.3,74.061L184.452,73.8L184.713,74.952Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.911,77.931L175.759,78.191L175.498,77.04L176.651,76.779L176.911,77.931Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.063,77.669L176.911,77.93L176.649,76.778L177.801,76.518L178.063,77.669Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.216,77.407L178.064,77.668L177.803,76.517L178.956,76.255L179.216,77.407Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.367,77.149L179.216,77.409L178.954,76.257L180.106,75.997L180.367,77.149Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.518,76.89L180.366,77.151L180.104,76L181.258,75.738L181.518,76.89Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.671,76.628L181.519,76.888L181.258,75.736L182.411,75.476L182.671,76.628Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.823,76.367L182.671,76.628L182.409,75.476L183.561,75.215L183.823,76.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.976,76.104L183.824,76.364L183.562,75.213L184.716,74.952L184.976,76.104Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.408,56.631L184.257,56.892L183.995,55.74L185.148,55.479L185.408,56.631Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.563,56.367L185.411,56.628L185.149,55.477L186.301,55.216L186.563,56.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.713,56.106L186.561,56.368L186.3,55.216L187.453,54.954L187.713,56.106Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.018,55.582L188.866,55.843L188.604,54.691L189.756,54.43L190.018,55.582Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.997,60.65L171.845,60.91L171.584,59.76L172.737,59.498L172.997,60.65Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.302,60.126L174.15,60.386L173.889,59.236L175.042,58.974L175.302,60.126Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.453,59.867L175.301,60.128L175.04,58.976L176.192,58.716L176.453,59.867Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.607,59.609L176.455,59.871L176.193,58.719L177.347,58.457L177.607,59.609Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.911,59.085L178.759,59.346L178.498,58.194L179.65,57.933L179.911,59.085Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.366,58.302L182.215,58.562L181.953,57.412L183.105,57.15L183.366,58.302Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.518,58.04L183.366,58.301L183.104,57.149L184.258,56.888L184.518,58.04Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.671,57.781L184.519,58.041L184.258,56.89L185.41,56.629L185.671,57.781Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.973,57.26L186.821,57.52L186.56,56.37L187.711,56.108L187.973,57.26Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.129,56.997L187.977,57.259L187.716,56.107L188.868,55.846L189.129,56.997Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.278,56.736L189.126,56.996L188.864,55.845L190.017,55.584L190.278,56.736Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.431,56.475L190.279,56.736L190.018,55.585L191.169,55.323L191.431,56.475Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.04,55.433L194.888,55.694L194.627,54.542L195.78,54.282L196.04,55.433Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.495,54.649L198.343,54.91L198.082,53.758L199.234,53.497L199.495,54.649Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.649,54.388L199.497,54.648L199.235,53.498L200.387,53.236L200.649,54.388Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.41,61.539L173.258,61.8L172.997,60.649L174.15,60.387L174.41,61.539Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.715,61.018L175.563,61.279L175.302,60.127L176.455,59.866L176.715,61.018Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.323,59.976L180.171,60.238L179.909,59.086L181.061,58.824L181.323,59.976Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.626,59.454L182.474,59.715L182.213,58.563L183.366,58.302L183.626,59.454Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.236,58.412L187.084,58.673L186.822,57.521L187.975,57.26L188.236,58.412Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.539,57.891L189.387,58.151L189.126,56.999L190.278,56.739L190.539,57.891Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.845,57.367L191.693,57.627L191.432,56.475L192.584,56.215L192.845,57.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.303,56.583L195.151,56.845L194.89,55.693L196.042,55.431L196.303,56.583Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.451,56.324L196.299,56.584L196.038,55.434L197.191,55.173L197.451,56.324Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.758,55.8L198.606,56.061L198.345,54.91L199.498,54.648L199.758,55.8Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.52,62.955L172.368,63.216L172.106,62.064L173.26,61.803L173.52,62.955Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.668,62.693L173.516,62.953L173.255,61.803L174.407,61.541L174.668,62.693Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.824,62.432L174.673,62.694L174.411,61.542L175.564,61.281L175.824,62.432Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.126,61.911L176.974,62.172L176.713,61.02L177.866,60.759L178.126,61.911Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.736,60.87L181.584,61.131L181.322,59.979L182.474,59.718L182.736,60.87Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.04,60.346L183.888,60.607L183.627,59.455L184.78,59.194L185.04,60.346Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.498,59.562L187.346,59.823L187.085,58.671L188.237,58.41L188.498,59.562Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.107,58.521L191.955,58.782L191.693,57.63L192.846,57.369L193.107,58.521Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.409,57.996L194.258,58.257L193.996,57.106L195.149,56.844L195.409,57.996Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.711,57.472L196.559,57.733L196.298,56.581L197.45,56.32L197.711,57.472Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.084,63.585L174.932,63.845L174.671,62.694L175.823,62.433L176.084,63.585Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.844,62.279L180.692,62.54L180.431,61.388L181.583,61.127L181.844,62.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.998,62.02L181.846,62.28L181.585,61.129L182.738,60.868L182.998,62.02Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.151,61.758L182.999,62.018L182.737,60.866L183.889,60.606L184.151,61.758Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.605,60.975L186.453,61.236L186.191,60.084L187.343,59.823L187.605,60.975Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.911,60.451L188.759,60.712L188.498,59.56L189.65,59.299L189.911,60.451Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.06,60.192L189.908,60.452L189.646,59.302L190.798,59.04L191.06,60.192Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.516,59.41L193.364,59.672L193.103,58.52L194.256,58.258L194.516,59.41Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.672,59.148L194.52,59.408L194.259,58.257L195.411,57.996L195.672,59.148Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.432,57.848L200.28,58.108L200.019,56.956L201.17,56.696L201.432,57.848Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.194,64.999L174.042,65.259L173.78,64.108L174.932,63.847L175.194,64.999Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.344,64.737L175.192,64.998L174.931,63.846L176.084,63.585L176.344,64.737Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.649,64.216L177.497,64.478L177.235,63.326L178.388,63.064L178.649,64.216Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.105,63.43L180.953,63.691L180.691,62.539L181.845,62.278L182.105,63.43Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.409,62.908L183.258,63.17L182.996,62.018L184.149,61.756L184.409,62.908Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.563,62.651L184.411,62.911L184.149,61.76L185.303,61.499L185.563,62.651Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.865,62.126L186.713,62.387L186.451,61.236L187.604,60.974L187.865,62.126Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.387,59.519L198.235,59.78L197.974,58.628L199.127,58.367L199.387,59.519Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.54,59.257L199.388,59.517L199.127,58.365L200.279,58.105L200.54,59.257Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.607,65.887L175.455,66.147L175.193,64.996L176.345,64.735L176.607,65.887Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.062,65.105L178.91,65.365L178.648,64.213L179.802,63.953L180.062,65.105Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.213,64.846L180.061,65.108L179.8,63.956L180.953,63.694L181.213,64.846Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.823,63.802L184.671,64.063L184.409,62.911L185.562,62.65L185.823,63.802Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.734,62.235L191.582,62.496L191.32,61.345L192.473,61.083L192.734,62.235Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.038,61.711L193.886,61.971L193.625,60.819L194.778,60.559L195.038,61.711Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.192,61.452L195.04,61.714L194.778,60.562L195.93,60.3L196.192,61.452Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.493,60.932L197.341,61.194L197.08,60.042L198.233,59.78L198.493,60.932Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.713,67.301L174.561,67.563L174.3,66.411L175.453,66.149L175.713,67.301Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.02,66.78L176.868,67.042L176.606,65.89L177.758,65.628L178.02,66.78Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.171,66.52L178.019,66.781L177.758,65.63L178.911,65.368L179.171,66.52Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.627,65.734L181.475,65.996L181.214,64.844L182.367,64.583L182.627,65.734Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.085,64.953L184.933,65.213L184.672,64.062L185.824,63.801L186.085,64.953Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.236,64.69L186.084,64.951L185.822,63.799L186.974,63.538L187.236,64.69Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.54,64.169L188.388,64.43L188.127,63.278L189.279,63.017L189.54,64.169Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.845,63.65L190.693,63.91L190.432,62.758L191.584,62.498L191.845,63.65Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.995,63.386L191.843,63.648L191.582,62.496L192.734,62.234L192.995,63.386Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.605,62.341L196.453,62.602L196.191,61.451L197.343,61.189L197.605,62.341Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.756,62.087L197.604,62.347L197.343,61.196L198.495,60.935L198.756,62.087Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.498,65.844L186.346,66.104L186.085,64.954L187.238,64.692L187.498,65.844Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.8,65.32L188.648,65.581L188.387,64.429L189.54,64.168L189.8,65.32Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.953,65.066L189.801,65.326L189.54,64.174L190.692,63.914L190.953,65.066Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.409,64.279L193.258,64.54L192.996,63.389L194.148,63.127L194.409,64.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.56,64.017L194.408,64.277L194.146,63.126L195.3,62.865L195.56,64.017Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.172,62.972L199.02,63.232L198.759,62.081L199.911,61.82L200.172,62.972Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.474,62.455L201.322,62.715L201.061,61.564L202.212,61.303L202.474,62.455Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.453,67.52L184.301,67.78L184.04,66.628L185.193,66.368L185.453,67.52Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.605,67.258L185.453,67.519L185.191,66.367L186.343,66.106L186.605,67.258Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.213,66.213L190.061,66.474L189.8,65.322L190.953,65.061L191.213,66.213Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.364,65.95L191.213,66.21L190.951,65.06L192.103,64.798L192.364,65.95Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.671,65.434L193.519,65.694L193.258,64.543L194.411,64.282L194.671,65.434Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.127,64.647L196.975,64.908L196.714,63.756L197.866,63.495L198.127,64.647Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.432,64.126L199.28,64.387L199.019,63.236L200.172,62.974L200.432,64.126Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.476,67.367L190.324,67.627L190.062,66.477L191.214,66.215L191.476,67.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.979,69.822L184.827,70.082L184.565,68.932L185.719,68.67L185.979,69.822Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.127,69.56L185.975,69.821L185.714,68.669L186.866,68.408L187.127,69.56Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.434,69.042L188.282,69.303L188.021,68.151L189.174,67.89L189.434,69.042Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.889,68.255L191.737,68.516L191.476,67.365L192.627,67.103L192.889,68.255Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.04,67.997L192.888,68.258L192.627,67.107L193.78,66.845L194.04,67.997Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.192,67.735L194.04,67.995L193.778,66.844L194.931,66.583L195.192,67.735Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.495,67.211L196.343,67.472L196.082,66.32L197.235,66.059L197.495,67.211Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.951,66.431L199.799,66.691L199.538,65.541L200.691,65.279L200.951,66.431Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M203.256,65.908L202.104,66.168L201.843,65.017L202.996,64.756L203.256,65.908Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.236,70.976L185.084,71.237L184.822,70.085L185.974,69.824L186.236,70.976Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.845,69.931L189.693,70.192L189.432,69.041L190.585,68.779L190.845,69.931Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.996,69.673L190.844,69.933L190.583,68.782L191.735,68.521L191.996,69.673Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.454,68.886L194.302,69.146L194.041,67.995L195.194,67.734L195.454,68.886Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.65,71.865L186.498,72.126L186.236,70.975L187.388,70.713L187.65,71.865Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.954,71.343L188.802,71.604L188.541,70.452L189.693,70.191L189.954,71.343Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.412,70.561L192.26,70.822L191.999,69.671L193.151,69.409L193.412,70.561Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.561,70.303L193.409,70.563L193.147,69.412L194.301,69.151L194.561,70.303Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.019,69.516L196.867,69.777L196.605,68.625L197.759,68.364L198.019,69.516Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.321,68.994L199.169,69.256L198.907,68.104L200.06,67.842L200.321,68.994Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.127,70.933L195.975,71.194L195.714,70.042L196.867,69.781L197.127,70.933Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.735,69.888L200.583,70.149L200.321,68.997L201.474,68.736L201.735,69.888Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.887,69.625L201.735,69.885L201.474,68.734L202.627,68.473L202.887,69.625Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M204.04,69.363L202.888,69.623L202.627,68.471L203.779,68.211L204.04,69.363Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.021,74.428L185.869,74.69L185.607,73.538L186.761,73.276L187.021,74.428Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.169,74.17L187.017,74.43L186.756,73.28L187.908,73.018L188.169,74.17Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.476,73.649L189.324,73.909L189.062,72.759L190.214,72.497L190.476,73.649Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.845,71.3L199.693,71.56L199.432,70.409L200.585,70.148L200.845,71.3Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.996,71.039L200.844,71.3L200.583,70.148L201.735,69.887L201.996,71.039Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.583,75.058L188.431,75.318L188.17,74.168L189.322,73.906L189.583,75.058Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.89,74.542L190.738,74.802L190.477,73.651L191.628,73.39L191.89,74.542Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.499,73.497L195.347,73.757L195.086,72.606L196.239,72.345L196.499,73.497Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M204.561,71.669L203.409,71.93L203.147,70.779L204.299,70.518L204.561,71.669Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M243.628,67.332L241.795,67.323L243.628,67.332Z" + android:fillColor="#FF395A" + android:fillType="evenOdd"/> + <path + android:pathData="M135.28,81.031C134.739,89.726 127.334,96.329 118.762,95.805C110.19,95.281 103.658,87.826 104.199,79.132C104.74,70.438 112.145,63.834 120.717,64.358C129.289,64.882 135.821,72.337 135.28,81.031Z" + android:strokeAlpha="0.36" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.36"/> + <path + android:pathData="M139.979,81.1C139.287,92.093 129.815,100.442 118.851,99.78C107.887,99.118 99.533,89.692 100.225,78.699C100.916,67.706 110.388,59.357 121.352,60.02C132.316,60.682 140.671,70.107 139.979,81.1Z" + android:strokeAlpha="0.14" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.14"/> + <path + android:pathData="M143.773,81.245C142.947,94.387 131.623,104.367 118.516,103.576C105.409,102.784 95.422,91.516 96.249,78.374C97.076,65.233 108.399,55.252 121.506,56.044C134.613,56.835 144.6,68.103 143.773,81.245Z" + android:strokeAlpha="0.04" + android:strokeWidth="4" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.04"/> + <path + android:pathData="M131.305,80.78C130.911,87.179 125.527,92.033 119.3,91.648C113.074,91.263 108.324,85.783 108.717,79.383C109.11,72.984 114.495,68.13 120.722,68.515C126.948,68.9 131.698,74.38 131.305,80.78Z" + android:strokeAlpha="0.5" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.5"/> + <path + android:pathData="M126.967,80.325C126.721,84.229 123.357,87.183 119.476,86.948C115.595,86.714 112.627,83.379 112.873,79.475C113.119,75.571 116.483,72.617 120.364,72.851C124.245,73.085 127.213,76.421 126.967,80.325Z" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1"/> + <path + android:pathData="M92.074,43.754L91.39,50.58L89.997,51.682L88.605,52.508L90.554,56.638L101.412,56.914L100.02,52.508L100.299,50.305L99.449,49.936C98.767,49.638 98.288,49.013 98.188,48.281L97.567,43.751H92.074V43.754Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M100.831,38.97C100.255,50.106 89.021,48.113 89.297,36.927C89.87,25.791 101.107,27.782 100.831,38.97Z" + android:fillColor="#F6B893"/> + <path + android:strokeWidth="1" + android:pathData="M100.074,40.111C97.427,40.949 94.402,41.683 88.731,40.111C87.943,40.984 87.597,43.57 90.621,44.828C93.646,46.086 97.238,45.352 98.656,44.828C100.231,42.906 102.72,39.272 100.074,40.111Z" + android:fillColor="#ffffff" + android:strokeColor="#ffffff"/> + <path + android:pathData="M86.378,81.697C81.645,100.422 86.188,127.328 87.653,148.923L91.088,149.033C91.088,149.033 93.059,113.915 93.895,105.929C94.148,103.503 94.978,98.318 95.401,96.063C95.434,95.892 95.799,95.146 95.843,96.016C96.122,101.523 98.627,107.582 99.184,113.64C100.484,127.797 100.198,137.652 100.763,149.336C100.763,149.336 104.747,151.666 104.752,151.641C105.585,148.381 107.815,121.521 107.815,117.495C107.815,116.669 108.901,99.466 104.474,81.972L86.378,81.697Z" + android:fillColor="#8C8C98"/> + <path + android:pathData="M77.27,76.464C79.358,79.768 81.176,78 86.179,74.536C86.419,74.371 86.658,74.198 86.906,74.024C86.828,77.351 86.672,80.349 86.38,81.696C85.706,84.81 105.311,84.725 104.754,82.522C103.574,77.857 103.084,69.304 103.084,62.695C102,59 104.754,70.243 119,81.696C120.23,84.34 121.049,78.658 121,78C112,70.004 105.219,51.742 103.5,51C103.378,50.948 99.997,49.865 100,50C100.072,52.47 97.457,56.359 96.121,56.359C93.615,56.359 89.439,52.779 88.86,49.888C82.899,51.609 81.129,58.306 79.973,62.417C78.581,67.377 76.196,74.765 77.27,76.464ZM84.066,70.004C84.261,69.527 84.623,68.494 85.266,66.275L86.588,61.701C86.647,61.497 86.95,61.536 86.953,61.748C86.97,63.334 87.276,64.785 87.254,67.924C85.856,69.049 84.779,70.07 84.303,70.243C84.149,70.301 84.005,70.152 84.066,70.004Z" + android:fillColor="#C66A61"/> + <path + android:pathData="M116.001,84.476C115.981,84.92 116.391,85.259 116.832,85.198C118.008,85.026 120.322,84.279 120.426,84.307C121.179,84.605 123.324,75.372 123.467,74.83C123.509,74.67 123.462,74.493 123.279,74.274C123.099,74.058 122.813,73.963 122.538,74.013C121.864,74.14 120.033,74.468 119.275,74.628C118.727,74.743 118.668,74.763 118.511,75.375C117.983,77.422 116.026,84.015 116.003,84.465C116.001,84.467 116.001,84.473 116.001,84.476Z" + android:fillColor="#4A4A4A" + android:fillType="evenOdd"/> + <path + android:pathData="M122.549,78.938C122.17,78.618 121.878,79.96 121.246,80.078C120.971,80.129 120.69,80.216 120.426,80.337C119.775,80.631 119.289,81.204 119.025,81.87C117.211,86.461 125.624,84.658 122.549,78.938Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M91.185,147.379L87.491,146.961C87.385,147.902 86.098,149.439 86.808,153.093C86.864,153.385 86.934,156.163 87.028,156.464C87.115,156.742 88.326,157.147 88.326,156.871C88.326,156.593 87.98,153.162 88.604,154.393C88.882,154.944 88.882,156.871 90.274,157.973C91.864,159.231 96.873,159.636 95.007,157.422C92.223,154.117 91.391,148.877 91.174,147.721" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M100.72,147.561C100.72,147.561 100.662,149.378 100.297,150.816C100.018,151.917 99.74,155.221 100.854,157.975H102.524C102.524,157.975 101.967,154.946 102.246,153.294C102.321,152.853 102.524,155.221 104.195,157.149C104.963,158.036 105.653,158.157 105.979,158.193C106.578,158.259 110.13,158.251 110.319,158.251C110.876,158.251 111.433,157.149 109.197,156.172C108.599,155.91 107.853,155.409 107.257,154.671C106.244,153.418 105.779,151.297 105.222,148.268L100.72,147.561Z" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M91.654,66.928L92.789,67.766C97.695,66.048 100.48,57.413 93.76,61.002C92.22,62.462 91.447,64.464 90.578,66.017" + android:fillColor="#F6B893"/> + <path + android:pathData="M102.844,51.623C102.452,51.329 102.129,51.114 101.689,50.858C101.179,50.56 100.82,50.398 100.258,50.164C100.213,50.145 100.11,50.164 100.08,50.222C99.606,50.106 99.231,49.897 98.838,49.536C98.011,48.776 97.482,47.427 97.761,46.05C97.911,45.306 98.201,44.998 98.359,44.808C101.937,40.542 99.581,33.754 99.581,33.754C99.581,33.754 97.571,37.946 89.988,40.815C89.988,40.815 90.302,42.765 91.416,44.141C91.496,44.243 92.332,44.99 92.362,46.16C92.39,47.308 92.393,48.47 91.6,50.23C90.633,52.378 88.175,52.896 86.31,52.158C84.918,51.607 84.361,50.23 84.297,48.872C84.297,48.872 88.091,49.093 87.198,44.902C86.53,41.751 85.733,34.87 88.877,30.891C88.921,30.836 88.966,30.78 89.01,30.725C89.041,30.684 89.077,30.643 89.113,30.604C89.177,30.53 89.244,30.455 89.311,30.384C89.375,30.318 89.439,30.252 89.503,30.186C90.489,29.197 91.786,28.454 93.481,28.09C93.481,28.09 99.952,27.209 101.065,30.959C101.065,30.959 102.85,31.843 103.075,35.153C103.298,38.463 102.738,39.675 102.627,42.214C102.493,45.301 102.404,48.393 105.751,49.054C105.756,49.049 105.873,50.734 102.844,51.623Z" + android:fillColor="#4A4A4A"/> + <group> + <clip-path + android:pathData="M156.012,28.116h103.79v104.24h-103.79z"/> + <path + android:pathData="M254.581,43.976H197.361V132.356H254.581V43.976Z" + android:fillColor="#94A1AB"/> + <path + android:pathData="M221.211,77.406H207.681C207.002,77.406 206.451,77.957 206.451,78.636V90.166C206.451,90.845 207.002,91.396 207.681,91.396H221.211C221.89,91.396 222.441,90.845 222.441,90.166V78.636C222.441,77.957 221.89,77.406 221.211,77.406Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M244.091,77.306H230.561C229.882,77.306 229.331,77.857 229.331,78.536V90.066C229.331,90.745 229.882,91.296 230.561,91.296H244.091C244.77,91.296 245.321,90.745 245.321,90.066V78.536C245.321,77.857 244.77,77.306 244.091,77.306Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M221.291,53.776H207.761C207.082,53.776 206.531,54.327 206.531,55.006V66.536C206.531,67.215 207.082,67.766 207.761,67.766H221.291C221.971,67.766 222.521,67.215 222.521,66.536V55.006C222.521,54.327 221.971,53.776 221.291,53.776Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M244.171,53.666H230.641C229.962,53.666 229.411,54.217 229.411,54.896V66.426C229.411,67.105 229.962,67.656 230.641,67.656H244.171C244.85,67.656 245.401,67.105 245.401,66.426V54.896C245.401,54.217 244.85,53.666 244.171,53.666Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M201.641,131.116C203.301,129.266 204.481,126.376 203.531,120.366C202.581,114.356 201.801,112.986 200.301,112.746C198.801,112.506 197.851,113.466 197.461,115.556C197.071,117.646 197.141,119.726 196.461,120.556C195.781,121.386 192.201,125.846 194.251,129.696C196.301,133.546 199.781,132.506 201.591,131.146" + android:fillColor="#B8E0FA" + android:fillType="evenOdd"/> + <path + android:pathData="M197.482,132.356C198.506,129.729 199.263,127.005 199.742,124.226C200.218,121.814 200.399,119.352 200.282,116.896H200.092C200.201,119.336 200.016,121.78 199.542,124.176C199.069,126.941 198.318,129.652 197.302,132.266L197.482,132.356Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M199.121,126.976C199.011,127.116 201.911,125.206 202.461,123.316L202.271,123.256C201.741,125.076 199.131,126.736 199.121,126.736V126.976Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M198.211,130.416C197.295,129.178 196.617,127.781 196.211,126.296H196.041C196.434,127.814 197.113,129.243 198.041,130.506L198.211,130.416Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M191.801,101.476C190.141,101.476 189.191,103.876 189.111,104.996C188.781,109.796 185.841,113.216 186.111,120.686C186.281,125.586 188.001,130.616 189.811,131.496C193.311,133.186 195.651,129.416 196.051,125.886C196.707,120.797 196.018,115.625 194.051,110.886C192.601,107.326 195.051,101.436 191.761,101.516" + android:fillColor="#B8E0FA" + android:fillType="evenOdd"/> + <path + android:pathData="M191.671,132.116C190.967,127.077 190.633,121.994 190.671,116.906C190.61,112.654 190.945,108.406 191.671,104.216H191.861C191.14,108.397 190.805,112.634 190.861,116.876C190.822,121.951 191.157,127.021 191.861,132.046L191.671,132.116Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M190.852,123.726C191.898,122.054 192.782,120.286 193.492,118.446H193.682C192.969,120.319 192.075,122.118 191.012,123.816L190.852,123.726Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M190.671,115.246C190.671,115.246 188.671,112.906 188.831,111.166H189.011C188.891,112.846 190.801,115.116 190.801,115.116L190.671,115.246Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M257.242,35.446H194.702C193.288,35.446 192.142,36.592 192.142,38.006V42.886C192.142,44.3 193.288,45.446 194.702,45.446H257.242C258.655,45.446 259.802,44.3 259.802,42.886V38.006C259.802,36.592 258.655,35.446 257.242,35.446Z" + android:fillColor="#C36A61"/> + <path + android:pathData="M209.231,132.356V104.396H225.961V132.356" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M226.961,132.356V104.396H243.701V132.356" + android:fillColor="#D8ECF9"/> + </group> + <path + android:pathData="M46.923,87.397C46.526,93.788 41.083,98.641 34.783,98.256C28.483,97.871 23.682,92.392 24.08,86.002C24.477,79.611 29.92,74.758 36.22,75.143C42.52,75.528 47.321,81.007 46.923,87.397Z" + android:strokeAlpha="0.36" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.36"/> + <path + android:pathData="M50.377,87.449C49.869,95.529 42.907,101.665 34.849,101.178C26.79,100.692 20.65,93.764 21.158,85.684C21.667,77.604 28.628,71.468 36.687,71.955C44.745,72.441 50.885,79.369 50.377,87.449Z" + android:strokeAlpha="0.14" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.14"/> + <path + android:pathData="M53.166,87.554C52.558,97.213 44.236,104.549 34.602,103.967C24.969,103.385 17.629,95.104 18.236,85.445C18.844,75.786 27.167,68.45 36.8,69.032C46.433,69.614 53.774,77.896 53.166,87.554Z" + android:strokeAlpha="0.04" + android:strokeWidth="4" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.04"/> + <path + android:pathData="M44.002,87.212C43.713,91.915 39.755,95.483 35.179,95.2C30.603,94.917 27.111,90.889 27.4,86.186C27.69,81.482 31.647,77.914 36.224,78.197C40.8,78.48 44.291,82.509 44.002,87.212Z" + android:strokeAlpha="0.5" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.5"/> + <path + android:pathData="M40.814,86.878C40.633,89.748 38.16,91.918 35.308,91.746C32.456,91.574 30.274,89.122 30.455,86.253C30.635,83.384 33.108,81.213 35.961,81.385C38.813,81.557 40.995,84.009 40.814,86.878Z" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1"/> + <path + android:pathData="M27.927,81.066C27.927,81.066 30.689,83.651 31.732,84.345C32.597,84.925 35.231,86.138 35.231,86.138L34.225,87.497C34.225,87.497 31.713,86.936 30.945,86.577C30.152,86.211 28.055,84.608 28.055,84.608L27.927,81.066Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M14.811,124.178L13.811,126.074C13.671,126.336 13.769,126.659 14.019,126.806C15.226,127.507 18.519,129.305 19.939,128.817C20.14,128.75 20.189,128.488 20.031,128.348C19.122,127.513 16.299,124.849 16.519,124.197L14.811,124.178Z" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M14.721,124.355L16.647,124.611L26.184,102.598L21.214,92.625L21.159,106.274C21.159,106.274 16.733,115.077 16.025,118.533C15.324,121.941 14.721,124.355 14.721,124.355Z" + android:fillColor="#B96161"/> + <path + android:pathData="M20.903,89.442L28.384,89.54C28.384,89.54 34.871,122.063 37.463,124.258L36.066,125.258C36.066,125.258 28.085,114.382 28.78,107.402C28.786,107.396 18.909,91.534 20.903,89.442Z" + android:fillColor="#C66A61"/> + <path + android:pathData="M26.189,76.926L25.707,73.525C25.707,73.525 27.798,73.616 27.75,70.702C27.743,70.16 27.701,69.239 27.207,68.538L25.292,67.928L24.085,71.794L22.933,76.481L24.969,77.78L26.372,77.743L26.189,76.926Z" + android:fillColor="#F6B893"/> + <path + android:strokeWidth="1" + android:pathData="M27.506,71.183H24.699L24.138,72.305C24.512,72.68 25.373,73.428 25.822,73.428C26.271,73.428 27.506,72.305 27.506,71.183Z" + android:fillColor="#ffffff" + android:strokeColor="#ffffff"/> + <path + android:pathData="M36.072,125.258L36.377,127.373C36.42,127.666 36.682,127.873 36.975,127.842C38.365,127.702 42.084,127.214 42.95,125.989C43.072,125.818 42.956,125.575 42.749,125.55C41.523,125.41 37.676,124.916 37.468,124.258L36.072,125.258Z" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M19.275,93.935L19.799,87.571L22.488,88.339L20.598,94.886C20.598,94.886 20.122,98.684 18.531,97.569C16.555,96.179 19.208,94.716 19.275,93.935Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M25.859,76.915C25.139,77.725 24.335,76.226 22.762,76.634C21.274,77.018 19.945,86.534 19.798,87.577C19.792,87.638 19.786,87.668 19.786,87.668C20.195,88.808 22.06,88.442 22.426,88.357L22.158,89.546L28.389,89.54C30.822,82.81 26.579,76.104 25.859,76.915Z" + android:fillColor="#B1DAEF"/> + <path + android:pathData="M27.75,70.727C27.75,70.727 29.25,69.758 28.256,67.173C28.256,67.173 28.037,66.063 26.482,66.1C26.482,66.1 24.007,63.881 21.677,65.765C19.348,67.648 20.94,69.532 20.94,69.532C20.94,69.532 17.836,72.343 18.909,76.147C18.909,76.147 20.056,78.622 21.385,77.774C22.714,76.927 22.641,78.774 23.342,76.299C24.043,73.824 25.263,74.19 24.781,70.02C24.781,70.02 26.445,70.13 26.811,68.429C26.817,68.429 27.695,68.843 27.75,70.727Z" + android:fillColor="#663014"/> + <path + android:pathData="M33.256,88.449C33.573,88.626 34.768,88.961 35.159,89.04C35.256,89.058 35.494,89.071 35.598,88.882C36.159,87.821 37.835,85.236 37.945,85.084C38.061,84.913 38.049,84.87 37.902,84.773C37.805,84.712 36.464,84.334 36.073,84.218C35.939,84.181 35.823,84.389 35.787,84.437C35.134,85.212 33.366,87.894 33.256,88.065C33.11,88.272 33.128,88.382 33.256,88.449Z" + android:fillColor="#4A4A4A" + android:fillType="evenOdd"/> + <path + android:pathData="M37.012,86.37C37.542,86.26 36.872,87.272 36.609,87.632C36.378,87.961 36.164,88.29 36.006,88.211C35.847,88.132 35.975,87.614 36.176,87.205C36.372,86.797 36.689,86.437 37.012,86.37Z" + android:fillColor="#F6B893"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_shield_illustration.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_shield_illustration.xml new file mode 100644 index 0000000000000000000000000000000000000000..e59b2403978ccb9dc27d57d2f048b3c61c21a1e0 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_shield_illustration.xml @@ -0,0 +1,17 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0" + android:fillColor="#434445"/> + <path + android:strokeWidth="1" + android:pathData="M12.5,19.1877V13.7342L20,10.1293L27.5,13.7342V19.1877C27.5,24.2904 24.2636,29.0038 20,30.2053C15.7364,29.0038 12.5,24.2904 12.5,19.1877Z" + android:fillColor="#00000000" + android:strokeColor="#83D2F2"/> + <path + android:pathData="M12,19.1877C12,24.5231 15.4133,29.5123 20,30.7236V9.5745L12,13.4198V19.1877Z" + android:fillColor="#83D2F2"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml b/Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml deleted file mode 100644 index fea2452990a68326b2ac7ee4a7a73a64725a963c..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml +++ /dev/null @@ -1,11 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="19dp" - android:height="16dp" - android:viewportWidth="19" - android:viewportHeight="16"> - <path - android:pathData="M11.9186,0.7475L10.4286,2.318L14.9685,7.1031H0.9918V9.197H14.9685L10.4286,13.9821L11.9186,15.5526L18.9419,8.15L11.9186,0.7475Z" - android:fillColor="#17191A" - android:fillAlpha="0.6" - android:fillType="evenOdd"/> -</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_rat_profile_create_card_illustration.xml b/Corona-Warn-App/src/main/res/drawable/ic_rat_profile_create_card_illustration.xml index 93abfe013c6cca56dab4a9fd183de8eb77b2a347..a3baedf234504c19a1f669dc78bbfa597cfd9e0e 100644 --- a/Corona-Warn-App/src/main/res/drawable/ic_rat_profile_create_card_illustration.xml +++ b/Corona-Warn-App/src/main/res/drawable/ic_rat_profile_create_card_illustration.xml @@ -10,14 +10,18 @@ <path android:pathData="M0,4C0,1.791 1.791,0 4,0H84C86.209,0 88,1.791 88,4V58C88,60.209 86.209,62 84,62H4C1.791,62 0,60.209 0,58V4Z"> <aapt:attr name="android:fillColor"> - <gradient + <gradient android:startY="4.38621E-7" android:startX="-8.91461" android:endY="76.41" android:endX="74.8561" android:type="linear"> - <item android:offset="0" android:color="#FF599BC4"/> - <item android:offset="1" android:color="#FF29689B"/> + <item + android:offset="0" + android:color="#FF599BC4" /> + <item + android:offset="1" + android:color="#FF29689B" /> </gradient> </aapt:attr> </path> @@ -33,20 +37,21 @@ android:fillColor="#ffffff"/> <path android:pathData="M20,23m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0" - android:fillColor="#ffffff"/> + android:fillColor="#ffffff" /> <group> - <clip-path - android:pathData="M25,20C25,22.75 22.75,25 20,25C17.25,25 15,22.75 15,20C15,17.25 17.25,15 20,15C22.75,15 25,17.25 25,20ZM26.95,28.95C28.8,29.75 30,31.55 30,33.575V35H10V33.575C10,31.55 11.2,29.75 13.05,28.95C15.175,28.025 17.525,27.5 20,27.5C22.475,27.5 24.825,28.025 26.95,28.95Z"/> + <clip-path android:pathData="M25,20C25,22.75 22.75,25 20,25C17.25,25 15,22.75 15,20C15,17.25 17.25,15 20,15C22.75,15 25,17.25 25,20ZM26.95,28.95C28.8,29.75 30,31.55 30,33.575V35H10V33.575C10,31.55 11.2,29.75 13.05,28.95C15.175,28.025 17.525,27.5 20,27.5C22.475,27.5 24.825,28.025 26.95,28.95Z" /> <path android:pathData="M20,23m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0" - android:fillColor="#C4C4C6"/> + android:fillColor="#C4C4C6" /> </group> <path - android:strokeWidth="1" - android:pathData="M75.184,89.565C74.433,89.181 73.819,88.567 73.435,87.816L73.881,87.589C73.637,87.113 73.5,86.573 73.5,86V82.76H73V78.44H73.5V71.96H73V67.64H73.5V61.16H73V56.84H73.5V50.36H73V46.04H73.5V39.56H73V35.24H73.5V32C73.5,31.427 73.637,30.887 73.881,30.411L73.435,30.184C73.819,29.433 74.433,28.819 75.184,28.435L75.411,28.881C75.887,28.637 76.427,28.5 77,28.5H80V28H84V28.5H90V28H94V28.5H100V28H104V28.5H110V28H114V28.5H120V28H124V28.5H130V28H134V28.5H140V28H144V28.5H150V28H154V28.5H157C157.573,28.5 158.113,28.637 158.589,28.881L158.816,28.435C159.567,28.819 160.181,29.433 160.565,30.184L160.119,30.411C160.363,30.887 160.5,31.427 160.5,32V35.24H161V39.56H160.5V46.04H161V50.36H160.5V56.84H161V61.16H160.5V67.64H161V71.96H160.5V78.44H161V82.76H160.5V86C160.5,86.573 160.363,87.113 160.119,87.589L160.565,87.816C160.181,88.567 159.567,89.181 158.816,89.565L158.589,89.119C158.113,89.363 157.573,89.5 157,89.5H154V90H150V89.5H144V90H140V89.5H134V90H130V89.5H124V90H120V89.5H114V90H110V89.5H104V90H100V89.5H94V90H90V89.5H84V90H80V89.5H77C76.427,89.5 75.887,89.363 75.411,89.119L75.184,89.565Z" android:fillColor="#EAF6FE" - android:strokeColor="#007FAD"/> + android:pathData="M73,32C73,29.791 74.791,28 77,28H157C159.209,28 161,29.791 161,32V86C161,88.209 159.209,90 157,90H77C74.791,90 73,88.209 73,86V32Z" /> + <path + android:fillColor="#007FAD" + android:fillType="evenOdd" + android:pathData="M75.184,89.565L75.638,88.674C76.046,88.882 76.508,89 77,89H80V90H77C76.346,90 75.729,89.843 75.184,89.565ZM154,90V89H157C157.492,89 157.954,88.882 158.362,88.674L158.816,89.565C158.271,89.843 157.654,90 157,90H154ZM161,35.24H160V32C160,31.508 159.882,31.046 159.674,30.638L160.565,30.184C160.843,30.729 161,31.346 161,32V35.24ZM80,28H77C76.346,28 75.729,28.157 75.184,28.435L75.638,29.326C76.046,29.118 76.508,29 77,29H80V28ZM73,82.76H74V86C74,86.492 74.118,86.954 74.326,87.362L73.435,87.816C73.157,87.271 73,86.654 73,86V82.76ZM73,78.44H74V71.96H73V78.44ZM73,67.64H74V61.16H73V67.64ZM73,56.84H74V50.36H73V56.84ZM73,46.04H74V39.56H73V46.04ZM73,35.24H74V32C74,31.508 74.118,31.046 74.326,30.638L73.435,30.184C73.157,30.729 73,31.346 73,32V35.24ZM84,28V29H90V28H84ZM94,28V29H100V28H94ZM104,28V29H110V28H104ZM114,28V29H120V28H114ZM124,28V29H130V28H124ZM134,28V29H140V28H134ZM144,28V29H150V28H144ZM154,28V29H157C157.492,29 157.954,29.118 158.362,29.326L158.816,28.435C158.271,28.157 157.654,28 157,28H154ZM161,39.56H160V46.04H161V39.56ZM161,50.36H160V56.84H161V50.36ZM161,61.16H160V67.64H161V61.16ZM161,71.96H160V78.44H161V71.96ZM161,82.76H160V86C160,86.492 159.882,86.954 159.674,87.362L160.565,87.816C160.843,87.271 161,86.654 161,86V82.76ZM150,90V89H144V90H150ZM140,90V89H134V90H140ZM130,90V89H124V90H130ZM120,90V89H114V90H120ZM110,90V89H104V90H110ZM100,90V89H94V90H100ZM90,90V89H84V90H90Z" /> <path android:pathData="M127.333,60.333H119.333V68.333H116.667V60.333H108.667V57.667H116.667V49.667H119.333V57.667H127.333V60.333Z" - android:fillColor="#007FAD"/> + android:fillColor="#007FAD" /> </vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_register_test_illustration.xml b/Corona-Warn-App/src/main/res/drawable/ic_register_test_illustration.xml new file mode 100644 index 0000000000000000000000000000000000000000..0763597ecc3bf0e88e70ae379c101844765a12fe --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_register_test_illustration.xml @@ -0,0 +1,1565 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="260dp" + android:height="159dp" + android:viewportWidth="260" + android:viewportHeight="159"> + <path + android:pathData="M48,26C32,58 21.028,40.688 6,66C-8.549,90.45 10.5,117.218 10.5,117.218L235.781,118.033C235.781,118.033 258.63,81.018 252.678,53.042C248.068,29.225 217.724,13.344 201.977,21.414C161.09,42.24 153.395,12.318 133,6.5C93.589,-4.685 67,0.5 48,26Z" + android:fillColor="#E8F5FF" + android:fillType="evenOdd"/> + <path + android:pathData="M138.908,28.334L214.43,10.899A4,4 121.394,0 1,219.227 13.897L242.355,114.07A4,4 121.394,0 1,239.357 118.867L163.836,136.302A4,4 121.394,0 1,159.038 133.304L135.911,33.131A4,4 121.394,0 1,138.908 28.334z" + android:fillColor="#F5F5F5"/> + <path + android:pathData="M161.342,105.56L229.356,89.858A0.436,0.436 119.383,0 1,229.879 90.185L229.879,90.185A0.436,0.436 119.383,0 1,229.552 90.708L161.538,106.41A0.436,0.436 119.383,0 1,161.015 106.083L161.015,106.083A0.436,0.436 119.383,0 1,161.342 105.56z" + android:fillColor="#657888"/> + <path + android:pathData="M163.039,112.204L213.199,100.624A0.436,0.436 121.396,0 1,213.722 100.951L213.722,100.951A0.436,0.436 121.396,0 1,213.395 101.474L163.235,113.054A0.436,0.436 121.396,0 1,162.712 112.727L162.712,112.727A0.436,0.436 121.396,0 1,163.039 112.204z" + android:fillColor="#657888"/> + <path + android:pathData="M164.918,118.619L225.28,104.684A0.436,0.436 119.383,0 1,225.803 105.011L225.803,105.011A0.436,0.436 119.383,0 1,225.476 105.534L165.114,119.469A0.436,0.436 119.383,0 1,164.591 119.142L164.591,119.142A0.436,0.436 119.383,0 1,164.918 118.619z" + android:fillColor="#657888"/> + <path + android:pathData="M194.25,40.848L193.098,41.11L192.837,39.958L193.99,39.696L194.25,40.848Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.401,40.59L194.249,40.85L193.988,39.699L195.14,39.438L195.401,40.59Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.555,40.328L195.403,40.589L195.142,39.438L196.295,39.176L196.555,40.328Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.706,40.065L196.554,40.325L196.292,39.175L197.444,38.913L197.706,40.065Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.859,39.807L197.707,40.068L197.446,38.916L198.599,38.655L198.859,39.807Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.013,39.544L198.861,39.804L198.6,38.653L199.753,38.392L200.013,39.544Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.161,39.283L200.009,39.544L199.748,38.392L200.9,38.131L201.161,39.283Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.424,40.438L200.272,40.698L200.01,39.548L201.163,39.286L201.424,40.438Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.684,41.588L200.532,41.849L200.271,40.697L201.422,40.437L201.684,41.588Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.944,42.739L200.792,43L200.531,41.849L201.684,41.587L201.944,42.739Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.206,43.89L201.054,44.15L200.793,43L201.946,42.738L202.206,43.89Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.467,45.045L201.315,45.306L201.053,44.154L202.205,43.893L202.467,45.045Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.726,46.196L201.574,46.457L201.313,45.306L202.466,45.044L202.726,46.196Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.783,45.94L172.935,45.678L172.674,44.526L171.522,44.788L171.783,45.94Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M170.631,46.195L171.783,45.935L171.522,44.781L170.371,45.043L170.631,46.195Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M169.482,46.458L170.634,46.196L170.372,45.044L169.22,45.306L169.482,46.458Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M168.328,46.719L169.48,46.459L169.218,45.306L168.066,45.567L168.328,46.719Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M167.173,46.98L168.325,46.719L168.064,45.567L166.913,45.828L167.173,46.98Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M166.024,47.244L167.176,46.983L166.914,45.83L165.762,46.092L166.024,47.244Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M164.871,47.502L166.023,47.24L165.762,46.089L164.611,46.35L164.871,47.502Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.132,48.655L166.284,48.395L166.023,47.242L164.871,47.503L165.132,48.655Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.391,49.803L166.543,49.542L166.282,48.39L165.131,48.651L165.391,49.803Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.654,50.958L166.806,50.698L166.545,49.545L165.393,49.806L165.654,50.958Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M165.915,52.109L167.067,51.848L166.806,50.695L165.655,50.957L165.915,52.109Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M166.173,53.264L167.325,53.002L167.065,51.85L165.913,52.112L166.173,53.264Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M166.437,54.414L167.589,54.153L167.328,53L166.176,53.262L166.437,54.414Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.011,75.12L200.859,75.382L201.119,76.534L202.271,76.272L202.011,75.12Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M203.167,74.862L202.015,75.122L202.277,76.275L203.428,76.014L203.167,74.862Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M204.315,74.603L203.164,74.864L203.425,76.016L204.576,75.755L204.315,74.603Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M205.469,74.341L204.317,74.601L204.578,75.754L205.73,75.493L205.469,74.341Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M206.623,74.08L205.471,74.341L205.732,75.493L206.884,75.231L206.623,74.08Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.771,73.816L206.619,74.077L206.881,75.23L208.031,74.968L207.771,73.816Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.927,73.558L207.775,73.818L208.036,74.972L209.188,74.71L208.927,73.558Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.665,72.404L207.513,72.664L207.774,73.818L208.925,73.556L208.665,72.404Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.402,71.253L207.25,71.515L207.511,72.667L208.663,72.405L208.402,71.253Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M208.145,70.102L206.993,70.362L207.254,71.515L208.405,71.254L208.145,70.102Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.882,68.947L206.73,69.208L206.991,70.36L208.143,70.099L207.882,68.947Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.62,67.796L206.468,68.056L206.729,69.209L207.88,68.948L207.62,67.796Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M207.357,66.642L206.206,66.902L206.467,68.055L207.619,67.794L207.357,66.642Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.546,80.212L180.698,79.951L180.96,81.103L179.808,81.364L179.546,80.212Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.395,80.472L179.547,80.212L179.808,81.364L178.655,81.624L178.395,80.472Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.24,80.732L178.392,80.47L178.653,81.622L177.501,81.883L177.24,80.732Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.091,80.993L177.243,80.733L177.504,81.884L176.351,82.145L176.091,80.993Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.937,81.253L176.089,80.991L176.35,82.143L175.197,82.405L174.937,81.253Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.787,81.514L174.939,81.254L175.2,82.404L174.048,82.666L173.787,81.514Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.635,81.777L173.787,81.515L174.049,82.667L172.895,82.929L172.635,81.777Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.373,80.621L173.524,80.361L173.786,81.511L172.634,81.773L172.373,80.621Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.113,79.47L173.265,79.209L173.526,80.361L172.373,80.622L172.113,79.47Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.853,78.317L173.004,78.056L173.266,79.207L172.114,79.469L171.853,78.317Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.591,77.168L172.743,76.908L173.004,78.058L171.851,78.32L171.591,77.168Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.331,76.016L172.482,75.755L172.744,76.907L171.592,77.168L171.331,76.016Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.068,74.863L172.22,74.603L172.482,75.754L171.329,76.015L171.068,74.863Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.014,47.932L179.862,48.194L179.601,47.042L180.754,46.78L181.014,47.932Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.472,47.15L183.32,47.41L183.059,46.26L184.212,45.998L184.472,47.15Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.43,48.826L181.278,49.087L181.017,47.935L182.17,47.674L182.43,48.826Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.888,48.039L184.736,48.301L184.475,47.149L185.628,46.887L185.888,48.039Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.19,47.522L187.038,47.784L186.777,46.632L187.93,46.37L188.19,47.522Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.844,49.714L182.692,49.974L182.43,48.822L183.583,48.562L183.844,49.714Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.45,48.673L187.299,48.933L187.037,47.783L188.189,47.521L188.45,48.673Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.802,51.389L180.65,51.651L180.388,50.499L181.54,50.237L181.802,51.389Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.106,50.868L182.954,51.13L182.692,49.978L183.844,49.717L184.106,50.868Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.408,50.345L185.256,50.606L184.995,49.454L186.148,49.193L186.408,50.345Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.561,50.086L186.409,50.346L186.147,49.195L187.299,48.934L187.561,50.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.059,52.54L180.907,52.8L180.646,51.65L181.799,51.388L182.059,52.54Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.213,52.279L182.061,52.541L181.799,51.389L182.951,51.127L183.213,52.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.474,53.431L182.322,53.692L182.061,52.541L183.214,52.279L183.474,53.431Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.626,53.17L183.474,53.431L183.212,52.28L184.364,52.018L184.626,53.17Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.084,52.391L186.932,52.652L186.67,51.501L187.822,51.239L188.084,52.391Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.232,52.128L188.08,52.389L187.819,51.237L188.972,50.976L189.232,52.128Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.584,54.845L181.432,55.105L181.17,53.955L182.324,53.694L182.584,54.845Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.037,54.062L184.885,54.322L184.624,53.17L185.775,52.91L186.037,54.062Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.844,56L181.692,56.26L181.43,55.108L182.582,54.848L182.844,56Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.994,55.737L182.842,55.999L182.581,54.847L183.734,54.585L183.994,55.737Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.299,55.213L185.147,55.475L184.886,54.323L186.039,54.062L186.299,55.213Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.604,54.693L187.452,54.954L187.19,53.802L188.342,53.541L188.604,54.693Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.755,54.431L188.603,54.691L188.342,53.54L189.495,53.279L189.755,54.431Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.235,45.847L189.083,46.107L188.821,44.956L189.974,44.695L190.235,45.847Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.497,46.998L189.345,47.26L189.083,46.108L190.235,45.846L190.497,46.998Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.757,48.152L189.605,48.412L189.344,47.262L190.497,47L190.757,48.152Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.061,47.628L191.909,47.888L191.648,46.738L192.801,46.476L193.061,47.628Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.215,47.366L193.063,47.627L192.802,46.475L193.954,46.214L194.215,47.366Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.364,47.107L194.212,47.367L193.951,46.216L195.104,45.955L195.364,47.107Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.517,46.845L195.365,47.106L195.104,45.954L196.257,45.693L196.517,46.845Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.017,49.3L189.865,49.562L189.604,48.41L190.755,48.148L191.017,49.3Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.324,48.783L192.172,49.044L191.911,47.892L193.063,47.631L193.324,48.783Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.475,48.519L193.323,48.779L193.062,47.629L194.215,47.367L194.475,48.519Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.626,48.258L194.474,48.519L194.212,47.368L195.364,47.106L195.626,48.258Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.777,47.995L195.625,48.255L195.363,47.104L196.515,46.843L196.777,47.995Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.279,50.453L190.127,50.713L189.866,49.562L191.019,49.301L191.279,50.453Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.581,49.934L192.429,50.195L192.168,49.043L193.321,48.782L193.581,49.934Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.735,49.671L193.583,49.932L193.321,48.78L194.473,48.52L194.735,49.671Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.886,49.412L194.734,49.674L194.473,48.522L195.626,48.261L195.886,49.412Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.039,49.15L195.887,49.41L195.626,48.258L196.779,47.998L197.039,49.15Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.539,51.605L190.387,51.865L190.126,50.713L191.279,50.453L191.539,51.605Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.844,51.084L192.692,51.344L192.431,50.194L193.583,49.932L193.844,51.084Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.995,50.822L193.843,51.083L193.582,49.931L194.735,49.67L194.995,50.822Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.146,50.564L194.994,50.824L194.732,49.674L195.884,49.412L196.146,50.564Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.297,50.301L196.145,50.563L195.884,49.411L197.037,49.149L197.297,50.301Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.802,52.759L190.65,53.02L190.388,51.868L191.54,51.607L191.802,52.759Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.386,45.584L190.234,45.846L189.973,44.694L191.125,44.432L191.386,45.584Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.537,45.322L191.385,45.583L191.124,44.431L192.277,44.171L192.537,45.322Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.69,45.061L192.538,45.322L192.276,44.17L193.428,43.909L193.69,45.061Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.843,44.802L193.692,45.063L193.43,43.912L194.582,43.651L194.843,44.802Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.995,44.543L194.843,44.805L194.582,43.653L195.735,43.392L195.995,44.543Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.146,44.28L195.994,44.54L195.732,43.39L196.884,43.128L197.146,44.28Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.297,44.019L197.145,44.281L196.883,43.129L198.036,42.868L198.297,44.019Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.559,45.174L197.407,45.434L197.146,44.283L198.298,44.022L198.559,45.174Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.822,46.325L197.67,46.585L197.409,45.433L198.562,45.173L198.822,46.325Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.082,47.474L197.93,47.735L197.668,46.583L198.82,46.322L199.082,47.474Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.341,48.626L198.189,48.886L197.928,47.736L199.081,47.474L199.341,48.626Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.604,49.78L198.452,50.042L198.19,48.89L199.342,48.628L199.604,49.78Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.864,50.931L198.712,51.192L198.451,50.041L199.604,49.779L199.864,50.931Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.062,53.91L190.91,54.17L190.648,53.02L191.802,52.758L192.062,53.91Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.213,53.652L192.061,53.914L191.8,52.762L192.953,52.5L193.213,53.652Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.364,53.389L193.212,53.649L192.95,52.498L194.102,52.237L194.364,53.389Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.517,53.128L194.365,53.389L194.104,52.237L195.257,51.976L195.517,53.128Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.671,52.866L195.519,53.126L195.257,51.975L196.409,51.714L196.671,52.866Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.822,52.603L196.67,52.864L196.408,51.712L197.561,51.451L197.822,52.603Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.975,52.345L197.823,52.605L197.562,51.454L198.715,51.193L198.975,52.345Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.124,52.086L198.972,52.346L198.71,51.194L199.862,50.934L200.124,52.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M170.65,50.281L169.498,50.541L169.236,49.389L170.388,49.129L170.65,50.281Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.801,50.02L170.649,50.281L170.388,49.13L171.541,48.868L171.801,50.02Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.952,49.757L171.8,50.017L171.539,48.865L172.692,48.605L172.952,49.757Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.103,49.499L172.951,49.76L172.69,48.608L173.842,48.347L174.103,49.499Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.257,49.241L174.105,49.501L173.843,48.349L174.996,48.089L175.257,49.241Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.41,48.978L175.258,49.24L174.997,48.088L176.148,47.826L176.41,48.978Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.561,48.717L176.409,48.977L176.148,47.826L177.301,47.565L177.561,48.717Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.712,48.453L177.56,48.715L177.299,47.563L178.452,47.302L178.712,48.453Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M170.91,51.432L169.758,51.694L169.497,50.542L170.65,50.28L170.91,51.432Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.974,49.608L177.822,49.868L177.561,48.718L178.713,48.456L178.974,49.608Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.172,52.587L170.02,52.847L169.759,51.696L170.911,51.435L171.172,52.587Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.472,52.063L172.32,52.323L172.059,51.172L173.212,50.911L173.472,52.063Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.628,51.805L173.476,52.066L173.214,50.914L174.366,50.653L174.628,51.805Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.779,51.542L174.627,51.802L174.366,50.651L175.519,50.39L175.779,51.542Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.93,51.28L175.778,51.541L175.517,50.389L176.669,50.128L176.93,51.28Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.235,50.759L178.083,51.021L177.821,49.869L178.974,49.607L179.235,50.759Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.432,53.738L170.28,53.999L170.019,52.847L171.172,52.586L171.432,53.738Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.734,53.216L172.582,53.478L172.321,52.326L173.474,52.064L173.734,53.216Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.888,52.956L173.736,53.216L173.475,52.065L174.628,51.804L174.888,52.956Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.041,52.693L174.889,52.954L174.628,51.802L175.78,51.541L176.041,52.693Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.192,52.435L176.04,52.695L175.779,51.544L176.932,51.283L177.192,52.435Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.494,51.91L178.342,52.172L178.081,51.02L179.233,50.758L179.494,51.91Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.692,54.889L170.54,55.149L170.278,53.999L171.43,53.737L171.692,54.889Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.997,54.364L172.845,54.624L172.583,53.473L173.735,53.212L173.997,54.364Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.15,54.11L173.998,54.37L173.736,53.218L174.888,52.958L175.15,54.11Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.299,53.847L175.147,54.109L174.885,52.957L176.038,52.695L176.299,53.847Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.452,53.585L176.3,53.846L176.039,52.694L177.19,52.434L177.452,53.585Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.757,53.064L178.605,53.325L178.343,52.174L179.496,51.912L179.757,53.064Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M171.954,56.043L170.802,56.303L170.541,55.151L171.694,54.891L171.954,56.043Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.259,55.519L173.107,55.779L172.846,54.627L173.999,54.367L174.259,55.519Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.41,55.258L174.258,55.519L173.997,54.367L175.15,54.106L175.41,55.258Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.561,54.998L175.409,55.258L175.148,54.108L176.3,53.846L176.561,54.998Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.715,54.739L176.563,55.001L176.301,53.849L177.454,53.588L177.715,54.739Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.019,54.215L178.867,54.477L178.606,53.325L179.759,53.064L180.019,54.215Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.215,57.194L171.063,57.456L170.801,56.304L171.953,56.042L172.215,57.194Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.277,55.37L179.125,55.63L178.863,54.48L180.015,54.218L180.277,55.37Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.477,58.349L171.325,58.609L171.063,57.458L172.217,57.197L172.477,58.349Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.628,58.086L172.476,58.347L172.214,57.195L173.366,56.934L173.628,58.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.779,57.824L173.627,58.084L173.365,56.934L174.518,56.672L174.779,57.824Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.933,57.562L174.781,57.824L174.52,56.672L175.671,56.41L175.933,57.562Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.081,57.304L175.929,57.564L175.668,56.414L176.82,56.152L177.081,57.304Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.235,57.04L177.083,57.302L176.821,56.15L177.974,55.889L178.235,57.04Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.39,56.779L178.238,57.04L177.977,55.889L179.129,55.627L179.39,56.779Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.539,56.518L179.387,56.78L179.126,55.628L180.279,55.366L180.539,56.518Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.084,69.868L173.932,70.129L173.67,68.978L174.822,68.716L175.084,69.868Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.235,69.607L175.083,69.868L174.822,68.716L175.975,68.455L176.235,69.607Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.388,69.344L176.237,69.604L175.975,68.453L177.128,68.192L177.388,69.344Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.542,69.086L177.39,69.348L177.128,68.196L178.28,67.934L178.542,69.086Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.691,68.823L178.539,69.083L178.277,67.933L179.43,67.671L179.691,68.823Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.844,68.561L179.692,68.823L179.43,67.671L180.582,67.409L180.844,68.561Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.997,68.298L180.845,68.559L180.584,67.408L181.737,67.146L181.997,68.298Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.149,68.04L181.997,68.302L181.735,67.15L182.888,66.888L183.149,68.04Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.346,71.019L174.194,71.28L173.933,70.129L175.086,69.867L175.346,71.019Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.408,69.191L182.257,69.453L181.995,68.301L183.147,68.039L183.408,69.191Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.606,72.17L174.454,72.43L174.193,71.28L175.345,71.018L175.606,72.17Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.911,71.649L176.759,71.91L176.498,70.759L177.649,70.497L177.911,71.649Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.062,71.391L177.91,71.651L177.649,70.499L178.801,70.239L179.062,71.391Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.215,71.128L179.063,71.39L178.802,70.238L179.955,69.976L180.215,71.128Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.366,70.868L180.215,71.128L179.953,69.976L181.105,69.716L181.366,70.868Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.671,70.346L182.519,70.606L182.257,69.455L183.41,69.194L183.671,70.346Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.866,73.325L174.715,73.585L174.453,72.433L175.606,72.173L175.866,73.325Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.171,72.801L177.019,73.061L176.757,71.909L177.91,71.649L178.171,72.801Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.324,72.538L178.173,72.799L177.911,71.648L179.064,71.386L179.324,72.538Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.473,72.279L179.321,72.539L179.06,71.388L180.211,71.127L180.473,72.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.627,72.016L180.475,72.278L180.213,71.126L181.367,70.865L181.627,72.016Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.931,71.497L182.779,71.758L182.518,70.606L183.671,70.345L183.931,71.497Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.129,74.476L174.977,74.737L174.715,73.585L175.867,73.324L176.129,74.476Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.433,73.954L177.281,74.216L177.02,73.064L178.171,72.803L178.433,73.954Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.584,73.692L178.432,73.952L178.171,72.802L179.324,72.54L179.584,73.692Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.735,73.43L179.583,73.692L179.322,72.54L180.475,72.278L180.735,73.43Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.888,73.168L180.737,73.428L180.475,72.277L181.627,72.016L181.888,73.168Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.191,72.652L183.039,72.912L182.777,71.761L183.929,71.5L184.191,72.652Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.391,75.63L175.239,75.89L174.978,74.74L176.131,74.478L176.391,75.63Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.691,75.106L177.539,75.366L177.277,74.216L178.43,73.954L178.691,75.106Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.844,74.844L178.693,75.105L178.431,73.953L179.583,73.692L179.844,74.844Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.998,74.585L179.846,74.845L179.584,73.695L180.736,73.433L180.998,74.585Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.149,74.322L180.997,74.583L180.735,73.432L181.888,73.17L182.149,74.322Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.451,73.798L183.299,74.059L183.038,72.907L184.191,72.646L184.451,73.798Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.649,76.777L175.497,77.038L175.235,75.886L176.387,75.625L176.649,76.777Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.713,74.952L183.561,75.213L183.3,74.061L184.452,73.8L184.713,74.952Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.911,77.931L175.759,78.191L175.498,77.04L176.651,76.779L176.911,77.931Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.062,77.669L176.91,77.93L176.648,76.778L177.8,76.518L178.062,77.669Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.216,77.407L178.064,77.668L177.802,76.517L178.955,76.255L179.216,77.407Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.366,77.149L179.215,77.409L178.953,76.257L180.105,75.997L180.366,77.149Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.517,76.89L180.365,77.151L180.104,76L181.257,75.738L181.517,76.89Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.671,76.628L181.519,76.888L181.258,75.736L182.411,75.476L182.671,76.628Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.822,76.367L182.67,76.628L182.409,75.476L183.561,75.215L183.822,76.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.975,76.104L183.823,76.364L183.562,75.213L184.715,74.952L184.975,76.104Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.408,56.631L184.256,56.892L183.995,55.74L185.148,55.479L185.408,56.631Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.562,56.367L185.41,56.628L185.148,55.477L186.3,55.216L186.562,56.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.713,56.106L186.561,56.368L186.299,55.216L187.452,54.954L187.713,56.106Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.017,55.582L188.865,55.843L188.604,54.691L189.755,54.43L190.017,55.582Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M172.997,60.65L171.845,60.91L171.583,59.76L172.737,59.498L172.997,60.65Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.301,60.126L174.15,60.386L173.888,59.236L175.041,58.974L175.301,60.126Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.453,59.867L175.301,60.128L175.04,58.976L176.191,58.716L176.453,59.867Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M177.606,59.609L176.454,59.871L176.192,58.719L177.346,58.457L177.606,59.609Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.911,59.085L178.759,59.346L178.498,58.194L179.649,57.933L179.911,59.085Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.366,58.302L182.214,58.562L181.953,57.412L183.105,57.15L183.366,58.302Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.517,58.04L183.365,58.301L183.104,57.149L184.257,56.888L184.517,58.04Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.671,57.781L184.519,58.041L184.257,56.89L185.409,56.629L185.671,57.781Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.973,57.26L186.821,57.52L186.56,56.37L187.711,56.108L187.973,57.26Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.129,56.997L187.977,57.259L187.715,56.107L188.867,55.846L189.129,56.997Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.277,56.736L189.125,56.996L188.864,55.845L190.017,55.584L190.277,56.736Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.431,56.475L190.279,56.736L190.018,55.585L191.169,55.323L191.431,56.475Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.039,55.433L194.887,55.694L194.626,54.542L195.779,54.282L196.039,55.433Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.495,54.649L198.343,54.91L198.082,53.758L199.234,53.497L199.495,54.649Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.648,54.388L199.496,54.648L199.235,53.498L200.387,53.236L200.648,54.388Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.41,61.539L173.258,61.8L172.997,60.649L174.15,60.387L174.41,61.539Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.715,61.018L175.563,61.279L175.301,60.127L176.454,59.866L176.715,61.018Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.322,59.976L180.17,60.238L179.908,59.086L181.06,58.824L181.322,59.976Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M183.626,59.454L182.474,59.715L182.213,58.563L183.366,58.302L183.626,59.454Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.235,58.412L187.083,58.673L186.821,57.521L187.974,57.26L188.235,58.412Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.539,57.891L189.387,58.151L189.126,56.999L190.278,56.739L190.539,57.891Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.844,57.367L191.692,57.627L191.431,56.475L192.583,56.215L192.844,57.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.302,56.583L195.15,56.845L194.889,55.693L196.041,55.431L196.302,56.583Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.45,56.324L196.299,56.584L196.037,55.434L197.19,55.173L197.45,56.324Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.758,55.8L198.606,56.061L198.344,54.91L199.497,54.648L199.758,55.8Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M173.519,62.955L172.367,63.216L172.106,62.064L173.259,61.803L173.519,62.955Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M174.668,62.693L173.516,62.953L173.255,61.803L174.407,61.541L174.668,62.693Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.823,62.432L174.672,62.694L174.41,61.542L175.563,61.281L175.823,62.432Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.126,61.911L176.974,62.172L176.712,61.02L177.866,60.759L178.126,61.911Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.735,60.87L181.583,61.131L181.322,59.979L182.474,59.718L182.735,60.87Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.039,60.346L183.887,60.607L183.626,59.455L184.779,59.194L185.039,60.346Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.497,59.562L187.345,59.823L187.084,58.671L188.236,58.41L188.497,59.562Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.107,58.521L191.955,58.782L191.693,57.63L192.846,57.369L193.107,58.521Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.408,57.996L194.257,58.257L193.995,57.106L195.148,56.844L195.408,57.996Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.711,57.472L196.559,57.733L196.297,56.581L197.449,56.32L197.711,57.472Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.084,63.585L174.932,63.845L174.67,62.694L175.822,62.433L176.084,63.585Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.844,62.279L180.692,62.54L180.431,61.388L181.583,61.127L181.844,62.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.997,62.02L181.845,62.28L181.584,61.129L182.737,60.868L182.997,62.02Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.151,61.758L182.999,62.018L182.737,60.866L183.889,60.606L184.151,61.758Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.604,60.975L186.452,61.236L186.19,60.084L187.342,59.823L187.604,60.975Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.911,60.451L188.759,60.712L188.498,59.56L189.649,59.299L189.911,60.451Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.06,60.192L189.908,60.452L189.646,59.302L190.798,59.04L191.06,60.192Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.515,59.41L193.363,59.672L193.102,58.52L194.255,58.258L194.515,59.41Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.671,59.148L194.519,59.408L194.258,58.257L195.41,57.996L195.671,59.148Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.431,57.848L200.279,58.108L200.018,56.956L201.17,56.696L201.431,57.848Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.193,64.999L174.041,65.259L173.779,64.108L174.931,63.847L175.193,64.999Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.344,64.737L175.192,64.998L174.93,63.846L176.083,63.585L176.344,64.737Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.648,64.216L177.496,64.478L177.235,63.326L178.388,63.064L178.648,64.216Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.104,63.43L180.952,63.691L180.691,62.539L181.844,62.278L182.104,63.43Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M184.408,62.908L183.257,63.17L182.995,62.018L184.148,61.756L184.408,62.908Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.562,62.651L184.41,62.911L184.149,61.76L185.302,61.499L185.562,62.651Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.864,62.126L186.712,62.387L186.451,61.236L187.604,60.974L187.864,62.126Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M199.386,59.519L198.235,59.78L197.973,58.628L199.126,58.367L199.386,59.519Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.54,59.257L199.388,59.517L199.126,58.365L200.278,58.105L200.54,59.257Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M176.606,65.887L175.454,66.147L175.193,64.996L176.345,64.735L176.606,65.887Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M180.062,65.105L178.91,65.365L178.648,64.213L179.802,63.953L180.062,65.105Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M181.213,64.846L180.061,65.108L179.799,63.956L180.952,63.694L181.213,64.846Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.822,63.802L184.67,64.063L184.409,62.911L185.562,62.65L185.822,63.802Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.733,62.235L191.581,62.496L191.32,61.345L192.473,61.083L192.733,62.235Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.037,61.711L193.885,61.971L193.624,60.819L194.777,60.559L195.037,61.711Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.191,61.452L195.039,61.714L194.778,60.562L195.93,60.3L196.191,61.452Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.493,60.932L197.341,61.194L197.08,60.042L198.233,59.78L198.493,60.932Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M175.713,67.301L174.561,67.563L174.299,66.411L175.452,66.149L175.713,67.301Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M178.019,66.78L176.867,67.042L176.606,65.89L177.758,65.628L178.019,66.78Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M179.171,66.52L178.019,66.781L177.757,65.63L178.91,65.368L179.171,66.52Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M182.626,65.734L181.474,65.996L181.213,64.844L182.366,64.583L182.626,65.734Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.084,64.953L184.932,65.213L184.671,64.062L185.823,63.801L186.084,64.953Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.235,64.69L186.083,64.951L185.822,63.799L186.974,63.538L187.235,64.69Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.54,64.169L188.388,64.43L188.126,63.278L189.278,63.017L189.54,64.169Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.844,63.65L190.693,63.91L190.431,62.758L191.583,62.498L191.844,63.65Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.995,63.386L191.843,63.648L191.582,62.496L192.734,62.234L192.995,63.386Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.604,62.341L196.452,62.602L196.191,61.451L197.343,61.189L197.604,62.341Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.756,62.087L197.604,62.347L197.342,61.196L198.494,60.935L198.756,62.087Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.498,65.844L186.346,66.104L186.084,64.954L187.238,64.692L187.498,65.844Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.8,65.32L188.648,65.581L188.386,64.429L189.539,64.168L189.8,65.32Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.953,65.066L189.801,65.326L189.54,64.174L190.691,63.914L190.953,65.066Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.408,64.279L193.257,64.54L192.995,63.389L194.147,63.127L194.408,64.279Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.56,64.017L194.408,64.277L194.146,63.126L195.3,62.865L195.56,64.017Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.171,62.972L199.019,63.232L198.758,62.081L199.91,61.82L200.171,62.972Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.473,62.455L201.321,62.715L201.06,61.564L202.212,61.303L202.473,62.455Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.453,67.52L184.301,67.78L184.04,66.628L185.193,66.368L185.453,67.52Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.604,67.258L185.452,67.519L185.191,66.367L186.343,66.106L186.604,67.258Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.213,66.213L190.061,66.474L189.8,65.322L190.953,65.061L191.213,66.213Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.364,65.95L191.212,66.21L190.951,65.06L192.103,64.798L192.364,65.95Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.671,65.434L193.519,65.694L193.258,64.543L194.411,64.282L194.671,65.434Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.127,64.647L196.975,64.908L196.713,63.756L197.865,63.495L198.127,64.647Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.431,64.126L199.279,64.387L199.018,63.236L200.171,62.974L200.431,64.126Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.475,67.367L190.323,67.627L190.062,66.477L191.214,66.215L191.475,67.367Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M185.978,69.822L184.826,70.082L184.564,68.932L185.718,68.67L185.978,69.822Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.126,69.56L185.974,69.821L185.713,68.669L186.865,68.408L187.126,69.56Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.434,69.042L188.282,69.303L188.021,68.151L189.174,67.89L189.434,69.042Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M192.889,68.255L191.737,68.516L191.476,67.365L192.627,67.103L192.889,68.255Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.04,67.997L192.888,68.258L192.627,67.107L193.78,66.845L194.04,67.997Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.191,67.735L194.039,67.995L193.778,66.844L194.931,66.583L195.191,67.735Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.495,67.211L196.343,67.472L196.082,66.32L197.235,66.059L197.495,67.211Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.951,66.431L199.799,66.691L199.538,65.541L200.691,65.279L200.951,66.431Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M203.256,65.908L202.104,66.168L201.842,65.017L202.995,64.756L203.256,65.908Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M186.236,70.976L185.084,71.237L184.822,70.085L185.974,69.824L186.236,70.976Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.844,69.931L189.692,70.192L189.431,69.041L190.584,68.779L190.844,69.931Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.995,69.673L190.843,69.933L190.582,68.782L191.734,68.521L191.995,69.673Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M195.453,68.886L194.301,69.146L194.04,67.995L195.193,67.734L195.453,68.886Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.649,71.865L186.497,72.126L186.235,70.975L187.387,70.713L187.649,71.865Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.953,71.343L188.801,71.604L188.54,70.452L189.692,70.191L189.953,71.343Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M193.411,70.561L192.259,70.822L191.998,69.671L193.15,69.409L193.411,70.561Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M194.56,70.303L193.408,70.563L193.146,69.412L194.3,69.151L194.56,70.303Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M198.018,69.516L196.866,69.777L196.604,68.625L197.758,68.364L198.018,69.516Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.32,68.994L199.168,69.256L198.907,68.104L200.06,67.842L200.32,68.994Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M197.127,70.933L195.975,71.194L195.713,70.042L196.867,69.781L197.127,70.933Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.734,69.888L200.582,70.149L200.32,68.997L201.473,68.736L201.734,69.888Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M202.887,69.625L201.735,69.885L201.474,68.734L202.627,68.473L202.887,69.625Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M204.04,69.363L202.888,69.623L202.627,68.471L203.779,68.211L204.04,69.363Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M187.02,74.428L185.868,74.69L185.607,73.538L186.76,73.276L187.02,74.428Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M188.169,74.17L187.017,74.43L186.756,73.28L187.908,73.018L188.169,74.17Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M190.476,73.649L189.324,73.909L189.062,72.759L190.214,72.497L190.476,73.649Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M200.844,71.3L199.693,71.56L199.431,70.409L200.584,70.148L200.844,71.3Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M201.996,71.039L200.844,71.3L200.583,70.148L201.734,69.887L201.996,71.039Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M189.582,75.058L188.43,75.318L188.169,74.168L189.321,73.906L189.582,75.058Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M191.889,74.542L190.737,74.802L190.476,73.651L191.627,73.39L191.889,74.542Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M196.498,73.497L195.346,73.757L195.085,72.606L196.238,72.345L196.498,73.497Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M204.56,71.669L203.408,71.93L203.147,70.779L204.299,70.518L204.56,71.669Z" + android:fillColor="#657888" + android:fillType="evenOdd"/> + <path + android:pathData="M243.628,67.332L241.794,67.323L243.628,67.332Z" + android:fillColor="#FF395A" + android:fillType="evenOdd"/> + <path + android:pathData="M135.28,81.031C134.739,89.726 127.334,96.329 118.762,95.805C110.19,95.281 103.658,87.826 104.199,79.132C104.74,70.438 112.145,63.834 120.717,64.358C129.289,64.882 135.821,72.337 135.28,81.031Z" + android:strokeAlpha="0.36" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.36"/> + <path + android:pathData="M139.979,81.1C139.287,92.093 129.815,100.442 118.851,99.78C107.887,99.118 99.533,89.692 100.225,78.699C100.916,67.706 110.388,59.357 121.352,60.02C132.316,60.682 140.671,70.107 139.979,81.1Z" + android:strokeAlpha="0.14" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.14"/> + <path + android:pathData="M143.773,81.245C142.947,94.387 131.623,104.367 118.516,103.576C105.409,102.784 95.422,91.516 96.249,78.374C97.076,65.233 108.399,55.252 121.506,56.044C134.613,56.835 144.6,68.103 143.773,81.245Z" + android:strokeAlpha="0.04" + android:strokeWidth="4" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.04"/> + <path + android:pathData="M131.305,80.78C130.912,87.179 125.527,92.033 119.301,91.648C113.074,91.263 108.324,85.783 108.718,79.383C109.111,72.984 114.496,68.13 120.722,68.515C126.949,68.9 131.698,74.38 131.305,80.78Z" + android:strokeAlpha="0.5" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.5"/> + <path + android:pathData="M126.968,80.325C126.722,84.229 123.357,87.183 119.477,86.948C115.596,86.714 112.627,83.379 112.873,79.475C113.119,75.571 116.484,72.617 120.364,72.851C124.245,73.085 127.213,76.421 126.968,80.325Z" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1"/> + <path + android:pathData="M92.074,43.754L91.389,50.58L89.997,51.682L88.605,52.508L90.554,56.638L101.412,56.914L100.02,52.508L100.298,50.305L99.449,49.936C98.767,49.638 98.288,49.013 98.188,48.281L97.567,43.751H92.074V43.754Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M100.832,38.97C100.256,50.106 89.022,48.113 89.298,36.927C89.871,25.791 101.107,27.782 100.832,38.97Z" + android:fillColor="#F6B893"/> + <path + android:strokeWidth="1" + android:pathData="M100.074,40.111C97.427,40.949 94.403,41.683 88.731,40.111C87.944,40.984 87.597,43.57 90.622,44.828C93.647,46.086 97.238,45.352 98.656,44.828C100.232,42.906 102.721,39.272 100.074,40.111Z" + android:fillColor="#ffffff" + android:strokeColor="#ffffff"/> + <path + android:pathData="M86.377,81.697C81.644,100.422 86.188,127.328 87.652,148.923L91.088,149.033C91.088,149.033 93.059,113.915 93.894,105.929C94.147,103.503 94.977,98.318 95.4,96.063C95.434,95.892 95.798,95.146 95.843,96.016C96.121,101.523 98.627,107.582 99.184,113.64C100.484,127.797 100.197,137.652 100.762,149.336C100.762,149.336 104.746,151.666 104.752,151.641C105.584,148.381 107.814,121.521 107.814,117.495C107.814,116.669 108.9,99.466 104.473,81.972L86.377,81.697Z" + android:fillColor="#8C8C98"/> + <path + android:pathData="M77.27,76.464C79.358,79.768 81.176,78 86.179,74.536C86.419,74.371 86.658,74.198 86.906,74.024C86.828,77.351 86.672,80.349 86.38,81.696C85.706,84.81 105.311,84.725 104.754,82.522C103.574,77.857 103.084,69.304 103.084,62.695C102,59 104.754,70.243 119,81.696C120.23,84.34 121.049,78.658 121,78C112,70.004 105.219,51.742 103.5,51C103.378,50.948 99.997,49.865 100,50C100.072,52.47 97.457,56.359 96.121,56.359C93.615,56.359 89.439,52.779 88.86,49.888C82.899,51.609 81.129,58.306 79.973,62.417C78.581,67.377 76.196,74.765 77.27,76.464ZM84.066,70.004C84.261,69.527 84.623,68.494 85.266,66.275L86.588,61.701C86.647,61.497 86.95,61.536 86.953,61.748C86.97,63.334 87.276,64.785 87.254,67.924C85.856,69.049 84.779,70.07 84.303,70.243C84.149,70.301 84.005,70.152 84.066,70.004Z" + android:fillColor="#C66A61"/> + <path + android:pathData="M116.001,84.476C115.981,84.92 116.391,85.259 116.832,85.198C118.008,85.026 120.322,84.279 120.426,84.307C121.179,84.605 123.324,75.372 123.467,74.83C123.509,74.67 123.462,74.493 123.279,74.274C123.099,74.058 122.813,73.963 122.538,74.013C121.864,74.14 120.033,74.468 119.275,74.628C118.727,74.743 118.668,74.763 118.511,75.375C117.983,77.422 116.026,84.015 116.003,84.465C116.001,84.467 116.001,84.473 116.001,84.476Z" + android:fillColor="#4A4A4A" + android:fillType="evenOdd"/> + <path + android:pathData="M122.549,78.938C122.17,78.618 121.878,79.96 121.246,80.078C120.971,80.129 120.69,80.216 120.426,80.337C119.775,80.631 119.289,81.204 119.025,81.87C117.211,86.461 125.624,84.658 122.549,78.938Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M91.185,147.379L87.491,146.961C87.385,147.902 86.098,149.439 86.808,153.093C86.864,153.385 86.934,156.163 87.028,156.464C87.115,156.742 88.326,157.147 88.326,156.871C88.326,156.593 87.98,153.162 88.604,154.393C88.882,154.944 88.882,156.871 90.274,157.973C91.864,159.231 96.873,159.636 95.007,157.422C92.223,154.117 91.391,148.877 91.174,147.721" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M100.72,147.561C100.72,147.561 100.662,149.378 100.297,150.816C100.018,151.917 99.74,155.221 100.854,157.975H102.524C102.524,157.975 101.967,154.946 102.246,153.294C102.321,152.853 102.524,155.221 104.195,157.149C104.963,158.036 105.653,158.157 105.979,158.193C106.578,158.259 110.13,158.251 110.319,158.251C110.876,158.251 111.433,157.149 109.197,156.172C108.599,155.91 107.853,155.409 107.257,154.671C106.244,153.418 105.779,151.297 105.222,148.268L100.72,147.561Z" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M91.654,66.928L92.789,67.766C97.695,66.048 100.48,57.413 93.76,61.002C92.22,62.462 91.447,64.464 90.578,66.017" + android:fillColor="#F6B893"/> + <path + android:pathData="M102.844,51.623C102.452,51.329 102.129,51.114 101.689,50.858C101.179,50.56 100.82,50.398 100.258,50.164C100.213,50.145 100.11,50.164 100.08,50.222C99.606,50.106 99.231,49.897 98.838,49.536C98.011,48.776 97.482,47.427 97.761,46.05C97.911,45.306 98.201,44.998 98.359,44.808C101.937,40.542 99.581,33.754 99.581,33.754C99.581,33.754 97.571,37.946 89.988,40.815C89.988,40.815 90.302,42.765 91.416,44.141C91.496,44.243 92.332,44.99 92.362,46.16C92.39,47.308 92.393,48.47 91.6,50.23C90.633,52.378 88.175,52.896 86.31,52.158C84.918,51.607 84.361,50.23 84.297,48.872C84.297,48.872 88.091,49.093 87.198,44.902C86.53,41.751 85.733,34.87 88.877,30.891C88.921,30.836 88.966,30.78 89.01,30.725C89.041,30.684 89.077,30.643 89.113,30.604C89.177,30.53 89.244,30.455 89.311,30.384C89.375,30.318 89.439,30.252 89.503,30.186C90.489,29.197 91.786,28.454 93.481,28.09C93.481,28.09 99.952,27.209 101.065,30.959C101.065,30.959 102.85,31.843 103.075,35.153C103.298,38.463 102.738,39.675 102.627,42.214C102.493,45.301 102.404,48.393 105.751,49.054C105.756,49.049 105.873,50.734 102.844,51.623Z" + android:fillColor="#4A4A4A"/> + <group> + <clip-path + android:pathData="M156.012,28.116h103.79v104.24h-103.79z"/> + <path + android:pathData="M254.582,43.976H197.362V132.356H254.582V43.976Z" + android:fillColor="#94A1AB"/> + <path + android:pathData="M221.212,77.406H207.682C207.002,77.406 206.452,77.957 206.452,78.636V90.166C206.452,90.845 207.002,91.396 207.682,91.396H221.212C221.891,91.396 222.442,90.845 222.442,90.166V78.636C222.442,77.957 221.891,77.406 221.212,77.406Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M244.092,77.306H230.562C229.882,77.306 229.332,77.857 229.332,78.536V90.066C229.332,90.745 229.882,91.296 230.562,91.296H244.092C244.771,91.296 245.322,90.745 245.322,90.066V78.536C245.322,77.857 244.771,77.306 244.092,77.306Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M221.292,53.776H207.762C207.082,53.776 206.532,54.327 206.532,55.006V66.536C206.532,67.215 207.082,67.766 207.762,67.766H221.292C221.971,67.766 222.522,67.215 222.522,66.536V55.006C222.522,54.327 221.971,53.776 221.292,53.776Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M244.172,53.666H230.642C229.962,53.666 229.412,54.217 229.412,54.896V66.426C229.412,67.105 229.962,67.656 230.642,67.656H244.172C244.851,67.656 245.402,67.105 245.402,66.426V54.896C245.402,54.217 244.851,53.666 244.172,53.666Z" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M201.642,131.116C203.302,129.266 204.482,126.376 203.532,120.366C202.582,114.356 201.802,112.986 200.302,112.746C198.802,112.506 197.852,113.466 197.462,115.556C197.072,117.646 197.142,119.726 196.462,120.556C195.782,121.386 192.202,125.846 194.252,129.696C196.302,133.546 199.782,132.506 201.592,131.146" + android:fillColor="#B8E0FA" + android:fillType="evenOdd"/> + <path + android:pathData="M197.482,132.356C198.506,129.729 199.263,127.005 199.742,124.226C200.218,121.814 200.399,119.352 200.282,116.896H200.092C200.201,119.336 200.016,121.78 199.542,124.176C199.069,126.941 198.318,129.652 197.302,132.266L197.482,132.356Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M199.122,126.976C199.012,127.116 201.912,125.206 202.462,123.316L202.272,123.256C201.742,125.076 199.132,126.736 199.122,126.736V126.976Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M198.212,130.416C197.296,129.178 196.618,127.781 196.212,126.296H196.042C196.435,127.814 197.114,129.243 198.042,130.506L198.212,130.416Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M191.802,101.476C190.142,101.476 189.192,103.876 189.112,104.996C188.782,109.796 185.842,113.216 186.112,120.686C186.282,125.586 188.002,130.616 189.812,131.496C193.312,133.186 195.652,129.416 196.052,125.886C196.708,120.797 196.018,115.625 194.052,110.886C192.602,107.326 195.052,101.436 191.762,101.516" + android:fillColor="#B8E0FA" + android:fillType="evenOdd"/> + <path + android:pathData="M191.672,132.116C190.967,127.077 190.633,121.994 190.672,116.906C190.611,112.654 190.946,108.406 191.672,104.216H191.862C191.141,108.397 190.806,112.634 190.862,116.876C190.823,121.951 191.157,127.021 191.862,132.046L191.672,132.116Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M190.852,123.726C191.898,122.054 192.782,120.286 193.492,118.446H193.682C192.969,120.319 192.075,122.118 191.012,123.816L190.852,123.726Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M190.672,115.246C190.672,115.246 188.672,112.906 188.832,111.166H189.012C188.892,112.846 190.802,115.116 190.802,115.116L190.672,115.246Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + <path + android:pathData="M257.242,35.446H194.702C193.288,35.446 192.142,36.592 192.142,38.006V42.886C192.142,44.3 193.288,45.446 194.702,45.446H257.242C258.655,45.446 259.802,44.3 259.802,42.886V38.006C259.802,36.592 258.655,35.446 257.242,35.446Z" + android:fillColor="#C36A61"/> + <path + android:pathData="M209.232,132.356V104.396H225.962V132.356" + android:fillColor="#D8ECF9"/> + <path + android:pathData="M226.962,132.356V104.396H243.702V132.356" + android:fillColor="#D8ECF9"/> + </group> + <path + android:pathData="M46.923,87.397C46.526,93.788 41.083,98.641 34.783,98.256C28.483,97.871 23.682,92.392 24.08,86.002C24.477,79.611 29.92,74.758 36.22,75.143C42.52,75.528 47.321,81.007 46.923,87.397Z" + android:strokeAlpha="0.36" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.36"/> + <path + android:pathData="M50.377,87.449C49.869,95.529 42.907,101.665 34.849,101.178C26.79,100.692 20.65,93.764 21.158,85.684C21.667,77.604 28.628,71.468 36.687,71.955C44.745,72.441 50.885,79.369 50.377,87.449Z" + android:strokeAlpha="0.14" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.14"/> + <path + android:pathData="M53.166,87.554C52.558,97.213 44.236,104.549 34.602,103.967C24.969,103.385 17.629,95.104 18.236,85.445C18.844,75.786 27.167,68.45 36.8,69.032C46.433,69.614 53.774,77.896 53.166,87.554Z" + android:strokeAlpha="0.04" + android:strokeWidth="4" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.04"/> + <path + android:pathData="M44.002,87.212C43.713,91.915 39.755,95.483 35.179,95.2C30.603,94.917 27.111,90.889 27.4,86.186C27.69,81.482 31.647,77.914 36.224,78.197C40.8,78.48 44.291,82.509 44.002,87.212Z" + android:strokeAlpha="0.5" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1" + android:fillAlpha="0.5"/> + <path + android:pathData="M40.814,86.878C40.633,89.748 38.16,91.918 35.308,91.746C32.456,91.574 30.274,89.122 30.455,86.253C30.635,83.384 33.108,81.213 35.961,81.385C38.813,81.557 40.995,84.009 40.814,86.878Z" + android:strokeWidth="2" + android:fillColor="#00000000" + android:fillType="evenOdd" + android:strokeColor="#C2D6E1"/> + <path + android:pathData="M27.927,81.066C27.927,81.066 30.689,83.651 31.732,84.345C32.597,84.925 35.231,86.138 35.231,86.138L34.225,87.497C34.225,87.497 31.713,86.936 30.945,86.577C30.152,86.211 28.055,84.608 28.055,84.608L27.927,81.066Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M14.811,124.178L13.811,126.074C13.671,126.336 13.769,126.659 14.019,126.806C15.226,127.507 18.519,129.305 19.939,128.817C20.14,128.75 20.189,128.488 20.031,128.348C19.122,127.513 16.299,124.849 16.519,124.197L14.811,124.178Z" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M14.72,124.355L16.647,124.611L26.183,102.598L21.214,92.625L21.159,106.274C21.159,106.274 16.732,115.077 16.025,118.533C15.324,121.941 14.72,124.355 14.72,124.355Z" + android:fillColor="#B96161"/> + <path + android:pathData="M20.903,89.442L28.384,89.54C28.384,89.54 34.871,122.063 37.463,124.258L36.066,125.258C36.066,125.258 28.085,114.382 28.78,107.402C28.786,107.396 18.909,91.534 20.903,89.442Z" + android:fillColor="#C66A61"/> + <path + android:pathData="M26.189,76.926L25.707,73.525C25.707,73.525 27.798,73.616 27.75,70.702C27.743,70.16 27.701,69.239 27.207,68.538L25.292,67.928L24.085,71.794L22.933,76.481L24.969,77.78L26.372,77.743L26.189,76.926Z" + android:fillColor="#F6B893"/> + <path + android:strokeWidth="1" + android:pathData="M27.506,71.183H24.699L24.137,72.305C24.511,72.68 25.372,73.428 25.822,73.428C26.271,73.428 27.506,72.305 27.506,71.183Z" + android:fillColor="#ffffff" + android:strokeColor="#ffffff"/> + <path + android:pathData="M36.073,125.258L36.378,127.373C36.42,127.666 36.682,127.873 36.975,127.842C38.365,127.702 42.085,127.214 42.951,125.989C43.072,125.818 42.957,125.575 42.749,125.55C41.524,125.41 37.676,124.916 37.469,124.258L36.073,125.258Z" + android:fillColor="#4A4A4A"/> + <path + android:pathData="M19.275,93.935L19.799,87.571L22.488,88.339L20.598,94.886C20.598,94.886 20.122,98.684 18.531,97.569C16.555,96.179 19.208,94.716 19.275,93.935Z" + android:fillColor="#F6B893"/> + <path + android:pathData="M25.86,76.915C25.14,77.725 24.335,76.226 22.762,76.634C21.274,77.018 19.945,86.534 19.799,87.577C19.793,87.638 19.787,87.668 19.787,87.668C20.195,88.808 22.061,88.442 22.427,88.357L22.159,89.546L28.39,89.54C30.823,82.81 26.579,76.104 25.86,76.915Z" + android:fillColor="#B1DAEF"/> + <path + android:pathData="M27.75,70.727C27.75,70.727 29.25,69.758 28.256,67.173C28.256,67.173 28.037,66.063 26.482,66.1C26.482,66.1 24.007,63.881 21.677,65.765C19.348,67.648 20.94,69.532 20.94,69.532C20.94,69.532 17.836,72.343 18.909,76.147C18.909,76.147 20.056,78.622 21.385,77.774C22.714,76.927 22.641,78.774 23.342,76.299C24.043,73.824 25.263,74.19 24.781,70.02C24.781,70.02 26.445,70.13 26.811,68.429C26.817,68.429 27.695,68.843 27.75,70.727Z" + android:fillColor="#663014"/> + <path + android:pathData="M33.256,88.449C33.573,88.626 34.768,88.961 35.158,89.04C35.256,89.058 35.493,89.071 35.597,88.882C36.158,87.821 37.835,85.236 37.945,85.084C38.061,84.913 38.048,84.87 37.902,84.773C37.804,84.712 36.463,84.334 36.073,84.218C35.939,84.181 35.823,84.389 35.786,84.437C35.134,85.212 33.366,87.894 33.256,88.065C33.11,88.272 33.128,88.382 33.256,88.449Z" + android:fillColor="#4A4A4A" + android:fillType="evenOdd"/> + <path + android:pathData="M37.012,86.37C37.542,86.26 36.872,87.272 36.609,87.632C36.378,87.961 36.164,88.29 36.006,88.211C35.847,88.132 35.975,87.614 36.176,87.205C36.372,86.797 36.689,86.437 37.012,86.37Z" + android:fillColor="#F6B893"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_shield_illustration.xml b/Corona-Warn-App/src/main/res/drawable/ic_shield_illustration.xml new file mode 100644 index 0000000000000000000000000000000000000000..d296f0d11dae0bf02bfabcee4591c2e14170ae98 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_shield_illustration.xml @@ -0,0 +1,17 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0" + android:fillColor="#F5F5F5"/> + <path + android:strokeWidth="1" + android:pathData="M12.5,19.1877V13.7342L20,10.1293L27.5,13.7342V19.1877C27.5,24.2904 24.2636,29.0038 20,30.2053C15.7364,29.0038 12.5,24.2904 12.5,19.1877Z" + android:fillColor="#00000000" + android:strokeColor="#007FAD"/> + <path + android:pathData="M12,19.1877C12,24.5231 15.4133,29.5123 20,30.7236V9.5745L12,13.4198V19.1877Z" + android:fillColor="#007FAD"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_test_result_step_deletion.xml b/Corona-Warn-App/src/main/res/drawable/ic_test_result_step_deletion.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b995295b96b00090aee4cd890ca39407daefe70 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_test_result_step_deletion.xml @@ -0,0 +1,16 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M20,20m-20,0a20,20 0,1 1,40 0a20,20 0,1 1,-40 0" + android:fillColor="#F5F5F5"/> + <group> + <clip-path + android:pathData="M8,8h24v24h-24z"/> + <path + android:pathData="M24,17V27H16V17H24ZM22.5,11H17.5L16.5,12H13V14H27V12H23.5L22.5,11ZM26,15H14V27C14,28.1 14.9,29 16,29H24C25.1,29 26,28.1 26,27V15Z" + android:fillColor="#979797"/> + </group> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml deleted file mode 100644 index ea2e7488de12496a7cab4402ddfb856a5961380a..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml +++ /dev/null @@ -1,15 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="88dp" - android:height="95dp" - android:viewportWidth="88" - android:viewportHeight="95"> - <path - android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z" - android:fillColor="#616F7E"/> - <path - android:pathData="M44.5,21L23,30.8182V45.5455C23,59.1682 32.1733,71.9073 44.5,75C56.8267,71.9073 66,59.1682 66,45.5455V30.8182L44.5,21Z" - android:fillColor="#ffffff"/> - <path - android:pathData="M32.525,46.7909L29,50.2335L39,60L59,40.4671L55.475,37L39,53.0902L32.525,46.7909Z" - android:fillColor="#616F7E"/> -</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml index 47227abb719d617b587e8270164fbde8a3e9aaf8..29d4300db7f6465d9bbf75efd976043b3d8d1414 100644 --- a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml +++ b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_complete.xml @@ -4,14 +4,14 @@ android:viewportWidth="78" android:viewportHeight="72"> <path - android:pathData="M44.2502,0V4.3846H46.4425V6.7139C42.0321,7.1507 38.05,8.8463 34.7958,11.5096L33.1516,9.8654L34.6588,8.3582L31.5759,5.2752L25.41,11.4411L28.4929,14.524L30.0001,13.0168L31.6444,14.6611C28.9811,17.9153 27.2855,21.8974 26.8487,26.3077H24.5194V24.1154H20.1348V32.8846H24.5194V30.6923H26.8487C27.2855,35.1369 29.0153,39.1447 31.7129,42.4075L30.0001,43.9832L28.4929,42.476L25.41,45.5589L31.5759,51.7248L34.6588,48.6418L33.1516,47.1346L34.7958,45.4219C38.0586,48.1023 42.0236,49.8493 46.4425,50.2861V52.6154H44.2502V57H53.0194V52.6154H50.8271V50.2861C55.2459,49.8493 59.2109,48.1023 62.4737,45.4219H62.5422L64.1179,47.1346L62.6107,48.6418L65.6937,51.7248L71.8595,45.5589L68.7766,42.476L67.2694,43.9832L65.5566,42.4075C65.5609,42.3989 65.5588,42.386 65.5566,42.3732C65.5545,42.3604 65.5524,42.3475 65.5566,42.3389C68.2371,39.0762 69.9841,35.1112 70.4208,30.6923H72.7501V32.8846H77.1348V24.1154H72.7501V26.3077H70.4208C69.9841,21.8974 68.2885,17.9153 65.6251,14.6611L67.2694,13.0168L68.7766,14.524L71.8595,11.4411L65.6937,5.2752L62.6107,8.3582L64.1179,9.8654L62.4737,11.5096C59.2195,8.8463 55.2374,7.1507 50.8271,6.7139V4.3846H53.0194V0H44.2502ZM48.6352,10.9604C58.3465,10.9604 66.1737,18.7876 66.1737,28.4989C66.1737,38.2101 58.3465,46.0373 48.6352,46.0373C38.924,46.0373 31.0968,38.2101 31.0968,28.4989C31.0968,18.7876 38.924,10.9604 48.6352,10.9604ZM39.8653,18.9777C39.8653,17.1622 41.3382,15.6893 43.1537,15.6893C44.9692,15.6893 46.4422,17.1622 46.4422,18.9777C46.4422,20.7933 44.9692,22.2662 43.1537,22.2662C41.3382,22.2662 39.8653,20.7933 39.8653,18.9777ZM54.1157,15.6893C52.3002,15.6893 50.8273,17.1622 50.8273,18.9777C50.8273,20.7933 52.3002,22.2662 54.1157,22.2662C55.9312,22.2662 57.4042,20.7933 57.4042,18.9777C57.4042,17.1622 55.9312,15.6893 54.1157,15.6893ZM34.3848,28.499C34.3848,26.6834 35.8578,25.2105 37.6733,25.2105C39.4888,25.2105 40.9618,26.6834 40.9618,28.499C40.9618,30.3145 39.4888,31.7874 37.6733,31.7874C35.8578,31.7874 34.3848,30.3145 34.3848,28.499ZM48.6353,25.2105C46.8198,25.2105 45.3468,26.6834 45.3468,28.499C45.3468,30.3145 46.8198,31.7874 48.6353,31.7874C50.4508,31.7874 51.9237,30.3145 51.9237,28.499C51.9237,26.6834 50.4508,25.2105 48.6353,25.2105ZM56.3075,28.499C56.3075,26.6834 57.7804,25.2105 59.5959,25.2105C61.4114,25.2105 62.8844,26.6834 62.8844,28.499C62.8844,30.3145 61.4114,31.7874 59.5959,31.7874C57.7804,31.7874 56.3075,30.3145 56.3075,28.499ZM43.1537,34.7339C41.3382,34.7339 39.8653,36.2069 39.8653,38.0224C39.8653,39.8379 41.3382,41.3108 43.1537,41.3108C44.9692,41.3108 46.4422,39.8379 46.4422,38.0224C46.4422,36.2069 44.9692,34.7339 43.1537,34.7339ZM50.8273,38.0224C50.8273,36.2069 52.3002,34.7339 54.1157,34.7339C55.9312,34.7339 57.4042,36.2069 57.4042,38.0224C57.4042,39.8379 55.9312,41.3108 54.1157,41.3108C52.3002,41.3108 50.8273,39.8379 50.8273,38.0224Z" + android:pathData="M44.2499,0V4.3846H46.4422V6.7139C42.0319,7.1507 38.0498,8.8463 34.7956,11.5096L33.1513,9.8654L34.6586,8.3582L31.5756,5.2752L25.4098,11.4411L28.4927,14.524L29.9999,13.0168L31.6441,14.6611C28.9808,17.9153 27.2852,21.8974 26.8485,26.3077H24.5191V24.1154H20.1345V32.8846H24.5191V30.6923H26.8485C27.2852,35.1369 29.0151,39.1447 31.7126,42.4075L29.9999,43.9832L28.4927,42.476L25.4098,45.5589L31.5756,51.7248L34.6586,48.6418L33.1513,47.1346L34.7956,45.4219C38.0583,48.1023 42.0233,49.8493 46.4422,50.2861V52.6154H44.2499V57H53.0191V52.6154H50.8268V50.2861C55.2457,49.8493 59.2107,48.1023 62.4735,45.4219H62.542L64.1177,47.1346L62.6105,48.6418L65.6934,51.7248L71.8593,45.5589L68.7763,42.476L67.2691,43.9832L65.5564,42.4075C65.5607,42.3989 65.5585,42.386 65.5564,42.3732C65.5543,42.3604 65.5521,42.3475 65.5564,42.3389C68.2368,39.0762 69.9838,35.1112 70.4206,30.6923H72.7499V32.8846H77.1345V24.1154H72.7499V26.3077H70.4206C69.9838,21.8974 68.2882,17.9153 65.6249,14.6611L67.2691,13.0168L68.7763,14.524L71.8593,11.4411L65.6934,5.2752L62.6105,8.3582L64.1177,9.8654L62.4735,11.5096C59.2193,8.8463 55.2371,7.1507 50.8268,6.7139V4.3846H53.0191V0H44.2499ZM48.635,10.9604C58.3462,10.9604 66.1734,18.7876 66.1734,28.4989C66.1734,38.2101 58.3462,46.0373 48.635,46.0373C38.9237,46.0373 31.0965,38.2101 31.0965,28.4989C31.0965,18.7876 38.9237,10.9604 48.635,10.9604ZM39.865,18.9777C39.865,17.1622 41.338,15.6893 43.1535,15.6893C44.969,15.6893 46.4419,17.1622 46.4419,18.9777C46.4419,20.7933 44.969,22.2662 43.1535,22.2662C41.338,22.2662 39.865,20.7933 39.865,18.9777ZM54.1155,15.6893C52.3,15.6893 50.827,17.1622 50.827,18.9777C50.827,20.7933 52.3,22.2662 54.1155,22.2662C55.931,22.2662 57.4039,20.7933 57.4039,18.9777C57.4039,17.1622 55.931,15.6893 54.1155,15.6893ZM34.3846,28.499C34.3846,26.6834 35.8575,25.2105 37.673,25.2105C39.4886,25.2105 40.9615,26.6834 40.9615,28.499C40.9615,30.3145 39.4886,31.7874 37.673,31.7874C35.8575,31.7874 34.3846,30.3145 34.3846,28.499ZM48.635,25.2105C46.8195,25.2105 45.3466,26.6834 45.3466,28.499C45.3466,30.3145 46.8195,31.7874 48.635,31.7874C50.4505,31.7874 51.9235,30.3145 51.9235,28.499C51.9235,26.6834 50.4505,25.2105 48.635,25.2105ZM56.3072,28.499C56.3072,26.6834 57.7802,25.2105 59.5957,25.2105C61.4112,25.2105 62.8841,26.6834 62.8841,28.499C62.8841,30.3145 61.4112,31.7874 59.5957,31.7874C57.7802,31.7874 56.3072,30.3145 56.3072,28.499ZM43.1535,34.7339C41.338,34.7339 39.865,36.2069 39.865,38.0224C39.865,39.8379 41.338,41.3108 43.1535,41.3108C44.969,41.3108 46.4419,39.8379 46.4419,38.0224C46.4419,36.2069 44.969,34.7339 43.1535,34.7339ZM50.827,38.0224C50.827,36.2069 52.3,34.7339 54.1155,34.7339C55.931,34.7339 57.4039,36.2069 57.4039,38.0224C57.4039,39.8379 55.931,41.3108 54.1155,41.3108C52.3,41.3108 50.827,39.8379 50.827,38.0224Z" android:fillColor="#ffffff" android:fillAlpha="0.2" - android:fillType="evenOdd" /> + android:fillType="evenOdd"/> <path android:pathData="M22,18L0,27.8182V42.5455C0,56.1682 9.3867,68.9073 22,72C34.6133,68.9073 44,56.1682 44,42.5455V27.8182L22,18Z" - android:fillColor="#ffffff" /> + android:fillColor="#ffffff"/> <path android:pathData="M11.29,43.7909L8,47.2335L17.3333,57L36,37.4671L32.71,34L17.3333,50.0902L11.29,43.7909Z" - android:fillColor="#007FAD" /> + android:fillColor="#616F7E"/> </vector> diff --git a/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_immune.xml b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_immune.xml new file mode 100644 index 0000000000000000000000000000000000000000..47227abb719d617b587e8270164fbde8a3e9aaf8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/vaccination_card_icon_immune.xml @@ -0,0 +1,17 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="78dp" + android:height="72dp" + android:viewportWidth="78" + android:viewportHeight="72"> + <path + android:pathData="M44.2502,0V4.3846H46.4425V6.7139C42.0321,7.1507 38.05,8.8463 34.7958,11.5096L33.1516,9.8654L34.6588,8.3582L31.5759,5.2752L25.41,11.4411L28.4929,14.524L30.0001,13.0168L31.6444,14.6611C28.9811,17.9153 27.2855,21.8974 26.8487,26.3077H24.5194V24.1154H20.1348V32.8846H24.5194V30.6923H26.8487C27.2855,35.1369 29.0153,39.1447 31.7129,42.4075L30.0001,43.9832L28.4929,42.476L25.41,45.5589L31.5759,51.7248L34.6588,48.6418L33.1516,47.1346L34.7958,45.4219C38.0586,48.1023 42.0236,49.8493 46.4425,50.2861V52.6154H44.2502V57H53.0194V52.6154H50.8271V50.2861C55.2459,49.8493 59.2109,48.1023 62.4737,45.4219H62.5422L64.1179,47.1346L62.6107,48.6418L65.6937,51.7248L71.8595,45.5589L68.7766,42.476L67.2694,43.9832L65.5566,42.4075C65.5609,42.3989 65.5588,42.386 65.5566,42.3732C65.5545,42.3604 65.5524,42.3475 65.5566,42.3389C68.2371,39.0762 69.9841,35.1112 70.4208,30.6923H72.7501V32.8846H77.1348V24.1154H72.7501V26.3077H70.4208C69.9841,21.8974 68.2885,17.9153 65.6251,14.6611L67.2694,13.0168L68.7766,14.524L71.8595,11.4411L65.6937,5.2752L62.6107,8.3582L64.1179,9.8654L62.4737,11.5096C59.2195,8.8463 55.2374,7.1507 50.8271,6.7139V4.3846H53.0194V0H44.2502ZM48.6352,10.9604C58.3465,10.9604 66.1737,18.7876 66.1737,28.4989C66.1737,38.2101 58.3465,46.0373 48.6352,46.0373C38.924,46.0373 31.0968,38.2101 31.0968,28.4989C31.0968,18.7876 38.924,10.9604 48.6352,10.9604ZM39.8653,18.9777C39.8653,17.1622 41.3382,15.6893 43.1537,15.6893C44.9692,15.6893 46.4422,17.1622 46.4422,18.9777C46.4422,20.7933 44.9692,22.2662 43.1537,22.2662C41.3382,22.2662 39.8653,20.7933 39.8653,18.9777ZM54.1157,15.6893C52.3002,15.6893 50.8273,17.1622 50.8273,18.9777C50.8273,20.7933 52.3002,22.2662 54.1157,22.2662C55.9312,22.2662 57.4042,20.7933 57.4042,18.9777C57.4042,17.1622 55.9312,15.6893 54.1157,15.6893ZM34.3848,28.499C34.3848,26.6834 35.8578,25.2105 37.6733,25.2105C39.4888,25.2105 40.9618,26.6834 40.9618,28.499C40.9618,30.3145 39.4888,31.7874 37.6733,31.7874C35.8578,31.7874 34.3848,30.3145 34.3848,28.499ZM48.6353,25.2105C46.8198,25.2105 45.3468,26.6834 45.3468,28.499C45.3468,30.3145 46.8198,31.7874 48.6353,31.7874C50.4508,31.7874 51.9237,30.3145 51.9237,28.499C51.9237,26.6834 50.4508,25.2105 48.6353,25.2105ZM56.3075,28.499C56.3075,26.6834 57.7804,25.2105 59.5959,25.2105C61.4114,25.2105 62.8844,26.6834 62.8844,28.499C62.8844,30.3145 61.4114,31.7874 59.5959,31.7874C57.7804,31.7874 56.3075,30.3145 56.3075,28.499ZM43.1537,34.7339C41.3382,34.7339 39.8653,36.2069 39.8653,38.0224C39.8653,39.8379 41.3382,41.3108 43.1537,41.3108C44.9692,41.3108 46.4422,39.8379 46.4422,38.0224C46.4422,36.2069 44.9692,34.7339 43.1537,34.7339ZM50.8273,38.0224C50.8273,36.2069 52.3002,34.7339 54.1157,34.7339C55.9312,34.7339 57.4042,36.2069 57.4042,38.0224C57.4042,39.8379 55.9312,41.3108 54.1157,41.3108C52.3002,41.3108 50.8273,39.8379 50.8273,38.0224Z" + android:fillColor="#ffffff" + android:fillAlpha="0.2" + android:fillType="evenOdd" /> + <path + android:pathData="M22,18L0,27.8182V42.5455C0,56.1682 9.3867,68.9073 22,72C34.6133,68.9073 44,56.1682 44,42.5455V27.8182L22,18Z" + android:fillColor="#ffffff" /> + <path + android:pathData="M11.29,43.7909L8,47.2335L17.3333,57L36,37.4671L32.71,34L17.3333,50.0902L11.29,43.7909Z" + android:fillColor="#007FAD" /> +</vector> diff --git a/Corona-Warn-App/src/main/res/layout/contact_diary_add_person_fragment.xml b/Corona-Warn-App/src/main/res/layout/contact_diary_add_person_fragment.xml index cd5fb2249c9f65979f3cdade5a0d16d897774fa4..9b51a88a0794e61ba5576e4774641c81eb83513f 100644 --- a/Corona-Warn-App/src/main/res/layout/contact_diary_add_person_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/contact_diary_add_person_fragment.xml @@ -2,8 +2,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:fillViewport="true" android:background="@color/colorBackground" + android:fillViewport="true" android:transitionName="contact_diary_shared_content"> <androidx.constraintlayout.widget.ConstraintLayout @@ -19,9 +19,9 @@ android:layout_marginTop="@dimen/spacing_tiny" android:contentDescription="@string/accessibility_close" android:padding="@dimen/spacing_mega_tiny" - app:srcCompat="@drawable/ic_close" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_close" /> <TextView android:id="@+id/contact_diary_person_title" @@ -43,9 +43,9 @@ android:layout_marginEnd="@dimen/spacing_tiny" android:contentDescription="@string/contact_diary_delete_icon_content_description" android:padding="@dimen/button_icon_padding" - app:srcCompat="@drawable/ic_baseline_delete" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_baseline_delete" /> <com.google.android.material.textfield.TextInputLayout android:id="@+id/person_name_input_layout" @@ -64,12 +64,12 @@ android:id="@+id/person_name_input" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" android:imeOptions="actionNext|flagNoPersonalizedLearning" android:inputType="textCapWords" - android:focusable="true" android:maxLength="250" /> - <requestFocus/> + <requestFocus /> </com.google.android.material.textfield.TextInputLayout> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml b/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml index 4473a4a36525220e724360fd058d988259918a9c..787d2728827dc1df89e69991c2cf10fad19ff43e 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml @@ -64,7 +64,6 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" - android:fitsSystemWindows="true" app:layout_collapseMode="pin" app:layout_scrollFlags="scroll|enterAlways" app:navigationIcon="@drawable/ic_close" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml b/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml index c81751a1d61be0f975de25004fc941fcc2f3bb90..d36602946fd708ef510d32ba03f28d2fad7ba7fd 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml @@ -67,7 +67,6 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" - android:fitsSystemWindows="true" app:layout_collapseMode="pin" app:layout_scrollFlags="scroll|enterAlways" app:navigationIcon="@drawable/ic_close" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_scan_qr_code.xml b/Corona-Warn-App/src/main/res/layout/fragment_scan_qr_code.xml index 2b4f586ab41d81c60a490a7912cf8af3caabf93d..76e16aaad1ad2e038d4125b2f0c89c2d9d3638a6 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_scan_qr_code.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_scan_qr_code.xml @@ -48,6 +48,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" android:indeterminate="true" + android:visibility="invisible" app:indicatorColor="@android:color/white" app:indicatorSize="64dp" app:trackColor="@android:color/transparent" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml index 4aa5dfa3dc42b20a66e957377f34b82ba15be099..971b3a38a36226e1c258ad9d25f5f4d910588eb1 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_dispatcher.xml @@ -46,29 +46,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:srcCompat="@drawable/ic_illustration_test" /> - - <TextView - android:id="@+id/submission_dispatcher_text" - style="@style/subtitle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/submission_dispatcher_subheadline" - app:layout_constraintEnd_toStartOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_dispatcher_illustration" /> - - <TextView - android:id="@+id/submission_dispatcher_needs_testing_text" - style="@style/headline6" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:text="@string/submission_dispatcher_needs_testing_subheadline" - app:layout_constraintEnd_toStartOf="@+id/guideline_end" - app:layout_constraintStart_toStartOf="@+id/guideline_start" - app:layout_constraintTop_toBottomOf="@+id/submission_dispatcher_text" /> + app:srcCompat="@drawable/ic_register_test_illustration" /> <include android:id="@+id/submission_dispatcher_qr" @@ -83,7 +61,7 @@ app:illustration="@{@drawable/ic_submission_illustration_qr_code_card}" app:layout_constraintEnd_toStartOf="@+id/guideline_card_end" app:layout_constraintStart_toStartOf="@+id/guideline_card_start" - app:layout_constraintTop_toBottomOf="@+id/submission_dispatcher_needs_testing_text" /> + app:layout_constraintTop_toBottomOf="@+id/submission_dispatcher_illustration" /> <!-- Card layout is inflated lazily based on the profile state--> <ViewStub @@ -129,7 +107,7 @@ layout="@layout/include_dispatcher_card" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginTop="16dp" android:layout_marginBottom="@dimen/spacing_normal" android:clickable="true" android:focusable="true" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_invalid.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_invalid.xml index 42606386e207a488c3573382f457db4d58ab4361..465e80a023138e7be6e82b0b57e8c61cc0d74866 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_invalid.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_test_result_invalid.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> - <androidx.constraintlayout.widget.ConstraintLayout +<androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/submission_test_result_container" android:layout_width="match_parent" android:layout_height="match_parent" @@ -27,10 +28,10 @@ android:layout_marginBottom="@dimen/button_padding_top_bottom" android:accessibilityLiveRegion="assertive" android:importantForAccessibility="yes" - app:layout_constraintBottom_toTopOf="@+id/submission_test_result_button_invalid_remove_test" + app:layout_constraintBottom_toTopOf="@id/submission_test_result_button_invalid_remove_test" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_header"> + app:layout_constraintTop_toBottomOf="@id/submission_test_result_header"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" @@ -58,23 +59,34 @@ android:text="@string/submission_test_result_subtitle" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" /> + app:layout_constraintTop_toBottomOf="@id/submission_test_result_section" /> <de.rki.coronawarnapp.ui.view.SimpleStepEntry - android:id="@+id/test_result_invalid_steps_added" + android:id="@+id/test_result_invalid_steps_pcr_added" android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/spacing_normal" android:layout_marginTop="@dimen/spacing_normal" - android:layout_marginEnd="@dimen/spacing_normal" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="@id/submission_test_result_subtitle" + app:layout_constraintStart_toStartOf="@id/submission_test_result_subtitle" app:layout_constraintTop_toBottomOf="@id/submission_test_result_subtitle" - app:simple_step_entry_text="@string/submission_test_result_steps_added_body" app:simple_step_entry_title="@string/submission_test_result_steps_added_heading" app:step_entry_final="false" app:step_entry_icon="@drawable/ic_test_result_step_done" /> + <de.rki.coronawarnapp.ui.view.SimpleStepEntry + android:id="@+id/test_result_invalid_steps_rat_added" + android:layout_width="0dp" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_height="wrap_content" + app:layout_constraintEnd_toEndOf="@id/submission_test_result_subtitle" + app:layout_constraintStart_toStartOf="@id/submission_test_result_subtitle" + app:layout_constraintTop_toBottomOf="@id/test_result_invalid_steps_pcr_added" + app:simple_step_entry_title="@string/submission_test_result_steps_added_rat_heading" + app:step_entry_final="false" + android:visibility="gone" + tools:visibility="visible" + app:step_entry_icon="@drawable/ic_test_result_step_done" /> + <de.rki.coronawarnapp.ui.view.SimpleStepEntry android:id="@+id/test_result_invalid_steps_invalid_result" android:layout_width="0dp" @@ -83,12 +95,25 @@ android:layout_marginEnd="@dimen/spacing_normal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/test_result_invalid_steps_added" + app:layout_constraintTop_toBottomOf="@id/test_result_invalid_steps_rat_added" app:simple_step_entry_text="@string/submission_test_result_invalid_steps_invalid_body" app:simple_step_entry_title="@string/submission_test_result_invalid_steps_invalid_heading" - app:step_entry_final="true" app:step_entry_icon="@drawable/ic_test_result_step_invalid" /> + <de.rki.coronawarnapp.ui.view.SimpleStepEntry + android:id="@+id/test_result_invalid_steps_remove_test" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/test_result_invalid_steps_invalid_result" + app:simple_step_entry_text="@string/submission_test_result_delete_steps_invalid_body" + app:simple_step_entry_title="@string/submission_test_result_delete_steps_invalid_heading" + app:step_entry_final="true" + app:step_entry_icon="@drawable/ic_test_result_step_deletion" /> + </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml index 9768d421cc96486db9634dc6d9ff930e9af942f2..eca90fd7d23c2162a80dc1242f2990494e057637 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml @@ -79,7 +79,7 @@ android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal"> - <ImageView + <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="72dp" @@ -107,7 +107,7 @@ <include android:id="@+id/qr_code_card" - layout="@layout/vaccination_list_certificate_card" + layout="@layout/vaccination_list_qrcode_card" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml index ec70295fcc340ef288ea5ccd16a32797e6bfd90c..da6a49f671a12448cba8ceedf090e805d5b058b2 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml @@ -13,7 +13,7 @@ android:layout_height="0dp" android:layout_marginBottom="12dp" android:nestedScrollingEnabled="true" - app:layout_constraintBottom_toTopOf="@id/refresh_button" + app:layout_constraintBottom_toTopOf="@id/register_new_vaccination_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -55,7 +55,7 @@ android:text="@string/vaccination_list_title" android:textColor="@android:color/white" android:textSize="20sp" - android:textStyle="bold"/> + android:textStyle="bold" /> <TextView android:id="@+id/subtitle" @@ -67,7 +67,7 @@ android:text="@string/vaccination_list_complete_vaccination_subtitle" android:textColor="@android:color/white" android:textSize="18sp" - android:visibility="visible"/> + android:visibility="visible" /> </LinearLayout> @@ -86,7 +86,7 @@ android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal"> - <ImageView + <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="72dp" @@ -104,26 +104,14 @@ android:id="@+id/recycler_view_vaccination_list" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_weight="1" + android:clipToPadding="false" + android:paddingTop="24dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_behavior="@string/appbar_scrolling_view_behavior" - tools:listitem="@layout/vaccination_list_incomplete_top_card" /> + tools:listitem="@layout/vaccination_list_qrcode_card" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> - <Button - android:id="@+id/refresh_button" - style="@style/buttonPrimary" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/spacing_normal" - android:layout_marginEnd="@dimen/spacing_normal" - android:layout_marginBottom="8dp" - android:text="@string/vaccination_list_refresh_button" - app:layout_constraintBottom_toTopOf="@id/register_new_vaccination_button" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent"/> - <Button android:id="@+id/register_new_vaccination_button" style="@style/buttonPrimary" diff --git a/Corona-Warn-App/src/main/res/layout/include_dispatcher_card.xml b/Corona-Warn-App/src/main/res/layout/include_dispatcher_card.xml index d2a3907c5506158b2d26d2d037fe2d87be67dbe1..6c000385c32526f7ea110b55e222eaf77987537e 100644 --- a/Corona-Warn-App/src/main/res/layout/include_dispatcher_card.xml +++ b/Corona-Warn-App/src/main/res/layout/include_dispatcher_card.xml @@ -73,15 +73,17 @@ app:layout_constraintVertical_bias="0.0" tools:text="@string/submission_dispatcher_qr_card_text" /> - <ImageView + <com.google.android.material.imageview.ShapeableImageView android:id="@+id/dispatcher_card_illustration" android:layout_width="wrap_content" + app:shapeAppearanceOverlay="@style/dispatcherImageStyle" android:layout_height="wrap_content" android:layout_marginTop="@dimen/button_icon_margin" android:src="@{illustration}" android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintVertical_bias="1.0" app:layout_constraintTop_toBottomOf="@+id/dispatcher_card_icon" tools:src="@drawable/ic_submission_illustration_qr_code_card" /> diff --git a/Corona-Warn-App/src/main/res/layout/rat_profile_create_fragment.xml b/Corona-Warn-App/src/main/res/layout/rat_profile_create_fragment.xml index 275542e4151543c295e5019474effabd7f65e5a3..e1f62efc0de64a8ecd43eb0d87f7f37ddac891df 100644 --- a/Corona-Warn-App/src/main/res/layout/rat_profile_create_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/rat_profile_create_fragment.xml @@ -141,7 +141,7 @@ <com.google.android.material.textfield.TextInputLayout android:id="@+id/zip_code_input_layout" style="@style/TextInputLayoutTheme" - android:layout_width="100dp" + android:layout_width="120dp" android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/spacing_normal" android:layout_marginTop="@dimen/spacing_small" diff --git a/Corona-Warn-App/src/main/res/layout/submission_create_rat_profile_card.xml b/Corona-Warn-App/src/main/res/layout/submission_create_rat_profile_card.xml index 0e89fd2eb78ba7e3c99c39c9830f6931ec048fc0..c530af99280fec8b3f055c37654196dc68b1fb3a 100644 --- a/Corona-Warn-App/src/main/res/layout/submission_create_rat_profile_card.xml +++ b/Corona-Warn-App/src/main/res/layout/submission_create_rat_profile_card.xml @@ -3,19 +3,33 @@ xmlns:app="http://schemas.android.com/apk/res-auto" style="@style/GreyCard.Ripple" android:layout_width="match_parent" - android:layout_height="match_parent" - android:padding="24dp"> + android:layout_height="wrap_content"> <TextView android:id="@+id/title" style="@style/headline6" - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_small" android:text="@string/rat_profile_create_card_title" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@+id/dispatcher_card_icon" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + <ImageView + android:id="@+id/dispatcher_card_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:layout_marginEnd="@dimen/spacing_normal" + android:importantForAccessibility="no" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_forward" + app:tint="@color/colorTextPrimary1" /> + <ImageView android:id="@+id/illustration" android:layout_width="wrap_content" @@ -32,10 +46,13 @@ style="@style/subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" android:layout_marginTop="18dp" + android:layout_marginBottom="24dp" android:text="@string/rat_profile_create_card_subtitle" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/illustration" /> -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml b/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml index 400fcff003c776803ea79b59c15d1e0562312f08..51317118fb1efa3c0b7f0a6b2daa256269cf6e85 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_consent_fragment.xml @@ -122,7 +122,7 @@ android:importantForAccessibility="no" app:layout_constraintStart_toStartOf="@id/vaccination_consent_qr_code_icon" app:layout_constraintTop_toBottomOf="@id/vaccination_consent_qr_code_text" - app:srcCompat="@drawable/ic_qr_time" /> + app:srcCompat="@drawable/ic_shield_illustration" /> <TextView android:id="@+id/vaccination_consent_time_sheet_text" @@ -153,9 +153,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="@dimen/spacing_medium" - android:layout_marginTop="@dimen/spacing_large" + android:layout_marginTop="@dimen/spacing_normal" android:layout_marginEnd="@dimen/spacing_medium" - android:layout_marginBottom="@dimen/spacing_medium" + android:layout_marginBottom="@dimen/spacing_small" android:focusable="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_consent_privacy_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_consent_privacy_card.xml index 0908aeae077ce0fb5eed074cf8533a9a08af4f75..ef10beac86e3e580bf76f193ca18a9e36e13bc6d 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_consent_privacy_card.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_consent_privacy_card.xml @@ -8,7 +8,7 @@ <TextView android:id="@+id/vaccination_consent_legal_text_card_title" - style="@style/headline5" + style="@style/subtitleBoldSixteen" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/spacing_small" @@ -19,68 +19,44 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <TextView - android:id="@+id/vaccination_consent_legal_text_card_subtitle" - style="@style/subtitle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/spacing_normal" - android:layout_marginEnd="@dimen/spacing_normal" - android:text="@string/vaccination_privacy_card_subtitle_text" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_title" - app:layout_constraintTop_toBottomOf="@id/vaccination_consent_legal_text_card_title" /> - <include android:id="@+id/bulletpoint_one" layout="@layout/include_bullet_point" android:layout_width="@dimen/bullet_point_size" android:layout_height="@dimen/bullet_point_size" - app:layout_constraintBaseline_toBaselineOf="@id/first_bulletpoint_title" - app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_subtitle" /> + app:layout_constraintBaseline_toBaselineOf="@id/first_bulletpoint_text" + app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_title" /> <TextView - android:id="@+id/first_bulletpoint_title" + android:id="@+id/first_bulletpoint_text" style="@style/subtitle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/spacing_normal" android:layout_marginTop="@dimen/spacing_normal" android:text="@string/vaccination_privacy_card_first_bulletpoint_title_text" - android:textStyle="bold" - app:layout_constraintEnd_toEndOf="@id/vaccination_consent_legal_text_card_subtitle" + app:layout_constraintEnd_toEndOf="@id/vaccination_consent_legal_text_card_title" app:layout_constraintStart_toEndOf="@id/bulletpoint_one" - app:layout_constraintTop_toBottomOf="@id/vaccination_consent_legal_text_card_subtitle" /> - - <TextView - android:id="@+id/first_bulletpoint_subtitle" - style="@style/subtitle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:text="@string/vaccination_privacy_card_first_bulletpoint_subtitle_text" - app:layout_constraintEnd_toEndOf="@id/first_bulletpoint_title" - app:layout_constraintStart_toStartOf="@id/first_bulletpoint_title" - app:layout_constraintTop_toBottomOf="@id/first_bulletpoint_title" /> + app:layout_constraintTop_toBottomOf="@id/vaccination_consent_legal_text_card_title" /> <include android:id="@+id/bulletpoint_two" layout="@layout/include_bullet_point" android:layout_width="@dimen/bullet_point_size" android:layout_height="@dimen/bullet_point_size" - app:layout_constraintBaseline_toBaselineOf="@id/second_bulletpoint_title" + app:layout_constraintBaseline_toBaselineOf="@id/second_bulletpoint_text" app:layout_constraintStart_toStartOf="@id/bulletpoint_one" /> <TextView - android:id="@+id/second_bulletpoint_title" + android:id="@+id/second_bulletpoint_text" style="@style/subtitle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" android:text="@string/vaccination_privacy_card_second_bulletpoint_title_text" - android:textStyle="bold" - app:layout_constraintEnd_toEndOf="@id/first_bulletpoint_subtitle" - app:layout_constraintStart_toStartOf="@id/first_bulletpoint_subtitle" - app:layout_constraintTop_toBottomOf="@id/first_bulletpoint_subtitle" /> + app:layout_constraintEnd_toEndOf="@id/first_bulletpoint_text" + app:layout_constraintStart_toStartOf="@id/first_bulletpoint_text" + app:layout_constraintTop_toBottomOf="@id/first_bulletpoint_text" /> <include android:id="@+id/bulletpoint_three" @@ -88,7 +64,7 @@ android:layout_width="@dimen/bullet_point_size" android:layout_height="@dimen/bullet_point_size" app:layout_constraintBaseline_toBaselineOf="@id/third_bulletpoint_text" - app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_subtitle" /> + app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_title" /> <TextView android:id="@+id/third_bulletpoint_text" @@ -97,21 +73,28 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" android:text="@string/vaccination_privacy_card_third_bulletpoint_title_text" - android:textStyle="bold" - app:layout_constraintEnd_toEndOf="@id/second_bulletpoint_title" - app:layout_constraintStart_toStartOf="@id/second_bulletpoint_title" - app:layout_constraintTop_toBottomOf="@id/second_bulletpoint_title" /> + app:layout_constraintEnd_toEndOf="@id/second_bulletpoint_text" + app:layout_constraintStart_toStartOf="@id/second_bulletpoint_text" + app:layout_constraintTop_toBottomOf="@id/second_bulletpoint_text" /> + + <include + android:id="@+id/bulletpoint_four" + layout="@layout/include_bullet_point" + android:layout_width="@dimen/bullet_point_size" + android:layout_height="@dimen/bullet_point_size" + app:layout_constraintBaseline_toBaselineOf="@id/fourth_bulletpoint_text" + app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_title" /> <TextView - android:id="@+id/vaccination_consent_legal_text_body" + android:id="@+id/fourth_bulletpoint_text" style="@style/subtitle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_normal" - android:paddingBottom="@dimen/spacing_medium" - android:text="@string/vaccination_privacy_card_body" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="@id/vaccination_consent_legal_text_card_title" + android:text="@string/vaccination_privacy_card_fourth_bulletpoint_title_text" + app:layout_constraintEnd_toEndOf="@id/third_bulletpoint_text" + android:paddingBottom="@dimen/spacing_small" + app:layout_constraintStart_toStartOf="@id/third_bulletpoint_text" app:layout_constraintTop_toBottomOf="@id/third_bulletpoint_text" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_home_incomplete_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml similarity index 94% rename from Corona-Warn-App/src/main/res/layout/vaccination_home_incomplete_card.xml rename to Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml index 6967cbc8040d458ae636b9683426fa628ff153d8..38faef5dc140c72d9728338bb3d88ebb0a06c549 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_home_incomplete_card.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml @@ -5,7 +5,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/vaccination_incomplete" - android:padding="@dimen/card_padding"> + android:padding="@dimen/card_padding" + tools:ignore="UnusedAttribute"> <ImageView @@ -23,6 +24,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" + android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/show_more_action" @@ -51,11 +53,11 @@ android:layout_marginEnd="16dp" android:accessibilityHeading="true" android:focusable="false" + android:text="@string/vaccination_card_status_vaccination_name" android:textColor="@color/colorTextPrimary1InvertedStable" app:layout_constraintEnd_toStartOf="@+id/icon" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/card_title" - android:text="@string/vaccination_card_status_vaccination_name" /> + app:layout_constraintTop_toBottomOf="@id/card_title" /> <TextView android:id="@+id/vaccination_state" @@ -88,6 +90,6 @@ app:layout_constraintEnd_toStartOf="@+id/icon" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/vaccination_state" - tools:text="François-Joan d'Arsøns - van Halen" /> + tools:text="Andrea Schneider" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_home_complete_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml similarity index 90% rename from Corona-Warn-App/src/main/res/layout/vaccination_home_complete_card.xml rename to Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml index 598ddd22dd51745335c2100a4b5b9c4e82c24891..51057d18a765bad49fa1f16cbae7b7d355344132 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_home_complete_card.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml @@ -5,7 +5,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/vaccination_compelete_gradient" - android:padding="@dimen/card_padding"> + android:padding="@dimen/card_padding" + tools:ignore="UnusedAttribute"> <ImageView @@ -22,10 +23,11 @@ android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/show_more_action" - app:srcCompat="@drawable/vaccination_card_icon_complete" /> + app:srcCompat="@drawable/vaccination_card_icon_immune" /> <TextView android:id="@+id/card_title" @@ -49,11 +51,11 @@ android:layout_marginEnd="16dp" android:accessibilityHeading="true" android:focusable="false" + android:text="@string/vaccination_card_status_vaccination_name" android:textColor="@color/colorTextPrimary1InvertedStable" app:layout_constraintEnd_toStartOf="@+id/icon" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/card_title" - android:text="@string/vaccination_card_status_vaccination_name" /> + app:layout_constraintTop_toBottomOf="@id/card_title" /> <TextView android:id="@+id/person_name" @@ -69,6 +71,6 @@ app:layout_constraintEnd_toStartOf="@+id/icon" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/vaccination_label" - tools:text="François-Joan d'Arsøns - van Halen" /> + tools:text="Andrea Schneider" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_immunity_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_immunity_card.xml new file mode 100644 index 0000000000000000000000000000000000000000..44c0c8ece8d8570746124ad74590771bf1e23440 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_immunity_card.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/Card.Vaccination" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="8dp" + android:orientation="vertical" + android:padding="16dp"> + + <TextView + android:id="@+id/body" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + +</FrameLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml deleted file mode 100644 index b5238b92da2f3a26ce42223a9921360882950def..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - style="@style/Card.Vaccination" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="16dp" - android:orientation="vertical" - android:paddingHorizontal="16dp" - android:paddingTop="24dp" - android:paddingBottom="12dp"> - - <TextView - android:id="@+id/top_card_title" - style="@style/headline4Bold" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/vaccination_list_top_card_title" - android:textSize="30sp"/> - - <TextView - android:id="@+id/top_card_subtitle" - style="@style/body2Medium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:text="@string/vaccination_list_top_card_subtitle" - android:textSize="18sp" /> - -</LinearLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_qrcode_card.xml similarity index 94% rename from Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml rename to Corona-Warn-App/src/main/res/layout/vaccination_list_qrcode_card.xml index 3ba5e6305f49af846f7bc391dba4cbb4705db7e2..3c640f5b6d9381162338ab761b0f877b6f8e6a2f 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_qrcode_card.xml @@ -7,6 +7,19 @@ android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" android:padding="16dp"> + + <com.google.android.material.progressindicator.LinearProgressIndicator + android:id="@+id/progress_bar" + android:layout_width="140dp" + android:layout_height="24dp" + android:indeterminate="true" + app:hideAnimationBehavior="inward" + app:indicatorColor="@color/colorAccent" + app:layout_constraintBottom_toBottomOf="@id/image" + app:layout_constraintEnd_toEndOf="@id/image" + app:layout_constraintStart_toStartOf="@id/image" + app:layout_constraintTop_toTopOf="@id/image" /> + <com.google.android.material.imageview.ShapeableImageView android:id="@+id/image" android:layout_width="0dp" @@ -21,18 +34,6 @@ tools:src="@drawable/ic_qrcode" tools:tint="@android:color/black" /> - <com.google.android.material.progressindicator.LinearProgressIndicator - android:id="@+id/progress_bar" - android:layout_width="150dp" - android:layout_height="wrap_content" - android:indeterminate="true" - app:hideAnimationBehavior="inward" - app:indicatorColor="@color/colorAccent" - app:layout_constraintBottom_toBottomOf="@id/image" - app:layout_constraintEnd_toEndOf="@id/image" - app:layout_constraintStart_toStartOf="@id/image" - app:layout_constraintTop_toTopOf="@id/image" /> - <TextView android:id="@+id/title" style="@style/body2" @@ -57,4 +58,4 @@ app:layout_constraintTop_toBottomOf="@id/title" tools:text="Geimpft 24.04.21 - gültig bis 24.04.22" /> -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml index 2078b26bd35e9629862d68c7448a0d97068f3634..20d3f5f2db114177c9b6ff5178964e5c45ad5e29 100644 --- a/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml @@ -2,17 +2,18 @@ <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/vaccination_card" - style="@style/Card.Vaccination.Ripple" + style="@style/Card.Vaccination.Ripple.NoPadding" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" - android:layout_marginTop="8dp" - android:padding="16dp"> + android:layout_marginTop="8dp"> <ImageView android:id="@+id/vaccination_icon" android:layout_width="88dp" android:layout_height="95dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" android:importantForAccessibility="no" app:srcCompat="@drawable/ic_vaccination_incomplete" app:layout_constraintStart_toStartOf="parent" @@ -27,9 +28,9 @@ android:text="@string/vaccination_list_vaccination_card_title" android:textSize="18sp" android:textStyle="bold" - app:layout_constraintEnd_toStartOf="@id/arrow_right" + app:layout_constraintEnd_toStartOf="@id/overflow_menu" app:layout_constraintStart_toEndOf="@id/vaccination_icon" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="@id/vaccination_icon" /> <TextView android:id="@+id/vaccination_card_subtitle" @@ -39,17 +40,27 @@ android:layout_marginStart="16dp" android:layout_marginTop="4dp" android:text="@string/vaccination_list_vaccination_card_subtitle" - app:layout_constraintEnd_toStartOf="@id/arrow_right" + app:layout_constraintEnd_toStartOf="@id/overflow_menu" app:layout_constraintStart_toEndOf="@id/vaccination_icon" app:layout_constraintTop_toBottomOf="@id/vaccination_card_title" /> - <ImageView - android:id="@+id/arrow_right" + <ImageButton + android:id="@+id/overflow_menu" + style="@style/CardOverFlowButton" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + <androidx.constraintlayout.widget.Barrier + android:id="@+id/bottom_barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:importantForAccessibility="no" - app:srcCompat="@drawable/ic_arrow_right_grey" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:barrierDirection="bottom" + app:constraint_referenced_ids="vaccination_icon,vaccination_card_subtitle" /> + + <Space + android:layout_width="match_parent" + android:layout_height="16dp" + app:layout_constraintTop_toBottomOf="@id/bottom_barrier" + app:layout_constraintStart_toStartOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/menu/menu_vaccination_item.xml b/Corona-Warn-App/src/main/res/menu/menu_vaccination_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e750fd6e2897b1981d849472a5af722627364ab --- /dev/null +++ b/Corona-Warn-App/src/main/res/menu/menu_vaccination_item.xml @@ -0,0 +1,5 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/menu_delete" + android:title="@string/vaccination_list_delete_button" /> +</menu> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml index 137c5716db96a44a55a69580d750dd2d71c6fbaa..ee14f5eb4790c3edeb18e38e071ea6a167764370 100644 --- a/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/antigen_strings.xml @@ -143,7 +143,7 @@ <!-- XHED: Create RAT profile card title --> <string name="rat_profile_create_card_title">Schnelltest-Profil anlegen</string> <!-- XTXT: Create RAT profile card subtitle --> - <string name="rat_profile_create_card_subtitle">Legen Sie ein Profil mit Ihren persönlichen Daten an, die Sie dann per QR-Code bei jedem Schnelltest vorlegen können.</string> + <string name="rat_profile_create_card_subtitle">Legen Sie ein Profil mit Ihren persönlichen Daten an, das Sie per QR-Code bei jeder teilnehmenden Teststelle vorlegen können.</string> <!-- XHED: Open RAT profile card title --> <string name="rat_profile_open_card_title">Schnelltest-Profil</string> <!-- XTXT: Open RAT profile card subtitle --> @@ -159,7 +159,7 @@ <!-- XBUT: Create RAT profile save button --> <string name="rat_profile_create_button">Speichern</string> <!-- XTXT: Create RAT profile description --> - <string name="rat_profile_create_description">Legen Sie Ihre persönlichen Daten als QR-Code ab, um die Registrierung an der Teststelle zu beschleunigen.</string> + <string name="rat_profile_create_description">Legen Sie ein Profil mit Ihren persönlichen Daten an, das Sie per QR-Code bei jeder teilnehmenden Teststelle vorlegen können.</string> <!-- XTXT: Create RAT profile street hint --> <string name="rat_profile_create_street_hint">Straße und Hausnummer</string> <!-- XTXT: Create RAT profile post code hint --> @@ -174,7 +174,7 @@ <!--RAT profile onboarding--> <string name="rat_profile_onboarding_image_content_description">Eine Frau mit einem Smartphone in der Hand steht vor einem Gebäude. Ein QR-Code symbolisiert das zu scannende Schnelltest-Profil.</string> <!-- XTXT: Create RAT profile onboarding title --> - <string name="rat_profile_onboarding_title">Legen Sie Ihre persönlichen Daten als QR-Code ab, um die Registrierung an der Teststelle zu beschleunigen.</string> + <string name="rat_profile_onboarding_title">Legen Sie ein Profil mit Ihren persönlichen Daten an, das Sie per QR-Code bei jeder teilnehmenden Teststelle vorlegen können.</string> <!-- XTXT: Create RAT profile onboarding subtitle --> <string name="rat_profile_onboarding_subtitle">Mit Ihrem eigenen Schnelltest-Profil müssen Sie Ihre persönlichen Daten nicht bei jedem neuen Schnelltest erneut ausfüllen.</string> <!-- XTXT: Create RAT profile onboarding next button --> diff --git a/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml b/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml index 82c6388ef5dcc30fe4d3b84fa5e77b17e02a317d..61235ef3c6682b6d2cda876f7d8651fc4e4107da 100644 --- a/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/contact_diary_strings.xml @@ -32,7 +32,7 @@ <!-- XTXT: Title for the contact diary onboarding screen --> <string name="contact_diary_information_card_title">"Behalten Sie den Überblick."</string> <!-- XTXT: Contact diary onboarding screen --> - <string name="contact_diary_onboarding_body">"Erstellen Sie eine Übersicht über Ihre Kontakte der letzten 14 Tage. So haben Sie bei Bedarf schnell eine vollständige Liste zur Hand."</string> + <string name="contact_diary_onboarding_body">"Erstellen Sie eine Übersicht über Ihre Kontakte der letzten 14 Tage. So haben Sie bei Bedarf schnell eine vollständige Liste zur Hand. Zusätzlich werden Ihnen hier Ihre Risiko-Begegnungen angezeigt."</string> <!-- XTXT: Contact diary onboarding screen first functionality --> <string name="contact_diary_onboarding_functionality_first_section">"Tragen Sie ein, mit wem Sie sich getroffen haben."</string> <!-- XTXT: Contact diary onboarding screen second functionality --> diff --git a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml index 02db550f85e4a05c8dca987bd7518c6b386a57d0..9cc3d26ac762a94c05e17fca6c9df4c831a67fba 100644 --- a/Corona-Warn-App/src/main/res/values-de/legal_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/legal_strings.xml @@ -169,24 +169,15 @@ <!-- YMSG: RAT Profile Onboarding bullet points --> <string name="rat_profile_onboarding_card_consent7" translatable="false">Private Personen oder Unternehmen dürfen von Ihnen nicht verlangen, dass Sie Ihr Schnelltest-Profil vorzeigen.</string> - <!-- XTXT: Vaccination Consent title--> - <string name="vaccination_consent_title">Ihr Einverständnis</string> - <!-- XTXT: Vaccination Consent subtitle--> - <string name="vaccination_consent_headline">Impfzertifikat registrieren</string> - <!-- XTXT: Vaccination Consent subtitle of qr info --> - <string name="vaccination_consent_info_subtitle_text">"Erstellen Sie einen digitalen Impfnachweis. Sie finden weitere Informationen in der FAQ zum Impfen."</string> - <!-- XTXT: Vaccination Consent subtitle of qr info (part that should be displayed as link) --> - <string name="vaccination_consent_info_subtitle_text_link_label">"FAQ zum Impfen."</string> - <!-- XTXT: Vaccination Consent text of qr info --> - <string name="vaccination_consent_qr_info_text">"Scannen Sie den QR-Code auf Ihrem Impfzertifikat, um das Zertifikat zu registrieren."</string> - <!-- XTXT: Vaccination Consent qr code text --> - <string name="vaccination_consent_qr_info_qr_code_text">"Die App erstellt einen Impfnachweis. Der QR-Code zum vollständigen Impfnachweis erhalten Sie, wenn Sie alle Impfungen erhalten haben. Je nach Impfstoff können mehrere Impftermine nötig sein."</string> - <!-- XTXT: Vaccination Consent time text --> - <string name="vaccination_consent_qr_info_time_text">"Ihr Impfnachweis wird in regelmäßigen Abständen automatisch aktualisiert. Wenn durch Mutationen des Coronavirus neue Impfungen nötig werden, kann Ihr Impfnachweis ungültig werden."</string> - <!-- XTXT: Text for vaccination consent legal information button --> - <string name="vaccination_consent_onboarding_legal_information">"Weitere Hinweise finden Sie in der Datenschutzerklärung."</string> - <!-- XBUT: Text for vaccination consent accept button --> - <string name="vaccination_consent_accept_button">"Einverstanden"</string> - <!-- XTXT: Vaccination Consent FAQ Url --> - <string name="vaccination_consent_faq_url">"https://www.coronawarn.app/de/faq/"</string> + <!-- Vaccination Consent Privacy Strings --> + <!-- XHED: Title for privacy card --> + <string name="vaccination_privacy_card_title_text" translatable="false">"Datenschutz und Datensicherheit"</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_first_bulletpoint_title_text" translatable="false">"Die Verwendung des digitalen Impfnachweises ist freiwillig. Der Nachweis des vollständigen Impfschutzes kann auch auf andere Weise erbracht werden (z.B. mit dem gelben Impfausweis)."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_second_bulletpoint_title_text" translatable="false">"Das Impfzertifikat enthält die Daten über Ihre Corona-Impfung. Zum Nachweis Ihres Impfschutzes in den gesetzlich vorgesehenen Fällen genügt das Vorzeigen des QR-Codes in der App. Stellen Sie die Impfzertifikate und QR-Codes niemandem zur Verfügung, wenn Sie nicht wollen, dass die Daten ausgelesen werden."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_third_bulletpoint_title_text" translatable="false">"Wenn Sie den QR-Code in der App vorzeigen und dieser mit der Prüf-App gescannt wird, können andere Personen nachvollziehen, ob Ihr Impfschutz vollständig ist. Bei der Prüfung werden in der offiziellen Prüf-App auch Ihr Name und Ihr Geburtsdatum angezeigt."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_fourth_bulletpoint_title_text" translatable="false">"Sie haben jederzeit die Möglichkeit, Impfzertifikate in der App wieder zu entfernen. Bis dahin bleiben die Impfzertifikate auf Ihrem Smartphone gespeichert."</string> </resources> diff --git a/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml b/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml index 04d61acf73a0ee7b5153408f3cdc6a2b35e86b18..a6cbbe492b6992fdf059623c3e726c29ee41198c 100644 --- a/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/release_info_strings.xml @@ -17,26 +17,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>Aufzeichnung von Fehleranalyse-Protokollen</item> - <item>Anlegen von Schnelltest-Profilen</item> + <item>Digitaler Impfnachweis</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>Sie können nun im Rahmen des technischen Supports für die App ein Fehlerprotokoll erstellen, das die Schritte aufzeichnet, die Sie in der App ausführen. Somit wird die Analyse von möglichen Fehlern erleichtert, welches zu einer schnelleren Fehlerbehebung führen kann.</item> - <item>Sie können nun ein Schnelltest-Profil mit Ihren persönlichen Daten anlegen. Ihr Profil kann dann an Teststellen per QR-Code schnell und einfach gescannt werden.</item> + <item>Sie können jetzt Ihre Impfzertifikate in der App hinzufügen und per QR-Code vorweisen. 14 Tage nach der letzten Impfung zeigt die App den vollständigen Impfschutz an.</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> <item></item> - <item></item> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> <item></item> - <item></item> </string-array> </resources> diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml index 62b50d512f3e9a2bff0d9e6b03a8628a25f6de44..dd1ea83e090b1f44d0901bf97433629f5c5192eb 100644 --- a/Corona-Warn-App/src/main/res/values-de/strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/strings.xml @@ -748,7 +748,7 @@ <string name="settings_privacy_preserving_analytics_title">"Datenspende"</string> <!-- XTXT: privacy preserving analytics settings switch subtitle --> - <string name="settings_analytics_switch_subtitle">"Nutzerdaten spenden"</string> + <string name="settings_analytics_switch_subtitle">"Datenspende"</string> <!-- #################################### App Information @@ -1064,7 +1064,7 @@ <!-- XHED: Page subheadline for test result --> <string name="submission_test_result_subtitle">"Info zum Ablauf:"</string> <!-- XHED: Page headline for results next steps --> - <string name="submission_test_result_steps_added_heading">"Test erfolgreich hinzugefügt"</string> + <string name="submission_test_result_steps_added_heading">"Ihr PCR-Test wurde hinzugefügt."</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Ihr Test wurde in der Corona-Warn-App registriert."</string> <!-- XHED: Page headline for pending test result next steps --> @@ -1102,10 +1102,19 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Weiter mit Symptom-Erfassung"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Weiter ohne Symptom-Erfassung"</string> + + + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_invalid_steps_invalid_heading">"Test kann nicht ausgewertet werden"</string> + <!-- XHED: Page headline for invalid test result screen --> - <string name="submission_test_result_invalid_steps_invalid_heading">"Ihr Testergebnis"</string> + <string name="submission_test_result_delete_steps_invalid_heading">"Test entfernen"</string> + + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_invalid_steps_invalid_body">"Es gab ein Problem bei der Auswertung Ihres Tests. Bitte kontaktieren Sie das Testcenter oder das zuständige Labor, um Informationen zum weiteren Vorgehen zu erhalten."</string> <!-- YTXT: Body text for next steps section of invalid test result--> - <string name="submission_test_result_invalid_steps_invalid_body">"Es gab ein Problem bei der Auswertung Ihres Tests. Bitte kontaktieren Sie das Testcenter oder das zuständige Labor, um Information zum weiteren Vorgehen zu erhalten.\n\nBitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."</string> + <string name="submission_test_result_delete_steps_invalid_body">"Bitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."</string> + <!-- XBUT: invalid test result : remove the test button --> <string name="submission_test_result_invalid_remove_test_button">"Test entfernen"</string> <!-- XHED: Dialog title for tracing required dailog --> @@ -1159,11 +1168,7 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Testergebnis abrufen"</string> - <!-- XHED: Page subheadline for dispatcher menu --> - <string name="submission_dispatcher_subheadline">"Rufen Sie über die App Ihr Testergebnis ab und warnen Sie anschließend Ihre Mitmenschen. So schützen Sie sich und andere und helfen mit, die Ausbreitung von Corona zu verhindern."</string> - <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> - <string name="submission_dispatcher_needs_testing_subheadline">"Sie haben sich bereits testen lassen?"</string> + <string name="submission_dispatcher_headline">"Test registrieren"</string> <!-- XHED: Page subheadline for dispatcher options asking if they already have a positive test: tele-TAN --> <string name="submission_dispatcher_already_positive_subheadline">"Ihr PCR-Test ist positiv?"</string> <!-- YTXT: Dispatcher text for QR code option --> @@ -1237,18 +1242,18 @@ <!-- YTXT: text after submission: pcr validation --> <string name="submission_done_share_keys">"Teilen Sie Ihre Zufalls-IDs, damit andere gewarnt werden können."</string> <!-- YTXT: text after submission: contagious --> - <string name="submission_done_contagious">"Das Gesundheitsamt wird sich in den nächsten Tagen bei Ihnen melden."</string> + <string name="submission_done_contagious">"Das Gesundheitsamt wird sich möglicherweise in den nächsten Tagen bei Ihnen melden."</string> <!-- YTXT: text after submission: isolate --> - <string name="submission_done_isolate">"Sie sind ansteckend. Isolieren Sie sich von anderen Personen."</string> + <string name="submission_done_isolate">"Sie sind sehr wahrscheinlich ansteckend. Isolieren Sie sich von anderen Personen."</string> <!-- XHED: Title for further info --> <string name="submission_done_further_info_title">"Weitere Infos:"</string> <!-- YTXT: submission done further info bullet points --> <string-array name="submission_done_further_info_bullet_points"> - <item>"Die Quarantänezeit beträgt in der Regel 14 Tage. Bitte beobachten Sie genau, wie sich Ihre Symptome entwickeln."</item> + <item>"Die Isolationszeit beträgt in der Regel 14 Tage. Bitte beobachten Sie genau, wie sich Ihre Symptome entwickeln."</item> <item>"Sie werden von Ihrem Gesundheitsamt gebeten, eine Liste Ihrer Kontaktpersonen zu erstellen. Erfassen Sie dabei alle Personen, zu denen Sie in den zwei Tagen vor Erkrankungsbeginn engen Kontakt (unter 2 Meter, direktes Gespräch) über insgesamt 15 Minuten hatten. Nutzen Sie hierfür Ihr Kontakt-Tagebuch. Sie können die Einträge einfach exportieren und ausdrucken oder als E-Mail verschicken."</item> <item>"Bitte denken Sie hier auch besonders an Personen, die nicht automatisch durch die App informiert werden, da sie kein Smartphone besitzen oder die App nicht installiert haben."</item> - <item>"Auch wenn Sie keine Symptome (mehr) haben, können Sie ansteckend sein. Bitte halten Sie die angeordnete Quarantänezeit in jedem Fall ein."</item> + <item>"Auch wenn Sie keine Symptome (mehr) haben, können Sie ansteckend sein. Bitte halten Sie die angeordnete Isolationszeit in jedem Fall ein."</item> </string-array> <!-- XBUT: submission finished button --> <string name="submission_done_button_done">"Fertig"</string> @@ -1396,9 +1401,9 @@ <!-- XHED: submission status card positive result subtitle --> <string name="submission_status_card_positive_result_subtitle">"Bitte beachten Sie:"</string> <!-- YTXT: text for contagious card --> - <string name="submission_status_card_positive_result_contagious">"Sie sind ansteckend. Isolieren Sie sich von anderen Personen."</string> + <string name="submission_status_card_positive_result_contagious">"Sie sind sehr wahrscheinlich ansteckend. Isolieren Sie sich von anderen Personen."</string> <!-- YTXT: text for contact card --> - <string name="submission_status_card_positive_result_contact">"Das Gesundheitsamt wird sich in den nächsten Tagen bei Ihnen melden."</string> + <string name="submission_status_card_positive_result_contact">"Das Gesundheitsamt wird sich möglicherweise in den nächsten Tagen bei Ihnen melden."</string> <!-- YTXT: text for share result card--> <string name="submission_status_card_positive_result_share">"Teilen Sie Ihre Zufalls-IDs, damit andere gewarnt werden können."</string> @@ -1992,7 +1997,7 @@ <!-- XHED: Trace location poster title --> <string name="trace_location_organiser_poster_title">"Druckversion"</string> <!-- XHED: Trace location check-ins consent screen title --> - <string name="trace_location_attendee_consent_title">Check-ins für diese Orte teilen?</string> + <string name="trace_location_attendee_consent_title">Check-ins teilen?</string> <!-- XTXT: Trace location check-ins consent screen header description --> <string name="trace_location_attendee_consent_header_description">Teilen Sie Ihre Check-ins, um andere zu warnen, die mit Ihnen eingecheckt waren. Ihre Identität bleibt geheim.</string> <!-- XBUT: Trace location check-ins consent screen header button --> diff --git a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml index 1299bc10fd14f186bb6ee6da42b26a2b6bb1e0ca..31cbf05d34c5faa786ca3bda7963bdae7b497e2b 100644 --- a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<resources> +<resources xmlns:tools="http://schemas.android.com/tools"> <!-- XTXT: Vaccination Details birth date --> <string name="vaccination_details_birth_date">Geboren %1$s</string> <!-- XTXT: Vaccination Details certificate date --> @@ -16,47 +16,44 @@ <string name="vaccination_details_certificate_country">Land</string> <!-- XTXT: Vaccination Details certificate id --> <string name="vaccination_details_certificate_id">Zertifikationsnummer</string> - <!-- XBUT: Vaccination Details delete button --> - <string name="vaccination_details_delete_button">Impfzertifikat entfernen</string> <!-- XTXT: Vaccination Details subtitle--> <string name="vaccination_details_subtitle">Impfzertifikat</string> <!-- XTXT: Vaccination Details title--> <string name="vaccination_details_title">Impfung %1$d von %2$d</string> <!-- XTXT: Vaccination Qr Code card title--> - <string name="vaccination_qr_code_card_title">Impfzertifikat %1$d von %2$d</string> + <string name="vaccination_qrcode_card_title">Impfzertifikat %1$d von %2$d</string> <!-- XTXT: Vaccination Qr Code card subtitle--> - <string name="vaccination_qr_code_card_subtitle">Geimpft %1$s - gültig bis %2$s</string> - <!-- XTXT: Vaccination Details deletion dialog title--> - <string name="vaccination_details_deletion_dialog_title">Wollen Sie das Impfzertifikat wirklich entfernen?</string> - <!-- XTXT: Vaccination Details deletion dialog message--> - <string name="vaccination_details_deletion_dialog_message">Wenn Sie das Impfzertifikat entfernen, kann die App die Impfung nicht mehr für die Prüfung Ihres Impfstatus berücksichtigen.</string> - <!-- XBUT: Vaccination Details deletion dialog positive button--> - <string name="vaccination_details_deletion_dialog_positive_button">Entfernen</string> - <!-- XBUT: Vaccination Details deletion dialog negative button--> - <string name="vaccination_details_deletion_dialog_negative_button">Abbrechen</string> + <string name="vaccination_qrcode_card_subtitle">Geimpft %1$s - gültig bis %2$s</string> <!-- XTXT: Vaccination List title--> <string name="vaccination_list_title">Digitaler Impfnachweis</string> - <!-- XTXT: Vaccination List complete vaccination subtitle--> - <string name="vaccination_list_complete_vaccination_subtitle">SARS-CoV-2-Impfschutz</string> - <!-- XTXT: Vaccination List top card title--> - <string name="vaccination_list_top_card_title">SARS-CoV-2 Impfung</string> <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_top_card_subtitle">Unvollständiger Impfschutz</string> - <!-- XTXT: Vaccination List name card subtitle--> <string name="vaccination_list_name_card_subtitle">geboren %1$s</string> <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_vaccination_card_title">Impfung %1$s von %2$s</string> + <string name="vaccination_list_vaccination_card_title">Impfung %1$d von %2$d</string> <!-- XTXT: Vaccination List top card subtitle--> <string name="vaccination_list_vaccination_card_subtitle">durchgeführt am %1$s</string> - <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_certificate_card_title">COVID-19-Prüfzertifikat</string> - <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_certificate_card_subtitle">Noch %1$d Tage gültig</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tag vollständig.</item> + <item quantity="other">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="zero">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="two">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="few">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="many">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + </plurals> <!-- XBUT: Vaccination List register additional vaccination button --> <string name="vaccination_list_register_new_vaccination_button">Weitere Impfung registrieren</string> - <!-- XBUT: Vaccination List refresh button --> - <string name="vaccination_list_refresh_button">Aktualisieren</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">Entfernen</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">Wollen Sie das Impfzertifikat wirklich entfernen?</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">Wenn Sie das Impfzertifikat entfernen, kann die App die Impfung nicht mehr für die Prüfung Ihres Impfstatus berücksichtigen.</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">Entfernen</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">Abbrechen</string> <!-- XACT: Vaccination List Qr-Code for screen readers --> <string name="vaccination_list_qr_code_accessibility">Qr-Code</string> @@ -64,18 +61,27 @@ Homescreen cards ###################################### --> <!-- XHED: Title for Vaccination Certificate Registration Home Card --> - <string name="vaccination_card_registration_title">"Impfzertifikat registrieren"</string> + <string name="vaccination_card_registration_title">"Impfzertifikat hinzufügen"</string> <!-- YTXT: Body text for Vaccination Certificate Registration Home Card --> - <string name="vaccination_card_registration_body">"Scannen Sie den QR-Code auf Ihrem Impfzertifikat, um Ihre Impfung zu registrieren und einen digitalen Impfnachweis zu erhalten."</string> + <string name="vaccination_card_registration_body">"Fügen Sie Ihre Impfzertifikate in die App hinzu, um sie immer bei sich zu haben. Scannen Sie dafür den QR-Code Ihres Dokuments."</string> <!-- XBUT: button for Vaccination Certificate Registration Home Card --> - <string name="vaccination_card_register">"Registrieren"</string> - + <string name="vaccination_card_register">"Hinzufügen"</string> <!-- XHED: Homescreen vaccination status card title --> <string name="vaccination_card_status_title">Digitaler Impfnachweis</string> <!-- XHED: Homescreen vaccination status card vaccination name --> <string name="vaccination_card_status_vaccination_name">SARS-CoV-2 Impfschutz</string> - <!-- XTXT: Homescreen vaccination status card vaccination status label --> + <!-- XTXT: Homescreen card incomplete vaccination status label --> <string name="vaccination_card_status_vaccination_incomplete">Unvollständiger Impfschutz</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete" tools:ignore="UnusedQuantity"> + <item quantity="one">Vollständiger Impfschutz in %1$d Tag</item> + <item quantity="other">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="zero">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="two">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="few">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="many">Vollständiger Impfschutz in %1$d Tagen</item> + </plurals> + <!-- XTXT: Vaccination QR code scan error message--> <string name="error_vc_invalid">Dieser QR-Code ist kein gültiges Impfzertifikat.</string> <!-- XTXT: Vaccination QR code scan error message--> @@ -87,4 +93,21 @@ <!-- XTXT: Vaccination QR code scan error message--> <string name="error_vc_different_person">Die persönlichen Daten dieses Impfzertifikats stimmen nicht mit denen der bereits registrierten Zertifikate überein. Sie können in der App nur Zertifikate einer Person registrieren.</string> + <!-- XTXT: Vaccination Consent title--> + <string name="vaccination_consent_title">Ihr Einverständnis</string> + <!-- XTXT: Vaccination Consent subtitle--> + <string name="vaccination_consent_headline">Impfzertifikat hinzufügen</string> + <!-- XTXT: Vaccination Consent subtitle of qr info --> + <string name="vaccination_consent_info_subtitle_text">"Fügen Sie Ihren digitalen Impfnachweis in der App hinzu. Sobald Ihr Impfschutz vollständig ist, können Sie den QR-Code in der App vorzeigen, um Ihren Impfschutz nachzuweisen."</string> + <!-- XTXT: Vaccination Consent text of qr info --> + <string name="vaccination_consent_qr_info_text">"Um ein Impfzertifikat in die App hinzuzufügen, scannen Sie den QR-Code, den Sie bei der Impfung erhalten haben."</string> + <!-- XTXT: Vaccination Consent qr code text --> + <string name="vaccination_consent_qr_info_qr_code_text">"Die App liest die Informationen aus dem QR-Code aus und speichert diese in einem sicheren Bereich Ihres Smartphones."</string> + <!-- XTXT: Vaccination Consent time text --> + <string name="vaccination_consent_qr_info_time_text">"Die Daten bleiben auf Ihrem Smartphone. Eine Übertragung an andere Personen findet nur statt, wenn Sie diesen Ihr Impfzertifikat zur Überprüfung vorzeigen."</string> + <!-- XTXT: Text for vaccination consent legal information button --> + <string name="vaccination_consent_onboarding_legal_information">"Weitere Hinweise finden Sie in der Datenschutzerklärung."</string> + <!-- XBUT: Text for vaccination consent accept button --> + <string name="vaccination_consent_accept_button">"Weiter"</string> + </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml b/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml index 1d5995b81ef8561a6edeb81b260ef6bad78e0c44..7a09f10daad48bcbd43615d73098a38ab68b16eb 100644 --- a/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml +++ b/Corona-Warn-App/src/main/res/values-tr/legal_strings.xml @@ -165,4 +165,17 @@ <string name="rat_profile_onboarding_card_consent6" translatable="false">Kare kodu kişisel verilerinizi içerir. Verilerinizin okunmasını istemiyorsanız kişisel kare kodunuzu kimseyle paylaşmayın. Kişisel kare kodunuzu paylaşmamanızı ve e-posta üzerinden göndermemenizi öneriyoruz.</string> <!-- YMSG: RAT Profile Onboarding bullet points --> <string name="rat_profile_onboarding_card_consent7" translatable="false">Özel şahıslar ya da şirketler hızlı test profilinizi göstermenizi talep edemezler.</string> + + <!-- Vaccination Consent Privacy Strings --> + <!-- XHED: Title for privacy card --> + <string name="vaccination_privacy_card_title_text" translatable="false">"Veri gizliliği ve veri güvenliği"</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_first_bulletpoint_title_text" translatable="false">"Dijital aşı sertifikasının kullanımı isteğe bağlıdır. Tam aşı korumasının gerçekleştirildiğine ilişkin kanıt, diğer yöntemlerle de sağlanabilir (örn. sarı aşı kartı ile)."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_second_bulletpoint_title_text" translatable="false">"Aşı sertifikası, yaptırdığınız Korona aşılarınıza ilişkin veriler içerir. Yasal açıdan zorunlu durumlarda aşı koruması yaptırdığınızı kanıtlamak için Uygulamada QR kodu göstermeniz yeterli olacaktır. Söz konusu verilerin okunmasını istemiyorsanız, aşı sertifikasını ve QR kodu hiç kimseye göstermeyin."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_third_bulletpoint_title_text" translatable="false">"QR kodu Uygulamada gösterirseniz ve bu kod, kontrol uygulamasıyla taranırsa, diğer kişiler sizin tam aşı koruması aldığınızı anlayabilir. Kontrol işlemi sırasında adınız ve doğum tarihiniz de resmi kontrol uygulamasında görüntülenecektir."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_fourth_bulletpoint_title_text" translatable="false">"Aşı sertifikasını istediğiniz zaman Uygulamadan kaldırma seçeneğiniz vardır. Bunu yapıncaya kadar aşı sertifikaları akıllı telefonunuzda kayıtlı kalacaktır."</string> + </resources> diff --git a/Corona-Warn-App/src/main/res/values/legal_strings.xml b/Corona-Warn-App/src/main/res/values/legal_strings.xml index 19cdd4e6e9c99b22c4fd82aab1126a8a076dbca5..d11cb77f78bea52d0463da0d41d81d44ef628d17 100644 --- a/Corona-Warn-App/src/main/res/values/legal_strings.xml +++ b/Corona-Warn-App/src/main/res/values/legal_strings.xml @@ -169,17 +169,14 @@ <!-- Vaccination Consent Privacy Strings --> <!-- XHED: Title for privacy card --> - <string name="vaccination_privacy_card_title_text" translatable="false">"Ihr Einverständnis"</string> - <!-- XTXT: Subtitle for privacy card --> - <string name="vaccination_privacy_card_subtitle_text" translatable="false">"Durch Antippen von „Einverstanden“ willigen Sie in folgende Schritte ein:"</string> + <string name="vaccination_privacy_card_title_text" translatable="false">"Data protection and data security"</string> <!-- XTXT: First bulletpoint title for privacy card --> - <string name="vaccination_privacy_card_first_bulletpoint_title_text" translatable="false">"Die App legal"</string> - <!-- XTXT: First bulletpoint subtitle for privacy card --> - <string name="vaccination_privacy_card_first_bulletpoint_subtitle_text" translatable="false">"Wenn Sie es sich später anders überlegen, können Sie den Test in der App entfernen."</string> + <string name="vaccination_privacy_card_first_bulletpoint_title_text" translatable="false">"Using the digital vaccination certificate feature is voluntary. There are other ways to prove that you are fully vaccinated (e.g. using a yellow vaccination booklet)."</string> <!-- XTXT: First bulletpoint title for privacy card --> - <string name="vaccination_privacy_card_second_bulletpoint_title_text" translatable="false">"Wenn Sie positiv auf Corona getestet wurden, teilt die App Ihr Testergebnis, um Nutzer, denen Sie begegnet sind, zu warnen. Dies betrifft Nutzer von Corona-Apps der oben genannten Länder und Nutzer, die zeitgleich am selben Event oder Ort wie Sie eingecheckt waren. Im Falle von Schnelltests werden nur Nutzer der Corona-Warn-App gewarnt."</string> + <string name="vaccination_privacy_card_second_bulletpoint_title_text" translatable="false">"The vaccination certificate contains your COVID-19 vaccination details. In cases where you are required by law to prove that you have been vaccinated, it is sufficient to show the QR code in the app. Do not provide vaccination certificates or QR codes to anyone if you do not want the data to be read."</string> <!-- XTXT: First bulletpoint title for privacy card --> - <string name="vaccination_privacy_card_third_bulletpoint_title_text" translatable="false">"Wenn Sie zusätzlich Angaben zum Beginn Ihrer Symptome machen, werden auch diese geteilt. "</string> - <!-- XTXT: Subtitle for privacy card --> - <string name="vaccination_privacy_card_body" translatable="false">"Sie können Ihr Einverständnis jederzeit zurücknehmen. Die Einstellung hierfür finden Sie unter „Test anzeigen“. Vor dem Teilen werden Sie nochmal auf Ihr Einverständnis hingewiesen."</string> + <string name="vaccination_privacy_card_third_bulletpoint_title_text" translatable="false">"If you present the QR code in the app and it is scanned using the verification app, others will be able to tell whether you are fully vaccinated. During verification, the official verification app will also display your name and date of birth."</string> + <!-- XTXT: First bulletpoint title for privacy card --> + <string name="vaccination_privacy_card_fourth_bulletpoint_title_text" translatable="false">"You have the possibility to delete vaccination certificates in the app at any time. Until then, the vaccination certificates will be stored on your smartphone."</string> + </resources> diff --git a/Corona-Warn-App/src/main/res/values/release_info_strings.xml b/Corona-Warn-App/src/main/res/values/release_info_strings.xml index 700fee76ef5384fd23a1b7cb2183624ceed8035c..111e4976d24252af61c03a60ba207e8e988da5c3 100644 --- a/Corona-Warn-App/src/main/res/values/release_info_strings.xml +++ b/Corona-Warn-App/src/main/res/values/release_info_strings.xml @@ -17,26 +17,22 @@ <!-- XHED: Titles for the release info screen bullet points --> <string-array name="new_release_title"> - <item>"Record Troubleshooting Logs"</item> - <item>"Create Rapid Test Profiles"</item> + <item>Digitaler Impfnachweis</item> </string-array> <!-- XTXT: Text bodies for the release info screen bullet points --> <string-array name="new_release_body"> - <item>"You can now generate an error log in the technical support feature for the app. It records the steps that you perform in the app, to simplify the analysis of potential errors and help us correct them more quickly."</item> - <item>"You can now create a rapid test profile in your personal data. Your profile can then be scanned at testing points quickly and easily via QR code."</item> + <item>Sie können jetzt Ihre Impfzertifikate in der App hinzufügen und per QR-Code vorweisen. 14 Tage nach der letzten Impfung zeigt die App den vollständigen Impfschutz an.</item> </string-array> <!-- XTXT: Text labels that will be converted to Links --> <string-array name="new_release_linkified_labels"> - <item /> - <item /> + <item></item> </string-array> <!-- XTXT: URL destinations for the lables in new_release_linkified_labels --> <string-array name="new_release_target_urls"> - <item /> - <item /> + <item></item> </string-array> -</resources> \ No newline at end of file +</resources> diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index d51d93ca101f0afafea9e6b273409a6c76b0038e..6901a354374c9079304532a17c23779bbfe567f8 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -1067,7 +1067,6 @@ <string name="submission_test_result_steps_added_heading">"Test added successfully"</string> <!-- YTXT: Body text for for results next steps --> <string name="submission_test_result_steps_added_body">"Your test has been stored in the Corona-Warn-App."</string> - <!-- XHED: Page headline for pending test result next steps --> <string name="submission_test_result_pending_steps_waiting_heading">"Your test result is not available yet."</string> <!-- YTXT: Body text for next steps section of waiting test result page --> @@ -1107,10 +1106,18 @@ <string name="submission_test_result_positive_continue_button_with_symptoms">"Enter Symptoms"</string> <!-- XBUT: positive test result : continue button without symptoms --> <string name="submission_test_result_positive_continue_button_wo_symptoms">"Don’t Enter Symptoms"</string> + + <!-- XHED: Page headline for invalid test result screen --> <string name="submission_test_result_invalid_steps_invalid_heading">"Your Test Result"</string> + <!-- XHED: Page headline for invalid test result screen --> + <string name="submission_test_result_delete_steps_invalid_heading">"Test entfernen"</string> + <!-- YTXT: Body text for next steps section of invalid test result--> <string name="submission_test_result_invalid_steps_invalid_body">"There was a problem evaluating your test. Please contact the test center or laboratory involved to find out how to proceed.\n\nPlease delete the test from your Corona-Warn-App so that you will be able to save a new test code there, if necessary."</string> + <!-- YTXT: Body text for next steps section of invalid test result--> + <string name="submission_test_result_delete_steps_invalid_body">"Bitte entfernen Sie den Test wieder aus der Corona-Warn-App, damit Sie bei Bedarf einen neuen Test hinterlegen können."</string> + <!-- XBUT: invalid test result : remove the test button --> <string name="submission_test_result_invalid_remove_test_button">"Remove test"</string> <!-- XHED: Dialog title for tracing required dailog --> @@ -1164,7 +1171,7 @@ <!-- Dispatcher --> <!-- XHED: Page headline for dispatcher menu --> - <string name="submission_dispatcher_headline">"Retrieve Test Result"</string> + <string name="submission_dispatcher_headline">"Test registrieren"</string> <!-- XHED: Page subheadline for dispatcher menu --> <string name="submission_dispatcher_subheadline">"Retrieve your test result through the app and then warn others. You’ll protect yourself and help to stop the spread of coronavirus."</string> <!-- XHED: Page subheadline for dispatcher options asking if they have already been tested: QR and TAN --> diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index e24c21b570aa34f8361a9884dc5c365e65a4879d..f9da4f1b3890a684198013169a70e7ea7143b9c3 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -243,6 +243,10 @@ <item name="android:background">@drawable/grey_card_ripple</item> </style> + <style name="Card.Vaccination.Ripple.NoPadding"> + <item name="android:padding">@dimen/no_padding</item> + </style> + <style name="Card.NoPadding"> <item name="android:padding">@dimen/no_padding</item> </style> @@ -257,6 +261,11 @@ <item name="android:background">@drawable/grey_card_ripple</item> </style> + <style name="dispatcherImageStyle"> + <item name="cornerFamily">rounded</item> + <item name="cornerSizeBottomRight">@dimen/radius_card</item> + </style> + <style name="BlueCard"> <item name="android:background">@drawable/blue_card_ripple</item> </style> diff --git a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml index 12ece40941b608dc4fbeef9422e9f02dc40adde9..80ce5d67e97a08172f945bcd6420adb4d89a09f9 100644 --- a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml +++ b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml @@ -16,24 +16,14 @@ <string name="vaccination_details_certificate_country">Land</string> <!-- XTXT: Vaccination Details certificate id --> <string name="vaccination_details_certificate_id">Zertifikationsnummer</string> - <!-- XBUT: Vaccination Details delete button --> - <string name="vaccination_details_delete_button">Impfzertifikat entfernen</string> <!-- XTXT: Vaccination Details subtitle--> <string name="vaccination_details_subtitle">Impfzertifikat</string> <!-- XTXT: Vaccination Details title--> <string name="vaccination_details_title">Impfung %1$d von %2$d</string> <!-- XTXT: Vaccination Qr Code card title--> - <string name="vaccination_qr_code_card_title">Impfzertifikat %1$d von %2$d</string> + <string name="vaccination_qrcode_card_title">Impfzertifikat %1$d von %2$d</string> <!-- XTXT: Vaccination Qr Code card subtitle--> - <string name="vaccination_qr_code_card_subtitle">Geimpft %1$s - gültig bis %2$s</string> - <!-- XTXT: Vaccination Details deletion dialog title--> - <string name="vaccination_details_deletion_dialog_title">Wollen Sie das Impfzertifikat wirklich entfernen?</string> - <!-- XTXT: Vaccination Details deletion dialog message--> - <string name="vaccination_details_deletion_dialog_message">Wenn Sie das Impfzertifikat entfernen, kann die App die Impfung nicht mehr für die Prüfung Ihres Impfstatus berücksichtigen.</string> - <!-- XBUT: Vaccination Details deletion dialog positive button--> - <string name="vaccination_details_deletion_dialog_positive_button">Entfernen</string> - <!-- XBUT: Vaccination Details deletion dialog negative button--> - <string name="vaccination_details_deletion_dialog_negative_button">Abbrechen</string> + <string name="vaccination_qrcode_card_subtitle">Geimpft %1$s - gültig bis %2$s</string> <!-- XTXT: Vaccination List title--> <string name="vaccination_list_title">Digitaler Impfnachweis</string> @@ -46,17 +36,30 @@ <!-- XTXT: Vaccination List name card subtitle--> <string name="vaccination_list_name_card_subtitle">geboren %1$s</string> <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_vaccination_card_title">Impfung %1$s von %2$s</string> + <string name="vaccination_list_vaccination_card_title">Impfung %1$d von %2$d</string> <!-- XTXT: Vaccination List top card subtitle--> <string name="vaccination_list_vaccination_card_subtitle">durchgeführt am %1$s</string> - <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_certificate_card_title">COVID-19-Prüfzertifikat</string> - <!-- XTXT: Vaccination List top card subtitle--> - <string name="vaccination_list_certificate_card_subtitle">Noch %1$d Tage gültig</string> + <!-- XTXT: Vaccination List immunity information card body--> + <plurals name="vaccination_list_immunity_card_body"> + <item quantity="one">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tag vollständig.</item> + <item quantity="other">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="zero">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="two">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="few">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + <item quantity="many">Sie haben nun alle Impfungen erhalten. Allerdings ist der Impfschutz erst in %1$d Tagen vollständig.</item> + </plurals> <!-- XBUT: Vaccination List register additional vaccination button --> <string name="vaccination_list_register_new_vaccination_button">Weitere Impfung registrieren</string> - <!-- XBUT: Vaccination List refresh button --> - <string name="vaccination_list_refresh_button">Aktualisieren</string> + <!-- XBUT: Vaccination List delete button --> + <string name="vaccination_list_delete_button">Entfernen</string> + <!-- XTXT: Vaccination List deletion dialog title--> + <string name="vaccination_list_deletion_dialog_title">Wollen Sie das Impfzertifikat wirklich entfernen?</string> + <!-- XTXT: Vaccination List deletion dialog message--> + <string name="vaccination_list_deletion_dialog_message">Wenn Sie das Impfzertifikat entfernen, kann die App die Impfung nicht mehr für die Prüfung Ihres Impfstatus berücksichtigen.</string> + <!-- XBUT: Vaccination List deletion dialog positive button--> + <string name="vaccination_list_deletion_dialog_positive_button">Entfernen</string> + <!-- XBUT: Vaccination List deletion dialog negative button--> + <string name="vaccination_list_deletion_dialog_negative_button">Abbrechen</string> <!-- XACT: Vaccination List Qr-Code for screen readers --> <string name="vaccination_list_qr_code_accessibility">Qr-Code</string> @@ -74,8 +77,17 @@ <string name="vaccination_card_status_title">Digitaler Impfnachweis</string> <!-- XHED: Homescreen vaccination status card vaccination name --> <string name="vaccination_card_status_vaccination_name">SARS-CoV-2 Impfschutz</string> - <!-- XTXT: Homescreen card vaccination status label --> + <!-- XTXT: Homescreen card incomplete vaccination status label --> <string name="vaccination_card_status_vaccination_incomplete">Unvollständiger Impfschutz</string> + <!-- XTXT: Homescreen card complete vaccination status label --> + <plurals name="vaccination_card_status_vaccination_complete"> + <item quantity="one">Vollständiger Impfschutz in %1$d Tag</item> + <item quantity="other">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="zero">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="two">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="few">Vollständiger Impfschutz in %1$d Tagen</item> + <item quantity="many">Vollständiger Impfschutz in %1$d Tagen</item> + </plurals> <!-- XTXT: Vaccination QR code scan error message--> <string name="error_vc_invalid"></string> diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e6c2927121c341a2a08c37e043b5953f86340121 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt @@ -0,0 +1,130 @@ +package de.rki.coronawarnapp.bugreporting.censors.vaccination + +import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 +import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.mockk +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class CertificateQrCodeCensorTest { + + private val testRawString = + "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3.ZH9M9ESIGUBA KWML/O6HXK 0D+4O5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3GG396B-43FZT-43:S0X37*ZV+FNI6HXY0ZSVILVQJF//05MVZJ5V.499TXY9KK9+OC+G9QJPNF67J6QW67KQY466PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIJSBHVA7UJQWT.+S+ND%%M%331BH.IA.C8KRDL4O54O4IGUJKJGI0JAXD15IAXMFU*GSHGHD63DAOC9JU0H11+*4.\$S6ZC0JBZAB-C3QHISKE MCAOI8%M3V96-PY\$N6XOWLIBPIAYU:*JIRHUF2XZQ4H9 XJ72WG1K36VF/9BL56%E8T1OEEG%5TW5A 6YO67N6UCE:WT6BT-UMM:ABJK2TMDN1:FW-%T+\$D78NDSC3%5F61NYS-P9LOE0%J/ZAY:N5L4H-H/LH:AO3FU JHG7K46IOIMT.RE%PHLA21JRI3HTC\$AH" + private val testCertificateData = VaccinationCertificateData( + header = mockk(), + certificate = VaccinationDGCV1( + version = "1", + nameData = VaccinationDGCV1.NameData( + familyName = "Kevin", + familyNameStandardized = "Kevin2", + givenName = "Bob", + givenNameStandardized = "Bob2" + ), + dob = "1969-11-16", + vaccinationDatas = listOf( + VaccinationDGCV1.VaccinationData( + targetId = "12345", + vaccineId = "1214765", + medicalProductId = "aaEd/easd", + marketAuthorizationHolderId = "ASD-2312", + doseNumber = 2, + totalSeriesOfDoses = 5, + dt = "1969-04-20", + countryOfVaccination = "DE", + certificateIssuer = "Herbert", + uniqueCertificateIdentifier = "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ" + ) + ) + ) + ) + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + } + + @AfterEach + fun teardown() { + CertificateQrCodeCensor.clearCertificateToCensor() + CertificateQrCodeCensor.clearQRCodeStringToCensor() + } + + private fun createInstance() = CertificateQrCodeCensor() + + @Test + fun `checkLog() should return censored LogLine`() = runBlockingTest { + CertificateQrCodeCensor.addQRCodeStringToCensor(testRawString) + CertificateQrCodeCensor.addCertificateToCensor(testCertificateData) + + val censor = createInstance() + + val logLineToCensor = LogLine( + timestamp = 1, + priority = 3, + message = "Here comes the rawString: $testRawString of the vaccine certificate", + tag = "I am tag", + throwable = null + ) + + censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( + message = "Here comes the rawString: ########-####-####-####-########C\$AH of the vaccine certificate", + ) + + val certDataToCensor = LogLine( + timestamp = 1, + priority = 3, + message = "Hello my name is Kevin Bob, i was born at 1969-11-16, i have been " + + "vaccinated with: 12345 1214765 aaEd/easd ASD-2312 1969-04-20 DE Herbert" + + " urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ", + tag = "I am tag", + throwable = null + ) + + censor.checkLog(certDataToCensor) shouldBe certDataToCensor.copy( + message = "Hello my name is nameData/familyName nameData/givenName, i was born at " + + "vaccinationCertificate/dob, i have been vaccinated with: vaccinationData/targetId " + + "vaccinationData/vaccineId vaccinationData/medicalProductId" + + " vaccinationData/marketAuthorizationHolderId vaccinationData/dt" + + " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" + + " vaccinationData/uniqueCertificateIdentifier" + ) + } + + @Test + fun `checkLog() should return null if no data to censor was set`() = runBlockingTest { + val censor = createInstance() + + val logLineNotToCensor = LogLine( + timestamp = 1, + priority = 3, + message = "Here comes the rawData: $testRawString", + tag = "I am tag", + throwable = null + ) + + censor.checkLog(logLineNotToCensor) shouldBe null + } + + @Test + fun `checkLog() should return null if nothing should be censored`() = runBlockingTest { + CertificateQrCodeCensor.addQRCodeStringToCensor(testRawString.replace("1", "2")) + CertificateQrCodeCensor.addCertificateToCensor(testCertificateData) + + val censor = createInstance() + + val logLineNotToCensor = LogLine( + timestamp = 1, + priority = 3, + message = "Here comes the rawString: $testRawString", + tag = "I am tag", + throwable = null + ) + + censor.checkLog(logLineNotToCensor) shouldBe null + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt index b4ccfd775f08b740cb3f13e00e4ee8e1b7c3384f..0bba493b4fee073d7150fd8fa0bd294693a80f55 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt @@ -2,12 +2,13 @@ package de.rki.coronawarnapp.bugreporting.debuglog.internal import android.content.Context import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone import de.rki.coronawarnapp.util.TimeStamper import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK -import org.joda.time.Instant +import org.joda.time.DateTime import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -26,7 +27,7 @@ class LogSnapshotterTest : BaseIOTest() { private val runningLogFake = File(testDir, "running.log") private val snapshotDir = File(cacheDir, "debuglog_snapshots") - private val expectedSnapshot = File(snapshotDir, "CWA Log 1970-01-01 00:00:00.000.zip") + private val expectedSnapshot = File(snapshotDir, "CWA Log 1970-01-01 00_00_00.000.zip") @BeforeEach fun setup() { @@ -38,7 +39,7 @@ class LogSnapshotterTest : BaseIOTest() { testDir.exists() shouldBe true every { debugLogger.runningLog } returns runningLogFake - every { timeStamper.nowUTC } returns Instant.EPOCH + every { timeStamper.nowUTC.toUserTimeZone() } returns DateTime.parse("1970-01-01T00:00:00.000Z") runningLogFake.parentFile!!.mkdirs() runningLogFake.writeText("1 Doge = 1 Doge") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt index 869893adae7cea43d461d87dd4b3ceb7001221db..12b178e9db9fd377c5eadcb406fb522a264d50e9 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/environment/EnvironmentSetupTest.kt @@ -68,7 +68,6 @@ class EnvironmentSetupTest : BaseTest() { dataDonationCdnUrl shouldBe "https://datadonation-${env.rawKey}" logUploadServerUrl shouldBe "https://logupload-${env.rawKey}" crowdNotifierPublicKey shouldBe "123_abc-${env.rawKey}" - vaccinationCdnUrl shouldBe "https://vaccination-${env.rawKey}" } } } @@ -128,8 +127,7 @@ class EnvironmentSetupTest : BaseTest() { EnvironmentSetup.EnvKey.LOG_UPLOAD.rawKey shouldBe "LOG_UPLOAD_SERVER_URL" EnvironmentSetup.EnvKey.SAFETYNET_API_KEY.rawKey shouldBe "SAFETYNET_API_KEY" EnvironmentSetup.EnvKey.CROWD_NOTIFIER_PUBLIC_KEY.rawKey shouldBe "CROWD_NOTIFIER_PUBLIC_KEY" - EnvironmentSetup.EnvKey.VACCINATION_VALUE.rawKey shouldBe "VACCINATION_CDN_URL" - EnvironmentSetup.EnvKey.values().size shouldBe 10 + EnvironmentSetup.EnvKey.values().size shouldBe 9 } companion object { diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt index 991ff951b66a1fbd02790442638020e2d403135c..065b85b7f36cc75781f53b78208ff919ec348c62 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/scan/ScanCheckInQrCodeViewModelTest.kt @@ -1,14 +1,19 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.scan -import com.google.zxing.Result import com.journeyapps.barcodescanner.BarcodeResult +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QRCodeUriParser +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocationVerifier +import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass +import de.rki.coronawarnapp.ui.presencetracing.attendee.scan.ScanCheckInQrCodeNavigation.ScanResultNavigation import de.rki.coronawarnapp.util.permission.CameraSettings import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations +import io.mockk.coEvery import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.mockk import io.mockk.verify +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -21,13 +26,17 @@ import testhelpers.preferences.mockFlowPreference class ScanCheckInQrCodeViewModelTest : BaseTest() { private lateinit var viewModel: ScanCheckInQrCodeViewModel + @MockK lateinit var qrCodeUriParser: QRCodeUriParser @MockK lateinit var cameraSettings: CameraSettings + @MockK lateinit var traceLocationVerifier: TraceLocationVerifier @BeforeEach fun setup() { MockKAnnotations.init(this) viewModel = ScanCheckInQrCodeViewModel( - cameraSettings + qrCodeUriParser, + cameraSettings, + traceLocationVerifier ) } @@ -38,15 +47,21 @@ class ScanCheckInQrCodeViewModelTest : BaseTest() { } @Test - fun `onScanResult results in navigation url`() { - val mockedResult = mockk<BarcodeResult>().apply { - every { result } returns mockk<Result>().apply { - every { text } returns "https://coronawarn.app/E1/SOME_PATH_GOES_HERE" + fun `onScanResult results in navigation url`() = runBlockingTest { + val codeContent = "https://coronawarn.app/E1/SOME_PATH_GOES_HERE" + val expectedOutcome: ScanCheckInQrCodeNavigation = ScanResultNavigation(codeContent) + val validationPassed = mockk<TraceLocationVerifier.VerificationResult.Valid>() + val mockedResult = mockk<BarcodeResult> { + every { result } returns mockk { + every { text } returns codeContent } } + val qrCodePayload = mockk<TraceLocationOuterClass.QRCodePayload>() + coEvery { qrCodeUriParser.getQrCodePayload(any()) } returns qrCodePayload + every { traceLocationVerifier.verifyTraceLocation(qrCodePayload) } returns validationPassed + viewModel.onScanResult(mockedResult) - viewModel.events.getOrAwaitValue() shouldBe - ScanCheckInQrCodeNavigation.ScanResultNavigation("https://coronawarn.app/E1/SOME_PATH_GOES_HERE") + viewModel.events.getOrAwaitValue() shouldBe expectedOutcome } @Test diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt index 1dfedac57403a304eb753e1193f923402fbab5b2..3dbba9d531d6e633a583ac0c0e946e78a18fbb80 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/DataResetTest.kt @@ -26,6 +26,7 @@ import de.rki.coronawarnapp.submission.SubmissionSettings import de.rki.coronawarnapp.ui.presencetracing.TraceLocationPreferences import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository import de.rki.coronawarnapp.vaccination.core.VaccinationPreferences +import de.rki.coronawarnapp.vaccination.core.repository.ValueSetsRepository import io.mockk.MockKAnnotations import io.mockk.coVerify import io.mockk.impl.annotations.MockK @@ -62,6 +63,7 @@ internal class DataResetTest : BaseTest() { @MockK lateinit var ratProfileSettings: RATProfileSettings @MockK lateinit var vaccinationRepository: VaccinationRepository @MockK lateinit var vaccinationPreferences: VaccinationPreferences + @MockK lateinit var valueSetsRepository: ValueSetsRepository @BeforeEach fun setUp() { @@ -95,6 +97,7 @@ internal class DataResetTest : BaseTest() { ratProfileSettings = ratProfileSettings, vaccinationPreferences = vaccinationPreferences, vaccinationRepository = vaccinationRepository, + valueSetsRepository = valueSetsRepository ) @Test @@ -128,6 +131,7 @@ internal class DataResetTest : BaseTest() { ratProfileSettings.deleteProfile() vaccinationRepository.clear() vaccinationPreferences.clear() + valueSetsRepository.clear() } } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt index 686426f4001791be9b32b9a9b141282c45a22ed4..5822f0e6951db3d730211a1a609c0c3d8c5fc608 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinatedPersonIdentifierTest.kt @@ -1,5 +1,9 @@ package de.rki.coronawarnapp.vaccination.core +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode +import io.kotest.assertions.throwables.shouldNotThrowAny +import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.shouldBe import org.joda.time.LocalDate import org.junit.jupiter.api.Test @@ -43,4 +47,23 @@ class VaccinatedPersonIdentifierTest : BaseTest() { person1.code shouldBe person2.code person1.codeSHA256 shouldBe person2.codeSHA256 } + + @Test + fun `required matching`() { + shouldNotThrowAny { + testPersonMaxData.requireMatch(testPersonMaxData) + } + + shouldThrow<InvalidHealthCertificateException> { + testPersonMaxData.requireMatch(testPersonMaxData.copy(firstNameStandardized = "nope")) + }.errorCode shouldBe ErrorCode.VC_NAME_MISMATCH + + shouldThrow<InvalidHealthCertificateException> { + testPersonMaxData.requireMatch(testPersonMaxData.copy(lastNameStandardized = "nope")) + }.errorCode shouldBe ErrorCode.VC_NAME_MISMATCH + + shouldThrow<InvalidHealthCertificateException> { + testPersonMaxData.requireMatch(testPersonMaxData.copy(dateOfBirth = LocalDate.parse("1900-12-31"))) + }.errorCode shouldBe ErrorCode.VC_DOB_MISMATCH + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQrCodeTestData.java b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationQrCodeTestData.java similarity index 84% rename from Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQrCodeTestData.java rename to Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationQrCodeTestData.java index 895f159f3203d8ffcfb85775d0d6ca2b1e9b7b97..82558ff23b6f13453b7bfd5f22557633710f2d6f 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQrCodeTestData.java +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationQrCodeTestData.java @@ -1,4 +1,4 @@ -package de.rki.coronawarnapp.vaccination.core.qrcode; +package de.rki.coronawarnapp.vaccination.core; public class VaccinationQrCodeTestData { static public String validVaccinationQrCode = "HC1:6BFOXN*TS0BI$ZD4N9:9S6RCVN5+O30K3/XIV0W23NTDEXWK G2EP4J0BGJLFX3R3VHXK.PJ:2DPF6R:5SVBHABVCNN95SWMPHQUHQN%A0SOE+QQAB-HQ/HQ7IR.SQEEOK9SAI4- 7Y15KBPD34 QWSP0WRGTQFNPLIR.KQNA7N95U/3FJCTG90OARH9P1J4HGZJKBEG%123ZC$0BCI757TLXKIBTV5TN%2LXK-$CH4TSXKZ4S/$K%0KPQ1HEP9.PZE9Q$95:UENEUW6646936HRTO$9KZ56DE/.QC$Q3J62:6LZ6O59++9-G9+E93ZM$96TV6NRN3T59YLQM1VRMP$I/XK$M8PK66YBTJ1ZO8B-S-*O5W41FD$ 81JP%KNEV45G1H*KESHMN2/TU3UQQKE*QHXSMNV25$1PK50C9B/9OK5NE1 9V2:U6A1ELUCT16DEETUM/UIN9P8Q:KPFY1W+UN MUNU8T1PEEG%5TW5A 6YO67N6BBEWED/3LS3N6YU.:KJWKPZ9+CQP2IOMH.PR97QC:ACZAH.SYEDK3EL-FIK9J8JRBC7ADHWQYSK48UNZGG NAVEHWEOSUI2L.9OR8FHB0T5HM7I"; @@ -7,4 +7,5 @@ public class VaccinationQrCodeTestData { static public String certificateMissing = "HC1:NCFNA0%00FFWTWGVLKJ99K83X4C8DTTMMX*4P8B3XK2F3$8JVJG2F3$%IQJG/IC6TAY50.FK6ZK6:ETPCBEC8ZKW.CNWE.Y92OAGY82+8UB8-R7/0A1OA1C9K09UIAW.CE$E7%E7WE KEVKER EB39W4N*6K3/D5$CMPCG/DA8DBB85IAAY8WY8I3DA8D0EC*KE: CZ CO/EZKEZ96446C56GVC*JC1A6NA73W5KF6TF627BSKL*8F.MLCM6$-I99MG$8THRJSCJVM/*V:0EY1QU 77*D9KR$SKIP5S-I2-RA1CC06+CHPYQX96*SUF3WZ36NM3XPK1P8.MAFZ6SHB"; static public String validVaccinationQrCode3 = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH%TAIOOW%I-1W0658WA/UAN9AAT4V22F/8X*G3M9JUPY0BX/KR96R/S09T./0LWTKD33236J3TA3M*4VV2 73-E3ND3DAJ-43%*48YIB73A*G3W19UEBY5:PI0EGSP4*2D$43B+2SEB7:I/2DY73CIBC:G 7376BXBJBAJ UNFMJCRN0H3PQN*E33H3OA70M3FMJIJN523S+0B/S7-SN2H N37J3JFTULJ5CB3ZCIATULV:SNS8F-67N%21Q21$48X2+36D-I/2DBAJDAJCNB-43SZ4RZ4E%5B/9OK53:UCT16DEZIE IE9.M CVCT1+9V*QERU1MK93P5 U02Y9.G9/G9F:QQ28R3U6/V.*NT*QM.SY$N-P1S29 34S0BYBRC.UYS1U%O6QKN*Q5-QFRMLNKNM8JI0EUGP$I/XK$M8-L9KDI:ZH2E4EVS6O0FVAQNJT:EZ6Q%D0*T1.XSDYV0.VI2OKSNODA.BOD:C.OTXS02:M5OGJIF4LHJW7FFJ2NLGFL/EE%CJF+KM%V$AUS:H+NARLK IBMMG"; static public String validVaccinationQrCode4 = "HC1:6BFOXN*TS0BI$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3KXH9M9ESIGUBA KWML%6S5B9-+P70Q5VC9:BPCNYKMXEE1JAA/CXGG0JK1WL260X638J3-E3ND3DAJ-43TTTO3HK1H3QBCWNZ83UQJ:T0/8F7V0HKN:Q8.HBV+0SZ4GH00T9UKP0T9WC5PF6846A$Q$76QW6%V98T5$FQMI5DN9QZ5Y0Q$UPE%5MZ5*T57ZA$O7T6LEJOA+MZ55EII-EB1EKC422JBBD0D2K.EJJ14B2MP41WTRZPQEC5L64HX6IAS 8S8FT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKG8VG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT$.FTD852IWKP/HLIJL8JF8JF172IMAS EDAHMXFBFBQSKJE72KV$FHJ%3O%6:XM+1QD+T2/VKKER3L3%1THL7MGY.1S:T:GLOX6OCE7+RWYL3.C-L27WNV0G::M74O%K7C50AAEI4"; + static public String qrCodeWithNonsenseCountry = "HC1:NCF3Y28.P-O0PS3JPU7RBWBA2*9VTS/9VZ+PLUOVTJ$EB7W3R9B3VN/3A44E./EZ.6Y8C$.C.IK6MA$00J1TQZ9$9IU+S7HP%X9%*MW09:4WB/5SWB20V5VFBBREWO+GIIUF4+PBZR7MNX/N1JIIML/X3Z.Q67RMB6:BJYE26A5NNL:CIM-A*/UZTM+QO: ACV6212500GUC+KM-5AUYGUD1330PFBA855/SNDPCSOC3KMR9X$DB61.0AESG$:THFGP-M/VI2SG/ 22SS+V8OP3R8LDJ50HR6S94JMN-84Q0C+2/8FUV9HH6N91GB3/YCHN6ALFFZL3M116O/IBU6QKJK/3FMQ0TLK-.UQOO$%A $J%H0%*J:DE6/DOKTG*F605WRK8G7S96JG0 4IF:B9VM0CIBRF/XNBOH9 SGIFJ/2CX593I0GE7FFDEQ6+UO5D+HM/2IDBI.ET/L725IHPKB/T/Q9KRJ* NOWN$6K8VOZIHJ5R29KQWSPYKYSDZRJ+1IVBFGPMXEVY6JIYI/ CVBTJ-FY%MO%RUTF17S:1OL8PVXHRPTUOTK/VF%U%:IR G"; } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt index 16b9d5cf00f6d1d5cb181993956c66a541d015cb..181970bd621adbbc1eb156126f6bd70dcbd01dd7 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestComponent.kt @@ -4,6 +4,7 @@ import dagger.Component import dagger.Module import de.rki.coronawarnapp.util.serialization.SerializationModule import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractorTest +import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepositoryTest import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationContainerTest import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationStorageTest import javax.inject.Singleton @@ -21,6 +22,7 @@ interface VaccinationTestComponent { fun inject(testClass: VaccinationContainerTest) fun inject(testClass: VaccinationQRCodeExtractorTest) fun inject(testClass: VaccinatedPersonTest) + fun inject(testClass: VaccinationRepositoryTest) @Component.Factory interface Factory { diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt index e5c19e3297000f5c72f776717d2ada42571fa159..0c5117d63094019d089ac68493a1edd962fda0cf 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/VaccinationTestData.kt @@ -1,6 +1,9 @@ package de.rki.coronawarnapp.vaccination.core +import de.rki.coronawarnapp.vaccination.core.certificate.HealthCertificateHeader import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 +import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData +import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateQRCode import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationContainer @@ -12,7 +15,7 @@ class VaccinationTestData @Inject constructor( ) { // AndreasAstra1.pdf - val personAVac1QR = + val personAVac1QRCodeString = "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3KXH9M9ESIGUBA KWML%6S5B9-+P70Q5VC9:BPCNYKMXEE1JAA/CXGG0JK1WL260X638J3-E3ND3DAJ-43TTTO3HK1H3QBCWNZ83UQJ:T0/8F7V0HKN:Q8.HBV+0SZ4GH00T9UKP0T9WC5PF6846A\$Q$76QW6%V98T5\$FQMI5DN9QZ5Y0Q\$UPE%5MZ5*T57ZA\$O7T6LEJOA+MZ55EII-EB1EKC422JBBD0D2K.EJJ14B2MP41WTRZPQEC5L64HX6IAS 8S8FT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKG8VG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT$.FTD852IWKP/HLIJL8JF8JF172IMAS EDAHMXFBFBQSKJE72KV\$FHJ%3O%6:XM+1QD+T2/VKKER3L3%1THL7MGY.1S:T:GLOX6OCE7+RWYL3.C-L27WNV0G::M74O%K7C50AAEI4" val personAVac1Certificate = VaccinationDGCV1( @@ -40,15 +43,31 @@ class VaccinationTestData @Inject constructor( ) ) + val personAVac1CertificateHeader = HealthCertificateHeader( + issuer = "DE", + issuedAt = Instant.parse("2021-05-11T09:25:00.000Z"), + expiresAt = Instant.parse("2022-05-11T09:25:00.000Z"), + ) + + val personAVac1CertificateData = VaccinationCertificateData( + certificate = personAVac1Certificate, + header = personAVac1CertificateHeader + ) + + val personAVac1QRCode = VaccinationCertificateQRCode( + qrCodeString = personAVac1QRCodeString, + parsedData = personAVac1CertificateData, + ) + val personAVac1Container = VaccinationContainer( scannedAt = Instant.ofEpochMilli(1620062834471), - vaccinationQrCode = personAVac1QR, + vaccinationQrCode = personAVac1QRCodeString, ).apply { qrCodeExtractor = this@VaccinationTestData.qrCodeExtractor } // AndreasAstra2.pdf - val personAVac2QR = + val personAVac2QRCodeString = "6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3D H9M9ESIGUBA KWMLYX1HXK 0DV:D5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3ND3DAJ-43TTTMDF6S8:B73QN VNZ.0K6HYI3CNN96BPHNW*0I85V.499TXY9KK9%OC+G9QJPNF67J6QW67KQ9G66PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIPUBN9CIZI.EJJ14B2MP41IZRZPQEC5L64HX6IAS 8SAFT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKGGVG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT\$.FTD852IWKP/HLIJL8JF8JF172E2JA0K*WDQMPB8T3%KLUSR43M.F\$QBQDR\$VT7V01Y7J0BOZLH+D-QF6MO\$R3%XB+.4QI596GY\$SITJP5BS0DFROC.7B.2RTB*UNYSM$*00HIL+H" val personAVac2Certificate = VaccinationDGCV1( @@ -76,14 +95,93 @@ class VaccinationTestData @Inject constructor( ) ) + val personAVac2CertificateHeader = HealthCertificateHeader( + issuer = "DE", + issuedAt = Instant.parse("2021-05-11T09:26:08.000Z"), + expiresAt = Instant.parse("2022-05-11T09:26:08.000Z"), + ) + + val personAVac2CertificateData = VaccinationCertificateData( + certificate = personAVac2Certificate, + header = personAVac2CertificateHeader + ) + + val personAVac2QRCode = VaccinationCertificateQRCode( + qrCodeString = personAVac2QRCodeString, + parsedData = personAVac2CertificateData, + ) + val personAVac2Container = VaccinationContainer( scannedAt = Instant.ofEpochMilli(1620069934471), - vaccinationQrCode = personAVac2QR, + vaccinationQrCode = personAVac2QRCodeString, ).apply { qrCodeExtractor = this@VaccinationTestData.qrCodeExtractor } - val personAData2Vac1Proof = VaccinatedPersonData( + val personAData2Vac = VaccinatedPersonData( vaccinations = setOf(personAVac1Container, personAVac2Container) ) + + // BorisJohnson1.pdf + val personBVac1QRCodeString = + "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3QVH9M9ESIGUBA KWML:SPHXK 0DMYF5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3ND3DAJ-43 QTCPFFIJRF3O8H43HX37DUF GFE VMJJYC3SM74E5V.499TXY9KK9+OC+G9QJPNF67J6QW67KQ2G66PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIPUBN9CIZI.EJJ14B2MP41AZRSEQEC5L64HX6IAS3DS2980IQ.DPUHLW\$GAHLW 70SO:GOLIROGO3T59YLQM14+OP\$I/XK\$M8CL6PZB*L8PK99Q9E\$BDZIF9J8-I\$GI0 J1ALL:F71APC9*KF6LF/NLR/FZ.COKEH-BB4OQ9OG4C5AO**HOELK2AZ7LBLEH-BHPLV5GK3DNKE\$JDVPLW1KD0KCZG.M1LUSB5BCQRJ\$DB5N9%V/GO4IHIBBJ-BI%NWRS%LR%\$KR46325NABFDDAFHD9PZP11COD5U*2KQXCA5W8HH/K51DQO8O0-SOSENFH9101U8$3" + + val personBVac1Certificate = VaccinationDGCV1( + version = "1.0.0", + nameData = VaccinationDGCV1.NameData( + givenName = "Boris", + givenNameStandardized = "BORIS", + familyName = "Johnson Gültig", + familyNameStandardized = "JOHNSON<GUELTIG", + ), + dob = "1966-11-11", + vaccinationDatas = listOf( + VaccinationDGCV1.VaccinationData( + targetId = "840539006", + vaccineId = "1119305005", + medicalProductId = "EU/1/20/1525", + marketAuthorizationHolderId = "ORG-100001417", + doseNumber = 1, + totalSeriesOfDoses = 1, + dt = "2021-04-20", + countryOfVaccination = "DE", + certificateIssuer = "Bundesministerium für Gesundheit - Test01", + uniqueCertificateIdentifier = "01DE/00001/1119305005/3H24U2KVOTPCSINK7N64F2OB9#S", + ) + ) + ) + + val personBVac1CertificateHeader = HealthCertificateHeader( + issuer = "DE", + issuedAt = Instant.parse("2021-05-11T09:23:03.000Z"), + expiresAt = Instant.parse("2022-05-11T09:23:03.000Z"), + ) + + val personBVac1CertificateData = VaccinationCertificateData( + certificate = personBVac1Certificate, + header = personBVac1CertificateHeader + ) + + val personBVac1QRCode = VaccinationCertificateQRCode( + qrCodeString = personBVac1QRCodeString, + parsedData = personBVac1CertificateData, + ) + + val personBVac1Container = VaccinationContainer( + scannedAt = Instant.ofEpochMilli(1620069934471), + vaccinationQrCode = personBVac1QRCodeString, + ).apply { + qrCodeExtractor = this@VaccinationTestData.qrCodeExtractor + } + + val personBData1Vac = VaccinatedPersonData( + vaccinations = setOf(personBVac1Container) + ) + + val personXVac1ContainerBadCountryData = VaccinationContainer( + scannedAt = Instant.ofEpochMilli(1620062834471), + vaccinationQrCode = VaccinationQrCodeTestData.qrCodeWithNonsenseCountry, + ).apply { + qrCodeExtractor = this@VaccinationTestData.qrCodeExtractor + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt index 8ac7c076ca5e02c5ac0b93215cb4af2f363a227b..ef2d3bd05a7f431767e5bf92ce403b1a1f3b1100 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt @@ -1,6 +1,8 @@ package de.rki.coronawarnapp.vaccination.core.qrcode import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent +import de.rki.coronawarnapp.vaccination.core.VaccinationQrCodeTestData +import de.rki.coronawarnapp.vaccination.core.VaccinationTestData import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED @@ -18,6 +20,7 @@ import javax.inject.Inject class VaccinationQRCodeExtractorTest : BaseTest() { @Inject lateinit var extractor: VaccinationQRCodeExtractor + @Inject lateinit var vaccinationTestData: VaccinationTestData @BeforeEach fun setup() { @@ -103,4 +106,16 @@ class VaccinationQRCodeExtractorTest : BaseTest() { extractor.extract(VaccinationQrCodeTestData.certificateMissing) }.errorCode shouldBe VC_NO_VACCINATION_ENTRY } + + @Test + fun `test data person A check`() { + val extracted = extractor.extract(vaccinationTestData.personAVac1QRCodeString) + extracted shouldBe vaccinationTestData.personAVac1QRCode + } + + @Test + fun `test data person B check`() { + val extracted = extractor.extract(vaccinationTestData.personBVac1QRCodeString) + extracted shouldBe vaccinationTestData.personBVac1QRCode + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt index bcefa337179dab6e378ec59efcac4de629151b8c..f0703302cb0f92b034fdb75003771bfd254ef56e 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/VaccinationRepositoryTest.kt @@ -1,14 +1,30 @@ package de.rki.coronawarnapp.vaccination.core.repository import de.rki.coronawarnapp.util.TimeStamper +import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent +import de.rki.coronawarnapp.vaccination.core.VaccinationTestData +import de.rki.coronawarnapp.vaccination.core.certificate.InvalidHealthCertificateException +import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationQRCodeExtractor +import de.rki.coronawarnapp.vaccination.core.repository.errors.VaccinationCertificateNotFoundException import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinatedPersonData import de.rki.coronawarnapp.vaccination.core.repository.storage.VaccinationStorage import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf import org.joda.time.Instant +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest +import testhelpers.TestDispatcherProvider import testhelpers.coroutines.runBlockingTest2 +import timber.log.Timber +import javax.inject.Inject class VaccinationRepositoryTest : BaseTest() { @@ -17,107 +33,171 @@ class VaccinationRepositoryTest : BaseTest() { @MockK lateinit var storage: VaccinationStorage @MockK lateinit var valueSetsRepository: ValueSetsRepository @MockK lateinit var vaccinationValueSet: VaccinationValueSet + @MockK lateinit var qrCodeExtractor: VaccinationQRCodeExtractor private var testStorage: Set<VaccinatedPersonData> = emptySet() - private var nowUTC = Instant.ofEpochMilli(1234567890) - -// @BeforeEach -// fun setup() { -// MockKAnnotations.init(this) -// -// every { timeStamper.nowUTC } returns nowUTC -// -// every { valueSetsRepository.latestValueSet } returns flowOf(vaccinationValueSet) -// -// coEvery { vaccinationProofServer.getProofCertificate(any()) } returns VaccinationTestData.PERSON_A_PROOF_1_RESPONSE -// -// storage.apply { -// every { personContainers } answers { testStorage } -// every { personContainers = any() } answers { testStorage = arg(0) } -// } -// } -// -// private fun createInstance(scope: CoroutineScope) = VaccinationRepository( -// appScope = scope, -// dispatcherProvider = TestDispatcherProvider(), -// timeStamper = timeStamper, -// storage = storage, -// valueSetsRepository = valueSetsRepository, -// vaccinationProofServer = vaccinationProofServer, -// ) -// -// @Test -// fun `add new certificate - no prior data`() = runBlockingTest2(ignoreActive = true) { -// val instance = createInstance(this) -// -// advanceUntilIdle() -// -// instance.registerVaccination(VaccinationTestData.PERSON_A_VAC_1_QRCODE).apply { -// Timber.i("Returned cert is %s", this) -// this.personIdentifier shouldBe VaccinationTestData.PERSON_A_VAC_1_CONTAINER.personIdentifier -// } -// } + @Inject lateinit var vaccinationTestData: VaccinationTestData + + // Few days after issued dates of person A in test data. + private var nowUTC = Instant.parse("2021-05-13T09:25:00.000Z") + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + + DaggerVaccinationTestComponent.factory().create().inject(this) + + every { timeStamper.nowUTC } returns nowUTC + + every { valueSetsRepository.latestValueSet } returns flowOf(vaccinationValueSet) + + storage.apply { + every { personContainers } answers { testStorage } + every { personContainers = any() } answers { testStorage = arg(0) } + } + } + + private fun createInstance(scope: CoroutineScope) = VaccinationRepository( + appScope = scope, + dispatcherProvider = TestDispatcherProvider(), + timeStamper = timeStamper, + storage = storage, + valueSetsRepository = valueSetsRepository, + vaccinationQRCodeExtractor = qrCodeExtractor, + ) @Test - fun `add new certificate - existing data`() = runBlockingTest2(ignoreActive = true) { -// val dataBefore = VaccinationTestData.PERSON_A_DATA_2VAC_PROOF.copy( -// vaccinations = setOf(VaccinationTestData.PERSON_A_VAC_1_CONTAINER), -// proofs = emptySet() -// ) -// val dataAfter = VaccinationTestData.PERSON_A_DATA_2VAC_PROOF.copy( -// vaccinations = setOf( -// VaccinationTestData.PERSON_A_VAC_1_CONTAINER, -// VaccinationTestData.PERSON_A_VAC_2_CONTAINER.copy(scannedAt = nowUTC) -// ), -// proofs = emptySet() -// ) -// testStorage = setOf(dataBefore) -// -// val instance = createInstance(this) -// -// advanceUntilIdle() -// -// instance.registerVaccination(VaccinationTestData.PERSON_A_VAC_2_QRCODE).apply { -// Timber.i("Returned cert is %s", this) -// this.personIdentifier shouldBe VaccinationTestData.PERSON_A_VAC_2_CONTAINER.personIdentifier -// } -// -// testStorage.first() shouldBe dataAfter + fun `add new certificate - no prior data`() = runBlockingTest2(ignoreActive = true) { + val instance = createInstance(this) + advanceUntilIdle() + + instance.registerVaccination(vaccinationTestData.personAVac1QRCode).apply { + Timber.i("Returned cert is %s", this) + this.personIdentifier shouldBe vaccinationTestData.personAVac1Container.personIdentifier + } } @Test - fun `add new certificate - if eligble for proof, start request`() = runBlockingTest2(ignoreActive = true) { -// TODO() + fun `add new certificate - existing data`() = runBlockingTest2(ignoreActive = true) { + val dataBefore = vaccinationTestData.personAData2Vac.copy( + vaccinations = setOf(vaccinationTestData.personAVac1Container), + ) + val dataAfter = vaccinationTestData.personAData2Vac.copy( + vaccinations = setOf( + vaccinationTestData.personAVac1Container, + vaccinationTestData.personAVac2Container.copy(scannedAt = nowUTC) + ), + ) + testStorage = setOf(dataBefore) + + val instance = createInstance(this) + advanceUntilIdle() + + instance.registerVaccination(vaccinationTestData.personAVac2QRCode).apply { + Timber.i("Returned cert is %s", this) + this.personIdentifier shouldBe vaccinationTestData.personAVac2Container.personIdentifier + } + + testStorage.first() shouldBe dataAfter } @Test - fun `add new certificate - does not match existing person`() { -// TODO() + fun `add new certificate - does not match existing person`() = runBlockingTest2(ignoreActive = true) { + testStorage = setOf(vaccinationTestData.personAData2Vac) + + val instance = createInstance(this) + advanceUntilIdle() + + shouldThrow<InvalidHealthCertificateException> { + instance.registerVaccination(vaccinationTestData.personBVac1QRCode) + }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH + + testStorage shouldBe setOf(vaccinationTestData.personAData2Vac) } @Test - fun `add new certificate - duplicate certificate`() { -// TODO() + fun `add new certificate - duplicate certificate`() = runBlockingTest2(ignoreActive = true) { + val dataBefore = vaccinationTestData.personAData2Vac.copy( + vaccinations = setOf(vaccinationTestData.personAVac1Container), + ) + + testStorage = setOf(dataBefore) + + val instance = createInstance(this) + advanceUntilIdle() + + shouldThrow<InvalidHealthCertificateException> { + instance.registerVaccination(vaccinationTestData.personAVac1QRCode) + }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.VC_ALREADY_REGISTERED + + testStorage.first() shouldBe dataBefore } @Test - fun `clear data`() { -// TODO() + fun `clear data`() = runBlockingTest2(ignoreActive = true) { + testStorage = setOf(vaccinationTestData.personAData2Vac) + + val instance = createInstance(this) + advanceUntilIdle() + + instance.vaccinationInfos.first().single().data shouldBe vaccinationTestData.personAData2Vac + + instance.clear() + + testStorage shouldBe emptySet() + instance.vaccinationInfos.first() shouldBe emptySet() } @Test - fun `remove certificate`() { -// TODO() + fun `remove certificate`() = runBlockingTest2(ignoreActive = true) { + val before = vaccinationTestData.personAData2Vac + val after = vaccinationTestData.personAData2Vac.copy( + vaccinations = setOf(vaccinationTestData.personAVac1Container) + ) + val toRemove = vaccinationTestData.personAVac2Container + + testStorage = setOf(before) + + val instance = createInstance(this) + advanceUntilIdle() + + instance.vaccinationInfos.first().single().data shouldBe vaccinationTestData.personAData2Vac + + instance.deleteVaccinationCertificate(toRemove.certificateId) + advanceUntilIdle() + + testStorage shouldBe setOf(after) + instance.vaccinationInfos.first().single().data shouldBe after } @Test - fun `remove certificate - starts proof check if we deleted a vaccination that was eligble for proof`() { -// TODO() + fun `remove certificate - unknown certificate`() = runBlockingTest2(ignoreActive = true) { + testStorage = setOf(vaccinationTestData.personAData2Vac) + + val instance = createInstance(this) + advanceUntilIdle() + + instance.vaccinationInfos.first().single().data shouldBe vaccinationTestData.personAData2Vac + + shouldThrow<VaccinationCertificateNotFoundException> { + instance.deleteVaccinationCertificate(vaccinationTestData.personBVac1Container.certificateId) + } } @Test - fun `check for new proof certificate`() { -// TODO() + fun `remove certificate - last certificate for person`() = runBlockingTest2(ignoreActive = true) { + testStorage = setOf(vaccinationTestData.personBData1Vac) + + val instance = createInstance(this) + advanceUntilIdle() + + instance.vaccinationInfos.first().single().data shouldBe vaccinationTestData.personBData1Vac + + instance.deleteVaccinationCertificate(vaccinationTestData.personBVac1Container.certificateId) + advanceUntilIdle() + + instance.vaccinationInfos.first() shouldBe emptySet() + testStorage shouldBe emptySet() } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..374831b938ca7e4384a0ad152b7c144bdf7b1766 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/ValueSetsRepositoryTest.kt @@ -0,0 +1,190 @@ +package de.rki.coronawarnapp.vaccination.core.repository + +import de.rki.coronawarnapp.util.preferences.FlowPreference +import de.rki.coronawarnapp.vaccination.core.repository.storage.ValueSetsStorage +import de.rki.coronawarnapp.vaccination.core.server.valueset.DefaultVaccinationValueSet +import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationServer +import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.Ordering +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.runs +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.preferences.mockFlowPreference +import java.util.Locale + +class ValueSetsRepositoryTest : BaseTest() { + + @MockK lateinit var vaccinationServer: VaccinationServer + @MockK lateinit var valueSetsStorage: ValueSetsStorage + + private val testScope = TestCoroutineScope() + + private val emptyValueSetEN = createValueSet(languageCode = Locale.ENGLISH) + private val valueSetPref: FlowPreference<ValueSetsStorage.StoredVaccinationValueSet> = + mockFlowPreference(emptyValueSetEN.toStoredVaccinationValueSet()) + + private val valueSetEN = createValueSet( + languageCode = Locale.ENGLISH, + vpItems = listOf( + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = "1119305005", + displayText = "Vaccine-Name" + ) + ), + mpItems = listOf( + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = "EU/1/21/1529", + displayText = "MedicalProduct-Name" + ) + ), + maItems = listOf( + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = "ORG-100001699", + displayText = "Manufactorer-Name" + ) + ) + ) + + private val valueSetDE = createValueSet( + languageCode = Locale.GERMAN, + vpItems = listOf( + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = "1119305005", + displayText = "Impfstoff-Name" + ) + ), + mpItems = listOf( + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = "EU/1/21/1529", + displayText = "Arzneimittel-Name" + ) + ), + maItems = listOf( + DefaultVaccinationValueSet.DefaultValueSet.DefaultItem( + key = "ORG-100001699", + displayText = "Hersteller-Name" + ) + ) + ) + + private fun createValueSet( + languageCode: Locale, + vpItems: List<DefaultVaccinationValueSet.DefaultValueSet.DefaultItem> = emptyList(), + mpItems: List<DefaultVaccinationValueSet.DefaultValueSet.DefaultItem> = emptyList(), + maItems: List<DefaultVaccinationValueSet.DefaultValueSet.DefaultItem> = emptyList() + ) = DefaultVaccinationValueSet( + languageCode = languageCode, + vp = DefaultVaccinationValueSet.DefaultValueSet(items = vpItems), + mp = DefaultVaccinationValueSet.DefaultValueSet(items = mpItems), + ma = DefaultVaccinationValueSet.DefaultValueSet(items = maItems) + ) + + private fun createInstance() = ValueSetsRepository( + vaccinationServer = vaccinationServer, + valueSetsStorage = valueSetsStorage, + scope = testScope + ) + + @BeforeEach + fun setUp() { + MockKAnnotations.init(this) + coEvery { vaccinationServer.getVaccinationValueSets(any()) } returns null + coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns valueSetEN + coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns valueSetDE + every { vaccinationServer.clear() } just runs + + every { valueSetsStorage.valueSet } returns valueSetPref + every { valueSetsStorage.clear() } just runs + } + + @Test + fun `successful update for de`() = runBlockingTest { + createInstance().run { + triggerUpdateValueSet(languageCode = Locale.GERMAN) + latestValueSet.first() + }.also { it.validateValues(valueSetDE) } + + coVerify(exactly = 1) { + vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) + } + + coVerify(exactly = 0) { + vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) + } + } + + @Test + fun `fallback to en`() = runBlockingTest { + createInstance().run { + triggerUpdateValueSet(languageCode = Locale.FRENCH) + latestValueSet.first() + }.also { it.validateValues(valueSetEN) } + + coVerify(ordering = Ordering.ORDERED) { + vaccinationServer.getVaccinationValueSets(languageCode = Locale.FRENCH) + vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) + } + } + + @Test + fun `server returns nothing`() = runBlockingTest { + coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) } returns null + coEvery { vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) } returns null + + createInstance().run { + triggerUpdateValueSet(languageCode = Locale.GERMAN) + latestValueSet.first() + }.also { it.validateValues(emptyValueSetEN) } + + coVerify(ordering = Ordering.ORDERED) { + vaccinationServer.getVaccinationValueSets(languageCode = Locale.GERMAN) + vaccinationServer.getVaccinationValueSets(languageCode = Locale.ENGLISH) + } + } + + @Test + fun `mapping is to stored version is correct`() { + valueSetDE.also { it.toStoredVaccinationValueSet().validateValues(it) } + valueSetEN.also { it.toStoredVaccinationValueSet().validateValues(it) } + emptyValueSetEN.also { it.toStoredVaccinationValueSet().validateValues(it) } + } + + @Test + fun `clear data of server and local storage`() { + createInstance().run { + clear() + + coVerify(exactly = 1) { + vaccinationServer.clear() + valueSetsStorage.clear() + } + } + } + + private fun VaccinationValueSet.validateValues(v2: VaccinationValueSet) { + languageCode shouldBe v2.languageCode + vp.validateValues(v2.vp) + mp.validateValues(v2.mp) + ma.validateValues(v2.ma) + } + + private fun VaccinationValueSet.ValueSet.validateValues(v2: VaccinationValueSet.ValueSet) { + items.forEachIndexed { index, item1 -> + val item2 = v2.items[index] + + item1.key shouldBe item2.key + item1.displayText shouldBe item2.displayText + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt index ec211990b19279cdc68d54302cbcbab0f21d022b..c362bebab70f4e7cfdccaa0e760174263e15374e 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationContainerTest.kt @@ -1,6 +1,5 @@ package de.rki.coronawarnapp.vaccination.core.repository.storage -import de.rki.coronawarnapp.ui.Country import de.rki.coronawarnapp.vaccination.core.DaggerVaccinationTestComponent import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier import de.rki.coronawarnapp.vaccination.core.VaccinationTestData @@ -8,11 +7,13 @@ import de.rki.coronawarnapp.vaccination.core.server.valueset.VaccinationValueSet import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk +import io.mockk.mockkObject import org.joda.time.Instant import org.joda.time.LocalDate import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest +import java.util.Locale import javax.inject.Inject class VaccinationContainerTest : BaseTest() { @@ -22,6 +23,7 @@ class VaccinationContainerTest : BaseTest() { @BeforeEach fun setup() { DaggerVaccinationTestComponent.factory().create().inject(this) + mockkObject(Locale.getDefault()) } @Test @@ -60,6 +62,7 @@ class VaccinationContainerTest : BaseTest() { @Test fun `mapping to user facing data - valueset is null`() { + every { Locale.getDefault().language } returns "de" testData.personAVac1Container.toVaccinationCertificate(null).apply { firstName shouldBe "Andreas" lastName shouldBe "Astrá Eins" @@ -71,7 +74,7 @@ class VaccinationContainerTest : BaseTest() { doseNumber shouldBe 1 totalSeriesOfDoses shouldBe 2 certificateIssuer shouldBe "Bundesministerium für Gesundheit - Test01" - certificateCountry shouldBe Country.DE + certificateCountry shouldBe "Deutschland" certificateId shouldBe "01DE/00001/1119305005/7T1UG87G61Y7NRXIBQJDTYQ9#S" personIdentifier shouldBe VaccinatedPersonIdentifier( dateOfBirth = LocalDate.parse("1966-11-11"), @@ -83,11 +86,32 @@ class VaccinationContainerTest : BaseTest() { @Test fun `mapping to user facing data - with valueset`() { + val vpItem = mockk<VaccinationValueSet.ValueSet.Item> { + every { key } returns "1119305005" + every { displayText } returns "Vaccine-Name" + } + + val mpItem = mockk<VaccinationValueSet.ValueSet.Item> { + every { key } returns "EU/1/21/1529" + every { displayText } returns "MedicalProduct-Name" + } + + val maItem = mockk<VaccinationValueSet.ValueSet.Item> { + every { key } returns "ORG-100001699" + every { displayText } returns "Manufactorer-Name" + } + + val vpMockk = mockk<VaccinationValueSet.ValueSet> { + every { items } returns listOf(vpItem, mpItem, maItem) + } + val valueSet = mockk<VaccinationValueSet> { - every { getDisplayText("ORG-100001699") } returns "Manufactorer-Name" - every { getDisplayText("EU/1/21/1529") } returns "MedicalProduct-Name" - every { getDisplayText("1119305005") } returns "Vaccine-Name" + every { vp } returns vpMockk + every { mp } returns vpMockk + every { ma } returns vpMockk } + every { Locale.getDefault().language } returns "de" + testData.personAVac1Container.toVaccinationCertificate(valueSet).apply { firstName shouldBe "Andreas" lastName shouldBe "Astrá Eins" @@ -99,7 +123,7 @@ class VaccinationContainerTest : BaseTest() { doseNumber shouldBe 1 totalSeriesOfDoses shouldBe 2 certificateIssuer shouldBe "Bundesministerium für Gesundheit - Test01" - certificateCountry shouldBe Country.DE + certificateCountry shouldBe "Deutschland" certificateId shouldBe "01DE/00001/1119305005/7T1UG87G61Y7NRXIBQJDTYQ9#S" personIdentifier shouldBe VaccinatedPersonIdentifier( dateOfBirth = LocalDate.parse("1966-11-11"), @@ -111,4 +135,11 @@ class VaccinationContainerTest : BaseTest() { expiresAt shouldBe Instant.parse("2022-05-11T09:25:00.000Z") } } + + @Test + fun `nonsense country code appears unchanged`() { + testData.personXVac1ContainerBadCountryData.toVaccinationCertificate(null).apply { + certificateCountry shouldBe "YY" + } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt index a888628a60455a202632c24e041d74366ce81758..9af9da65bd8172c743c89b1078d28416502a678b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/VaccinationStorageTest.kt @@ -61,7 +61,7 @@ class VaccinationStorageTest : BaseTest() { @Test fun `store one person`() { val instance = createInstance() - instance.personContainers = setOf(testData.personAData2Vac1Proof) + instance.personContainers = setOf(testData.personAData2Vac) val json = (mockPreferences.dataMapPeek["vaccination.person.1966-11-11#ASTRA<EINS#ANDREAS"] as String) @@ -70,10 +70,10 @@ class VaccinationStorageTest : BaseTest() { { "vaccinationData": [ { - "vaccinationQrCode": "${testData.personAVac1QR}", + "vaccinationQrCode": "${testData.personAVac1QRCodeString}", "scannedAt": 1620062834471 }, { - "vaccinationQrCode": "${testData.personAVac2QR}", + "vaccinationQrCode": "${testData.personAVac2QRCodeString}", "scannedAt": 1620069934471 } ] @@ -81,7 +81,7 @@ class VaccinationStorageTest : BaseTest() { """.toComparableJsonPretty() instance.personContainers.single().apply { - this shouldBe testData.personAData2Vac1Proof + this shouldBe testData.personAData2Vac this.vaccinations shouldBe setOf( testData.personAVac1Container, testData.personAVac2Container, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..e333cef8a7f2eb2ba48fd036fb38a1840c1c1f58 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/repository/storage/ValueSetsStorageTest.kt @@ -0,0 +1,95 @@ +package de.rki.coronawarnapp.vaccination.core.repository.storage + +import android.content.Context +import de.rki.coronawarnapp.util.serialization.SerializationModule +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runBlockingTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.preferences.MockSharedPreferences +import java.util.Locale + +class ValueSetsStorageTest : BaseTest() { + + @MockK lateinit var context: Context + lateinit var prefs: MockSharedPreferences + + private val gson = SerializationModule().baseGson() + + private val storedValueSetDE = ValueSetsStorage.StoredVaccinationValueSet( + languageCode = Locale.GERMAN, + vp = createValueSet(key = "1119305005", displayText = "Impfstoff-Name"), + mp = createValueSet(key = "EU/1/21/1529", displayText = "Arzneimittel-Name"), + ma = createValueSet(key = "ORG-100001699", displayText = "Hersteller-Name") + ) + + private val storedValueSetEN = ValueSetsStorage.StoredVaccinationValueSet( + languageCode = Locale.ENGLISH, + vp = createValueSet(key = "1119305005", displayText = "Vaccine-Name"), + mp = createValueSet(key = "EU/1/21/1529", displayText = "MedicalProduct-Name"), + ma = createValueSet(key = "ORG-100001699", displayText = "Manufactorer-Name") + ) + + private fun createValueSet(key: String, displayText: String): ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet { + val item = ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet.StoredItem( + key = key, + displayText = displayText + ) + return ValueSetsStorage.StoredVaccinationValueSet.StoredValueSet(items = listOf(item)) + } + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + prefs = MockSharedPreferences() + every { context.getSharedPreferences("valuesets_localdata", Context.MODE_PRIVATE) } returns prefs + } + + private fun createInstance() = ValueSetsStorage( + context = context, + gson = gson + ) + + @Test + fun `Default value is empty value set`() { + createInstance().valueSet.value.run { + languageCode shouldBe Locale.ENGLISH + vp.items shouldBe emptyList() + mp.items shouldBe emptyList() + ma.items shouldBe emptyList() + } + } + + @Test + fun `Clear resets value set`() { + createInstance().run { + valueSet.update { storedValueSetDE } + clear() + + valueSet.value.also { + it.languageCode shouldBe Locale.ENGLISH + it.vp.items shouldBe emptyList() + it.mp.items shouldBe emptyList() + it.ma.items shouldBe emptyList() + } + } + } + + @Test + fun `Updates values`() = runBlockingTest { + createInstance().valueSet.run { + update { storedValueSetDE } + value shouldBe storedValueSetDE + flow.first() shouldBe storedValueSetDE + + update { storedValueSetEN } + value shouldBe storedValueSetEN + flow.first() shouldBe storedValueSetEN + } + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..0c27822e117164f0baa327bb8b978c7e72b688b4 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/vaccination/core/server/valueset/VaccinationServerTest.kt @@ -0,0 +1,109 @@ +package de.rki.coronawarnapp.vaccination.core.server.valueset + +import dagger.Lazy +import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.security.SignatureValidation +import de.rki.coronawarnapp.vaccination.core.server.valueset.internal.ValueSetInvalidSignatureException +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.runs +import io.mockk.verify +import okhttp3.Cache +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import java.io.File + +class VaccinationServerTest : BaseTest() { + + /** + * contains both binary and signature + */ + private val exportZip = File("src/test/resources/vaccination/valueset_default.zip") + + /** + * binary is missing + */ + private val invalidExportZip = File("src/test/resources/vaccination/valueset_invalid.zip") + + @MockK lateinit var cache: Cache + @MockK lateinit var apiV1: Lazy<VaccinationValueSetApiV1> + @MockK lateinit var dispatcherProvider: DispatcherProvider + @MockK lateinit var signatureValidation: SignatureValidation + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + exportZip.exists() shouldBe true + invalidExportZip.exists() shouldBe true + } + + private fun createInstance() = VaccinationServer( + cache, + apiV1, + dispatcherProvider, + signatureValidation + ) + + @Test + fun `valid export data`() { + every { signatureValidation.hasValidSignature(any(), any()) } returns true + exportZip.inputStream().use { + createInstance().parseBody(it).apply { + this shouldNotBe null + ma.apply { + itemsCount shouldBe 1 + getItems(0).apply { + key shouldBe "maKey" + displayText shouldBe "maDisplayText" + } + } + mp.apply { + itemsCount shouldBe 1 + getItems(0).apply { + key shouldBe "mpKey" + displayText shouldBe "mpDisplayText" + } + } + vp.apply { + itemsCount shouldBe 1 + getItems(0).apply { + key shouldBe "vpKey" + displayText shouldBe "vpDisplayText" + } + } + } + } + } + + @Test + fun `invalid signature`() { + every { signatureValidation.hasValidSignature(any(), any()) } returns false + exportZip.inputStream().use { + shouldThrow<ValueSetInvalidSignatureException> { + createInstance().parseBody(it) + } + } + } + + @Test + fun `a file is missing`() { + invalidExportZip.inputStream().use { + shouldThrow<ValueSetInvalidSignatureException> { + createInstance().parseBody(it) + } + } + } + + @Test + fun `call to clear invalidates cache`() { + every { cache.evictAll() } just runs + createInstance().clear() + verify { cache.evictAll() } + } +} diff --git a/Corona-Warn-App/src/test/resources/vaccination/valueset_default.zip b/Corona-Warn-App/src/test/resources/vaccination/valueset_default.zip new file mode 100755 index 0000000000000000000000000000000000000000..07bab18cc3ed089272171b18702eda8d62cab2d9 Binary files /dev/null and b/Corona-Warn-App/src/test/resources/vaccination/valueset_default.zip differ diff --git a/Corona-Warn-App/src/test/resources/vaccination/valueset_invalid.zip b/Corona-Warn-App/src/test/resources/vaccination/valueset_invalid.zip new file mode 100755 index 0000000000000000000000000000000000000000..7a574548e639ff20f9d465304ff3c03c3ed8437d Binary files /dev/null and b/Corona-Warn-App/src/test/resources/vaccination/valueset_invalid.zip differ diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt index 27b4fe9757b14077fea0e63b813f732064aeab88..c1b802516a2f5aa590dd3cf5ba6fcbd6d23e5906 100644 --- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt +++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/debugoptions/ui/DebugOptionsFragmentViewModelTest.kt @@ -31,7 +31,6 @@ class DebugOptionsFragmentViewModelTest : BaseTestInstrumentation() { every { environmentSetup.verificationCdnUrl } returns "verificationUrl" every { environmentSetup.dataDonationCdnUrl } returns "dataDonationUrl" every { environmentSetup.logUploadServerUrl } returns "logUploadServerUrl" - every { environmentSetup.vaccinationCdnUrl } returns "vaccinationCdnUrl" every { environmentSetup.crowdNotifierPublicKey } returns "crowdNotifierPublicKey" every { environmentSetup.appConfigPublicKey } returns "appConfigPublicKey" diff --git a/gradle.properties b/gradle.properties index 84cdb96a7ae0ac734688bd25cbeb83f33b691584..fa1b8e30ecbbea40dffe8fed20d0872c10341e01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,4 +20,4 @@ org.gradle.dependency.verification.console=verbose VERSION_MAJOR=2 VERSION_MINOR=4 VERSION_PATCH=0 -VERSION_BUILD=0 +VERSION_BUILD=2 diff --git a/prod_environments.json b/prod_environments.json index 8c50a11f3fd336642c98f2cdbc19deb6c17aac4c..09d9015c150489eb2dac757a9dfbe5d25f476926 100644 --- a/prod_environments.json +++ b/prod_environments.json @@ -6,8 +6,6 @@ "VERIFICATION_CDN_URL": "https://verification.coronawarn.app", "DATA_DONATION_CDN_URL": "https://data.coronawarn.app", "LOG_UPLOAD_SERVER_URL": "https://logupload.coronawarn.app", - "VACCINATION_PROOF_SERVER_URL": "https://api.recertify.ubirch.com", - "VACCINATION_CDN_URL": "https://placeholder", "SAFETYNET_API_KEY": "placeholder", "PUB_KEYS_SIGNATURE_VERIFICATION": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc7DEstcUIRcyk35OYDJ95/hTg3UVhsaDXKT0zK7NhHPXoyzipEnOp3GyNXDVpaPi3cAfQmxeuFMZAIX2+6A5Xg==", "CROWD_NOTIFIER_PUBLIC_KEY": "gwLMzE153tQwAOf2MZoUXXfzWTdlSpfS99iZffmcmxOG9njSK4RTimFOFwDh6t0Tyw8XR01ugDYjtuKwjjuK49Oh83FWct6XpefPi9Skjxvvz53i9gaMmUEc96pbtoaA"