From 0ab337d2aa1171ec7b048001995bb9b4ceb4c71d Mon Sep 17 00:00:00 2001 From: Mohamed <mohamed.metwalli@sap.com> Date: Thu, 22 Apr 2021 16:50:49 +0200 Subject: [PATCH] Negative RAT timer (EXPOSUREAPP-6590) (#2902) * extra line * Fix constraint * Hide profile info * initial impl * lint * Handle deletion * Bind views * Tweaking * Lint * Clean up * Date format * Use one TextView * Refactoring * time since test conduction * fix null values * remove redeem state * adapt strings Co-authored-by: chilja <chiljamgossow@gmail.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> --- .../negative/RATResultNegativeFragment.kt | 61 ++++++++++++++- .../negative/RATResultNegativeNavigation.kt | 5 ++ .../negative/RATResultNegativeViewModel.kt | 78 ++++++++++++++++++- .../ic_test_result_delete_test.xml | 12 +++ .../drawable/ic_test_result_delete_test.xml | 12 +-- ...ubmission_antigen_test_result_negative.xml | 24 ++---- .../src/main/res/layout/time_counter.xml | 7 +- .../main/res/values-de/antigen_strings.xml | 6 +- .../src/main/res/values/antigen_strings.xml | 6 +- 9 files changed, 174 insertions(+), 37 deletions(-) create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeNavigation.kt create mode 100644 Corona-Warn-App/src/main/res/drawable-night/ic_test_result_delete_test.xml 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 082b63819..bb7df906e 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 @@ -2,13 +2,18 @@ package de.rki.coronawarnapp.submission.ui.testresults.negative import android.os.Bundle import android.view.View +import androidx.core.text.bold +import androidx.core.text.buildSpannedString import androidx.fragment.app.Fragment import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.FragmentSubmissionAntigenTestResultNegativeBinding +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.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.cwaViewModels +import org.joda.time.format.DateTimeFormat import javax.inject.Inject class RATResultNegativeFragment : Fragment(R.layout.fragment_submission_antigen_test_result_negative), AutoInject { @@ -17,8 +22,58 @@ class RATResultNegativeFragment : Fragment(R.layout.fragment_submission_antigen_ private val binding: FragmentSubmissionAntigenTestResultNegativeBinding by viewBindingLazy() - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - // TODO: Add fragment logic and databinding. + private val shortTime = DateTimeFormat.shortTime() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) = + with(binding) { + coronatestNegativeAntigenResultButton.setOnClickListener { viewModel.deleteTest() } + toolbar.setNavigationOnClickListener { viewModel.onClose() } + + viewModel.testAge.observe(viewLifecycleOwner) { + it?.let { bindView(it) } + } + + viewModel.events.observe(viewLifecycleOwner) { + when (it) { + RATResultNegativeNavigation.Back -> popBackStack() + } + } + } + + private fun FragmentSubmissionAntigenTestResultNegativeBinding.bindView( + testAge: RATResultNegativeViewModel.TestAge + ) { + resultReceivedCounter.chronometer.text = testAge.ageText + + val patientName = getString( + R.string.submission_test_result_antigen_patient_name_placeholder, + testAge.test.firstName ?: "", + testAge.test.lastName ?: "" + ) + + rapidTestCardPatientInfo.text = buildSpannedString { + bold { + if (patientName.isNotBlank()) append(patientName) + } + testAge.test.dateOfBirth?.let { + val birthDate = getString( + R.string.submission_test_result_antigen_patient_birth_date_placeholder, + it.toString(DATE_FORMAT) + ) + if (this.isNotBlank()) append(", ") + append(birthDate) + } + } + + val localTime = testAge.test.testedAt.toUserTimeZone() + resultReceivedTimeAndDate.text = getString( + R.string.coronatest_negative_antigen_result_time_date_placeholder, + localTime?.toString(DATE_FORMAT), + localTime?.toString(shortTime) + ) + } + + companion object { + private const val DATE_FORMAT = "dd.MM.yy" } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeNavigation.kt new file mode 100644 index 000000000..c5a874e10 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeNavigation.kt @@ -0,0 +1,5 @@ +package de.rki.coronawarnapp.submission.ui.testresults.negative + +sealed class RATResultNegativeNavigation { + object Back : RATResultNegativeNavigation() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt index ee69cae57..607dde740 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/ui/testresults/negative/RATResultNegativeViewModel.kt @@ -1,15 +1,91 @@ package de.rki.coronawarnapp.submission.ui.testresults.negative +import androidx.lifecycle.asLiveData import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.coronatest.CoronaTestRepository +import de.rki.coronawarnapp.coronatest.type.CoronaTest +import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest +import de.rki.coronawarnapp.exception.ExceptionCategory +import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.submission.SubmissionRepository +import de.rki.coronawarnapp.util.TimeStamper import de.rki.coronawarnapp.util.coroutine.DispatcherProvider +import de.rki.coronawarnapp.util.flow.combine +import de.rki.coronawarnapp.util.flow.intervalFlow +import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory +import org.joda.time.Duration +import org.joda.time.format.PeriodFormatter +import org.joda.time.format.PeriodFormatterBuilder +import timber.log.Timber class RATResultNegativeViewModel @AssistedInject constructor( - dispatcherProvider: DispatcherProvider + dispatcherProvider: DispatcherProvider, + private val timeStamper: TimeStamper, + private val submissionRepository: SubmissionRepository, + coronaTestRepository: CoronaTestRepository ) : CWAViewModel(dispatcherProvider) { + val events = SingleLiveEvent<RATResultNegativeNavigation>() + val testAge = combine( + intervalFlow(1), + coronaTestRepository.coronaTests + ) { _, tests -> + val rapidTest = tests.firstOrNull { + it.type == CoronaTest.Type.RAPID_ANTIGEN + } + + rapidTest?.testAge() + }.asLiveData(context = dispatcherProvider.Default) + + private fun CoronaTest.testAge(): TestAge? { + if (this !is RACoronaTest) { + Timber.d("Rapid test is missing") + return null + } + + val nowUTC = timeStamper.nowUTC + val age = nowUTC.millis - testedAt.millis + val ageText = formatter.print(Duration(age).toPeriod()) + + return TestAge(test = this, ageText) + } + + fun deleteTest() { + try { + Timber.d("deleteTest") + submissionRepository.removeTestFromDevice(CoronaTest.Type.RAPID_ANTIGEN) + events.postValue(RATResultNegativeNavigation.Back) + } catch (e: Exception) { + Timber.d(e, "Failed to delete rapid antigen test") + e.report(ExceptionCategory.INTERNAL) + } + } + + fun onClose() { + events.postValue(RATResultNegativeNavigation.Back) + } + @AssistedFactory interface Factory : SimpleCWAViewModelFactory<RATResultNegativeViewModel> + + data class TestAge( + val test: RACoronaTest, + val ageText: String, + ) + + companion object { + private val formatter: PeriodFormatter = + PeriodFormatterBuilder().apply { + printZeroAlways() + minimumPrintedDigits(2) + appendHours() + appendSuffix(":") + appendMinutes() + appendSuffix(":") + appendSeconds() + }.toFormatter() + } } diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_test_result_delete_test.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_test_result_delete_test.xml new file mode 100644 index 000000000..b72e2b6e2 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_test_result_delete_test.xml @@ -0,0 +1,12 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:fillColor="#434445" + android:pathData="M20,40C31.0457,40 40,31.0457 40,20C40,8.9543 31.0457,0 20,0C8.9543,0 0,8.9543 0,20C0,31.0457 8.9543,40 20,40Z" /> + <path + android:fillColor="#979797" + 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" /> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_test_result_delete_test.xml b/Corona-Warn-App/src/main/res/drawable/ic_test_result_delete_test.xml index 7d9791144..94ad81c22 100644 --- a/Corona-Warn-App/src/main/res/drawable/ic_test_result_delete_test.xml +++ b/Corona-Warn-App/src/main/res/drawable/ic_test_result_delete_test.xml @@ -3,10 +3,10 @@ android:height="40dp" android:viewportWidth="40" android:viewportHeight="40"> - <path - android:pathData="M20,40C31.0457,40 40,31.0457 40,20C40,8.9543 31.0457,0 20,0C8.9543,0 0,8.9543 0,20C0,31.0457 8.9543,40 20,40Z" - android:fillColor="#F5F5F5"/> - <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"/> + <path + android:fillColor="#F5F5F5" + android:pathData="M20,40C31.0457,40 40,31.0457 40,20C40,8.9543 31.0457,0 20,0C8.9543,0 0,8.9543 0,20C0,31.0457 8.9543,40 20,40Z" /> + <path + android:fillColor="#979797" + 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" /> </vector> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml b/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml index 196761444..bac63ca3f 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_submission_antigen_test_result_negative.xml @@ -81,26 +81,16 @@ tools:text="@string/submission_test_result_negative" /> <TextView - android:id="@+id/rapid_test_card_patient_name" + android:id="@+id/rapid_test_card_patient_info" style="@style/body2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_small" android:layout_marginEnd="@dimen/spacing_normal" - android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/rapid_test_card_diagnosis" app:layout_constraintTop_toBottomOf="@id/rapid_test_card_diagnosis" - tools:text="@string/submission_test_result_antigen_patient_name_placeholder" /> - - <TextView - android:id="@+id/rapid_test_card_patient_birthdate" - style="@style/body2" - android:layout_width="0dp" - android:layout_height="wrap_content" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@id/rapid_test_card_patient_name" - app:layout_constraintTop_toTopOf="@id/rapid_test_card_patient_name" - tools:text="@string/submission_test_result_antigen_patient_birth_date_placeholder" /> + tools:text="Max Mustermann, geboren 14.03.1987" /> <TextView android:id="@+id/rapid_test_card_negative_result_message" @@ -111,8 +101,8 @@ android:layout_marginEnd="@dimen/spacing_normal" android:text="@string/submission_test_result_negative_message" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="@id/rapid_test_card_patient_name" - app:layout_constraintTop_toBottomOf="@id/rapid_test_card_patient_birthdate" /> + app:layout_constraintStart_toStartOf="@id/rapid_test_card_patient_info" + app:layout_constraintTop_toBottomOf="@id/rapid_test_card_patient_info" /> <include android:id="@+id/result_received_counter" @@ -212,7 +202,7 @@ app:layout_constraintTop_toBottomOf="@+id/test_result_negative_steps_added" app:simple_step_entry_text="@string/coronatest_negative_antigen_result_second_info_body" app:simple_step_entry_title="@string/coronatest_negative_antigen_result_second_info_title" - app:step_entry_final="true" + app:step_entry_final="false" app:step_entry_icon="@drawable/ic_test_result_step_invalid" /> <de.rki.coronawarnapp.ui.view.SimpleStepEntry @@ -235,7 +225,7 @@ android:background="@color/colorSurface2" android:orientation="vertical" android:padding="@dimen/spacing_normal" - app:layout_constraintTop_toBottomOf="@id/test_result_negative_steps_negative_result"> + app:layout_constraintTop_toBottomOf="@id/coronatest_negative_antigen_result_third_info"> <TextView android:id="@+id/further_info_title" diff --git a/Corona-Warn-App/src/main/res/layout/time_counter.xml b/Corona-Warn-App/src/main/res/layout/time_counter.xml index 07a4f5274..879a5c5c4 100644 --- a/Corona-Warn-App/src/main/res/layout/time_counter.xml +++ b/Corona-Warn-App/src/main/res/layout/time_counter.xml @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> - <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" @@ -24,19 +23,19 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <Chronometer + <TextView android:id="@+id/chronometer" style="@style/headline4Bold" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_tiny" - android:format="00:00:00" android:gravity="center" + android:text="00:00:00" android:textColor="@color/colorTextPrimary1InvertedStable" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/result_timer" - tools:text="00:00:00" /> + tools:ignore="HardcodedText" /> <TextView android:id="@+id/chronometer_hours" 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 a1aa228c7..1b2b6aef0 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 @@ -111,11 +111,11 @@ <!-- XTXT: submission test result fragment positive diagnosis --> <string name="submission_test_result_positive">"Positiv"</string> <!-- XTXT: submission result antigen fragment card patient name placeholder --> - <string name="submission_test_result_antigen_patient_name_placeholder">"Max Mustermann,"</string> + <string name="submission_test_result_antigen_patient_name_placeholder">"%1$s %2$s"</string> <!-- XTXT: submission result antigen fragment card patient birth date placeholder --> - <string name="submission_test_result_antigen_patient_birth_date_placeholder">"geboren 14.03.1987"</string> + <string name="submission_test_result_antigen_patient_birth_date_placeholder">"geboren %1$s"</string> <!-- XTXT: coronatest negative antigen result time and date placeholder --> - <string name="coronatest_negative_antigen_result_time_date_placeholder">"Ausgestellt: 10.03.2021, 18:01 Uhr"</string> + <string name="coronatest_negative_antigen_result_time_date_placeholder">"Ausgestellt: %1$s, %2$s Uhr"</string> <!-- XTXT: submission result antigen fragment card negative result message --> <string name="submission_test_result_negative_message">"Das Virus SARS-CoV-2 wurde bei Ihnen nicht nachgewiesen."</string> <!-- XHED: submission result antigen fragment negative result proof title --> diff --git a/Corona-Warn-App/src/main/res/values/antigen_strings.xml b/Corona-Warn-App/src/main/res/values/antigen_strings.xml index 6edb51d3d..85dd938a6 100644 --- a/Corona-Warn-App/src/main/res/values/antigen_strings.xml +++ b/Corona-Warn-App/src/main/res/values/antigen_strings.xml @@ -111,11 +111,11 @@ <!-- XTXT: submission test result fragment positive diagnosis --> <string name="submission_test_result_positive">"Positiv"</string> <!-- XTXT: submission result antigen fragment card patient name placeholder --> - <string name="submission_test_result_antigen_patient_name_placeholder">"Max Mustermann,"</string> + <string name="submission_test_result_antigen_patient_name_placeholder">"%1$s %2$s"</string> <!-- XTXT: submission result antigen fragment card patient birth date placeholder --> - <string name="submission_test_result_antigen_patient_birth_date_placeholder">"geboren 14.03.1987"</string> + <string name="submission_test_result_antigen_patient_birth_date_placeholder">"geboren %1$s"</string> <!-- XTXT: coronatest negative antigen result time and date placeholder --> - <string name="coronatest_negative_antigen_result_time_date_placeholder">"Ausgestellt: 10.03.2021, 18:01 Uhr"</string> + <string name="coronatest_negative_antigen_result_time_date_placeholder">"Ausgestellt: %1$s, %2$s Uhr"</string> <!-- XTXT: submission result antigen fragment card negative result message --> <string name="submission_test_result_negative_message">"Das Virus SARS-CoV-2 wurde bei Ihnen nicht nachgewiesen."</string> <!-- XHED: submission result antigen fragment negative result proof title --> -- GitLab