Skip to content
Snippets Groups Projects
Unverified Commit f00bde0d authored by Oliver Zimmerman's avatar Oliver Zimmerman Committed by GitHub
Browse files

Merge pull request #1761 from corona-warn-app/feature/3744-test-result-screen

Submission Flow: Positive test result with given user consent (EXPOSUREAPP-3680)
parents a3dbae38 d9c60926
No related branches found
No related tags found
No related merge requests found
Showing
with 666 additions and 17 deletions
package de.rki.coronawarnapp.ui.submission
import androidx.fragment.app.testing.launchFragment
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.Module
import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenFragment
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenViewModel
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import testhelpers.BaseUITest
@RunWith(AndroidJUnit4::class)
class SubmissionTestResultConsentGivenFragmentTest : BaseUITest() {
@MockK lateinit var viewModel: SubmissionTestResultConsentGivenViewModel
@Before
fun setup() {
MockKAnnotations.init(this, relaxed = true)
setupMockViewModel(object : SubmissionTestResultConsentGivenViewModel.Factory {
override fun create(): SubmissionTestResultConsentGivenViewModel = viewModel
})
}
@After
fun teardown() {
clearAllViewModels()
}
@Test
fun launch_fragment() {
launchFragment<SubmissionTestResultConsentGivenFragment>()
}
@Test
fun testEventConsentGivenContinueWithSymptomsClicked() {
val mockNavController = mock(NavController::class.java)
val scenario = launchFragmentInContainer<SubmissionTestResultConsentGivenFragment>()
scenario.onFragment { fragment ->
Navigation.setViewNavController(fragment.requireView(), mockNavController)
}
// Verify that performing a click prompts the correct Navigation action
onView(ViewMatchers.withId(R.id.submission_test_result_button_consent_given_continue)).perform(ViewActions.click())
verify(mockNavController).navigate(R.id.action_submissionTestResultConsentGivenFragment_to_submissionSymptomIntroductionFragment)
}
}
@Module
abstract class SubmissionTestResultConsentGivenTestModule {
@ContributesAndroidInjector
abstract fun submissionTestResultScreen(): SubmissionTestResultConsentGivenViewModel
}
......@@ -13,12 +13,13 @@ import de.rki.coronawarnapp.ui.submission.SubmissionDispatcherTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionDoneTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionIntroTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionOtherWarningTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionQRInfoFragmentModule
import de.rki.coronawarnapp.ui.submission.SubmissionQRScanFragmentModule
import de.rki.coronawarnapp.ui.submission.SubmissionSymptomCalendarFragmentTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionSymptomIntroFragmentTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionTanTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionTestResultConsentGivenTestModule
import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestModule
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenModule
@Module(
includes = [
......@@ -35,13 +36,13 @@ import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestModule
SubmissionDispatcherTestModule::class,
SubmissionTanTestModule::class,
SubmissionTestResultTestModule::class,
SubmissionTestResultConsentGivenTestModule::class,
SubmissionOtherWarningTestModule::class,
SubmissionSymptomIntroFragmentTestModule::class,
SubmissionSymptomCalendarFragmentTestModule::class,
SubmissionContactTestModule::class,
SubmissionDoneTestModule::class,
SubmissionQRInfoFragmentModule::class,
SubmissionQRScanFragmentModule::class
SubmissionQRScanFragmentModule::class,
]
)
class FragmentTestModuleRegistrar
package de.rki.coronawarnapp.ui.submission.testresult
import android.app.AlertDialog
import android.os.Bundle
import android.view.View
import android.view.accessibility.AccessibilityEvent
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentSubmissionTestResultConsentGivenBinding
import de.rki.coronawarnapp.exception.http.CwaClientError
import de.rki.coronawarnapp.exception.http.CwaServerError
import de.rki.coronawarnapp.exception.http.CwaWebException
import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
import de.rki.coronawarnapp.util.DialogHelper
import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withFailure
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.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import javax.inject.Inject
class SubmissionTestResultConsentGivenFragment : Fragment(R.layout.fragment_submission_test_result_consent_given),
AutoInject {
@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val viewModel: SubmissionTestResultConsentGivenViewModel by cwaViewModels { viewModelFactory }
private val binding: FragmentSubmissionTestResultConsentGivenBinding by viewBindingLazy()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.uiState.observe2(this) {
binding.uiState = it
with(binding) {
submissionTestResultSection
.setTestResultSection(uiState?.deviceUiState, uiState?.testResultReceivedDate)
}
it.deviceUiState.withFailure {
if (it is CwaWebException) {
DialogHelper.showDialog(buildErrorDialog(it))
}
}
}
setButtonOnClickListener()
viewModel.showCancelDialog.observe2(this) {
showCancelDialog()
}
viewModel.routeToScreen.observe2(this) {
when (it) {
is SubmissionNavigationEvents.NavigateToSymptomIntroduction ->
doNavigate(
SubmissionTestResultConsentGivenFragmentDirections
.actionSubmissionTestResultConsentGivenFragmentToSubmissionSymptomIntroductionFragment()
)
is SubmissionNavigationEvents.NavigateToMainActivity ->
doNavigate(
SubmissionTestResultConsentGivenFragmentDirections
.actionSubmissionTestResultConsentGivenFragmentToHomeFragment()
)
}
}
}
private fun navigateToMainScreen() =
doNavigate(
SubmissionTestResultConsentGivenFragmentDirections
.actionSubmissionTestResultConsentGivenFragmentToHomeFragment()
)
private fun buildErrorDialog(exception: CwaWebException): DialogHelper.DialogInstance {
return when (exception) {
is CwaClientError, is CwaServerError -> DialogHelper.DialogInstance(
requireActivity(),
R.string.submission_error_dialog_web_generic_error_title,
getString(
R.string.submission_error_dialog_web_generic_network_error_body,
exception.statusCode
),
R.string.submission_error_dialog_web_generic_error_button_positive,
null,
true,
::navigateToMainScreen
)
else -> DialogHelper.DialogInstance(
requireActivity(),
R.string.submission_error_dialog_web_generic_error_title,
R.string.submission_error_dialog_web_generic_error_body,
R.string.submission_error_dialog_web_generic_error_button_positive,
null,
true,
::navigateToMainScreen
)
}
}
override fun onResume() {
super.onResume()
binding.submissionTestResultContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT)
}
private fun setButtonOnClickListener() {
binding.submissionTestResultButtonConsentGivenContinue.setOnClickListener {
viewModel.onContinuePressed()
}
binding.submissionTestResultButtonConsentGivenContinueWithoutSymptoms.setOnClickListener {
viewModel.onShowCancelDialog()
}
binding.submissionTestResultConsentGivenHeader.headerButtonBack.buttonIcon.setOnClickListener {
viewModel.onShowCancelDialog()
}
}
private fun showCancelDialog() {
AlertDialog.Builder(requireContext()).apply {
setTitle(R.string.submission_error_dialog_confirm_cancellation_title)
setMessage(R.string.submission_error_dialog_confirm_cancellation_body)
setPositiveButton(R.string.submission_error_dialog_confirm_cancellation_button_positive) { _, _ ->
viewModel.cancelTestSubmission()
}
setNegativeButton(R.string.submission_error_dialog_confirm_cancellation_button_negative) { _, _ ->
// NOOP
}
}.show()
}
}
package de.rki.coronawarnapp.ui.submission.testresult
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
@Module
abstract class SubmissionTestResultConsentGivenModule {
@Binds
@IntoMap
@CWAViewModelKey(SubmissionTestResultConsentGivenViewModel::class)
abstract fun submissionTestResultConsentGivenFragment(
factory: SubmissionTestResultConsentGivenViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
package de.rki.coronawarnapp.ui.submission.testresult
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import com.squareup.inject.assisted.AssistedInject
import de.rki.coronawarnapp.storage.SubmissionRepository
import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
import de.rki.coronawarnapp.util.DeviceUIState
import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withSuccess
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
class SubmissionTestResultConsentGivenViewModel @AssistedInject constructor(
private val submissionRepository: SubmissionRepository
) : CWAViewModel() {
private val showRedeemedTokenWarning = SingleLiveEvent<Unit>()
private var wasRedeemedTokenErrorShown = false
private val tokenErrorMutex = Mutex()
val uiState: LiveData<TestResultUIState> = combineTransform(
submissionRepository.deviceUIStateFlow,
submissionRepository.testResultReceivedDateFlow
) { deviceUiState, resultDate ->
tokenErrorMutex.withLock {
if (!wasRedeemedTokenErrorShown) {
deviceUiState.withSuccess {
if (it == DeviceUIState.PAIRED_REDEEMED) {
wasRedeemedTokenErrorShown = true
showRedeemedTokenWarning.postValue(Unit)
}
}
}
}
TestResultUIState(
deviceUiState = deviceUiState,
testResultReceivedDate = resultDate
).let { emit(it) }
}.asLiveData(context = Dispatchers.Default)
val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent()
val showCancelDialog = SingleLiveEvent<Unit>()
fun onContinuePressed() {
Timber.d("Beginning symptom flow")
routeToScreen.postValue(SubmissionNavigationEvents.NavigateToSymptomIntroduction)
}
fun onShowCancelDialog() {
showCancelDialog.postValue(Unit)
}
fun cancelTestSubmission() {
Timber.d("Submission was cancelled.")
routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity)
}
@AssistedInject.Factory
interface Factory : SimpleCWAViewModelFactory<SubmissionTestResultConsentGivenViewModel>
}
......@@ -76,6 +76,10 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_
viewModel.uiState.observe2(this) {
binding.uiState = it
with(binding) {
submissionTestResultContent.submissionTestResultSection
.setTestResultSection(uiState?.deviceUiState, uiState?.testResultReceivedDate)
}
it.deviceUiState.withFailure {
if (it is CwaWebException) {
DialogHelper.showDialog(buildErrorDialog(it))
......@@ -147,7 +151,7 @@ class SubmissionTestResultFragment : Fragment(R.layout.fragment_submission_test_
private fun setButtonOnClickListener() {
binding.submissionTestResultButtonPendingRefresh.setOnClickListener {
viewModel.refreshDeviceUIState()
binding.submissionTestResultContent.submissionTestResultCard.testResultCard
binding.submissionTestResultContent.submissionTestResultSection
.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
}
......
......@@ -16,6 +16,8 @@ import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSympto
import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionModule
import de.rki.coronawarnapp.ui.submission.tan.SubmissionTanFragment
import de.rki.coronawarnapp.ui.submission.tan.SubmissionTanModule
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenFragment
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenModule
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultFragment
import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultModule
import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningFragment
......@@ -62,4 +64,7 @@ internal abstract class SubmissionFragmentModule {
@ContributesAndroidInjector(modules = [SubmissionConsentModule::class])
abstract fun submissionConsentScreen(): SubmissionConsentFragment
@ContributesAndroidInjector(modules = [SubmissionTestResultConsentGivenModule::class])
abstract fun submissionTestResultConsentGivenScreen(): SubmissionTestResultConsentGivenFragment
}
package de.rki.coronawarnapp.ui.view
import android.content.Context
import android.graphics.drawable.Drawable
import android.text.Spannable
import android.text.SpannableString
import android.util.AttributeSet
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.withStyledAttributes
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.util.DeviceUIState
import de.rki.coronawarnapp.util.NetworkRequestWrapper
import de.rki.coronawarnapp.util.NetworkRequestWrapper.Companion.withSuccess
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUIFormat
import de.rki.coronawarnapp.util.formatter.formatTestResult
import kotlinx.android.synthetic.main.view_test_result_section.view.*
import java.util.Date
/**
* The [TestResultSectionView] Displays the appropriate test result.
*/
class TestResultSectionView @JvmOverloads
constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
init {
inflate(context, R.layout.view_test_result_section, this)
context.withStyledAttributes(attrs, R.styleable.TestResultSection) {
test_result_section_headline.text =
getText(R.styleable.TestResultSection_test_result_section_headline)
test_result_section_content.text =
getText(R.styleable.TestResultSection_test_result_section_content)
test_result_section_registered_at_text.text =
getText(R.styleable.TestResultSection_test_result_section_registered_at_text)
val resultIconId = getResourceId(R.styleable.TestResultSection_test_result_section_status_icon, 0)
if (resultIconId != 0) {
val drawable = getDrawable(context, resultIconId)
test_result_section_status_icon.setImageDrawable(drawable)
}
}
}
fun setTestResultSection(uiState: NetworkRequestWrapper<DeviceUIState, Throwable>?, registeredAt: Date?) {
test_result_section_registered_at_text.text = formatTestResultRegisteredAtText(registeredAt)
val testResultIcon = formatTestStatusIcon(uiState)
test_result_section_status_icon.setImageDrawable(testResultIcon)
test_result_section_content.text = formatTestResultSectionContent(uiState)
}
private fun formatTestStatusIcon(uiState: NetworkRequestWrapper<DeviceUIState, Throwable>?): Drawable? {
return uiState.withSuccess(R.drawable.ic_test_result_illustration_invalid) {
when (it) {
DeviceUIState.PAIRED_NO_RESULT -> R.drawable.ic_test_result_illustration_pending
DeviceUIState.PAIRED_POSITIVE_TELETAN,
DeviceUIState.PAIRED_POSITIVE -> R.drawable.ic_test_result_illustration_positive
DeviceUIState.PAIRED_NEGATIVE -> R.drawable.ic_test_result_illustration_negative
DeviceUIState.PAIRED_ERROR,
DeviceUIState.PAIRED_REDEEMED -> R.drawable.ic_test_result_illustration_invalid
else -> R.drawable.ic_test_result_illustration_invalid
}
}.let { context.getDrawable(it) }
}
private fun formatTestResultRegisteredAtText(registeredAt: Date?): String {
return context.getString(R.string.test_result_card_registered_at_text)
.format(registeredAt?.toUIFormat(context))
}
private fun formatTestResultSectionContent(uiState: NetworkRequestWrapper<DeviceUIState, Throwable>?): Spannable {
return uiState.withSuccess(SpannableString("")) {
when (it) {
DeviceUIState.PAIRED_NO_RESULT ->
SpannableString(context.getString(R.string.test_result_card_status_pending))
DeviceUIState.PAIRED_ERROR,
DeviceUIState.PAIRED_REDEEMED ->
SpannableString(context.getString(R.string.test_result_card_status_invalid))
DeviceUIState.PAIRED_POSITIVE,
DeviceUIState.PAIRED_POSITIVE_TELETAN,
DeviceUIState.PAIRED_NEGATIVE -> formatTestResult(uiState)
else -> SpannableString("")
}
}
}
}
<?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">
<data>
<import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
<variable
name="uiState"
type="de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/submission_test_result_container"
android:contentDescription="@string/submission_test_result_headline"
android:accessibilityLiveRegion="assertive"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/submission_test_result_consent_given_header"
layout="@layout/include_header"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
app:icon="@{@drawable/ic_close}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:title="@{@string/submission_test_result_consent_given_heading}" />
<ScrollView
android:layout_width="@dimen/match_constraint"
android:layout_height="@dimen/match_constraint"
app:layout_constraintEnd_toEndOf="@+id/guideline_end"
app:layout_constraintStart_toStartOf="@+id/guideline_start"
android:fillViewport="true"
app:layout_constraintTop_toBottomOf="@+id/submission_test_result_consent_given_header"
app:layout_constraintBottom_toTopOf="@+id/include_submission_test_result_consent_given_buttons"
app:layout_constraintVertical_bias="1.0">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true">
<de.rki.coronawarnapp.ui.view.TestResultSectionView
android:id="@+id/submission_test_result_section"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small"
android:focusable="true"
android:importantForAccessibility="yes"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/submission_test_result_consent_given_subtitle"
style="@style/headline6"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:accessibilityHeading="true"
android:text="@string/submission_test_result_consent_given_subtitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" />
<TextView
android:id="@+id/submission_test_result_consent_given_body"
style="@style/body1"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:accessibilityHeading="true"
android:text="@string/submission_test_result_consent_given_body"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/submission_test_result_consent_given_subtitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/include_submission_test_result_consent_given_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierAllowsGoneWidgets="false"
app:barrierDirection="top"
app:constraint_referenced_ids="submission_test_result_button_consent_given_continue" />
<Button
android:id="@+id/submission_test_result_button_consent_given_continue"
style="@style/buttonPrimary"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:text="@string/submission_test_result_positive_continue_button_with_symptoms"
app:layout_constraintBottom_toTopOf="@+id/submission_test_result_button__consent_given_continue_without_symptoms"
app:layout_constraintEnd_toStartOf="@+id/guideline_end"
app:layout_constraintStart_toStartOf="@id/guideline_start"
app:layout_constraintTop_toBottomOf="@+id/guideline_action_large" />
<Button
android:id="@+id/submission_test_result_button_consent_given_continue_without_symptoms"
style="@style/buttonPrimary"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:text="@string/submission_test_result_consent_given_breakup_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline_end"
app:layout_constraintStart_toStartOf="@id/guideline_start"
app:layout_constraintTop_toBottomOf="@+id/submission_test_result_button_consent_given_continue" />
<include layout="@layout/merge_guidelines_side" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_action_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="@dimen/guideline_action_large" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="@dimen/guideline_action" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
......@@ -3,9 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
<variable
name="uiState"
type="de.rki.coronawarnapp.ui.submission.testresult.TestResultUIState" />
......@@ -20,19 +18,17 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="@+id/submission_test_result_card"
layout="@layout/include_test_result_card"
<de.rki.coronawarnapp.ui.view.TestResultSectionView
android:id="@+id/submission_test_result_section"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_small"
android:focusable="true"
android:importantForAccessibility="yes"
app:deviceUIState="@{uiState.deviceUiState}"
app:test_result_section_headline="@string/test_result_card_headline"
app:layout_constraintEnd_toEndOf="@+id/guideline_card_end"
app:layout_constraintStart_toStartOf="@+id/guideline_card_start"
app:layout_constraintTop_toTopOf="parent"
app:registerDate="@{uiState.testResultReceivedDate}" />
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/submission_test_result_subtitle"
......@@ -44,7 +40,7 @@
android:text="@string/submission_test_result_subtitle"
app:layout_constraintEnd_toEndOf="@+id/guideline_end"
app:layout_constraintStart_toStartOf="@+id/guideline_start"
app:layout_constraintTop_toBottomOf="@+id/submission_test_result_card" />
app:layout_constraintTop_toBottomOf="@+id/submission_test_result_section" />
<include
android:id="@+id/submission_test_result_pending_steps"
......
......@@ -4,9 +4,7 @@
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="de.rki.coronawarnapp.util.formatter.FormatterSubmissionHelper" />
<variable
name="registerDate"
type="java.util.Date" />
......
<?xml version="1.0" encoding="utf-8"?>
<merge 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/test_result_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/card_dark"
android:focusable="true"
android:padding="@dimen/card_padding">
<TextView
android:id="@+id/test_result_section_headline"
style="@style/body2"
android:accessibilityHeading="true"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_small"
app:layout_constraintEnd_toStartOf="@id/test_result_section_status_icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Ihr Befund"/>
<TextView
android:id="@+id/test_result_section_content"
style="@style/headline5"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/spacing_small"
android:layout_marginBottom="@dimen/spacing_normal"
app:layout_constraintBottom_toTopOf="@id/test_result_section_registered_at_text"
app:layout_constraintEnd_toStartOf="@id/test_result_section_status_icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/test_result_section_headline"
tools:text="SARS-CoV-2 Negativ" />
<ImageView
android:id="@+id/test_result_section_status_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_test_result_illustration_negative" />
<TextView
android:id="@+id/test_result_section_registered_at_text"
style="@style/body2"
android:layout_width="@dimen/match_constraint"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_normal"
android:layout_marginEnd="@dimen/spacing_small"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/test_result_section_status_icon"
app:layout_constraintStart_toStartOf="parent"
tools:text="@string/test_result_card_registered_at_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
</merge>
\ No newline at end of file
......@@ -395,4 +395,16 @@
app:destination="@id/informationPrivacyFragment" />
</fragment>
<fragment
android:id="@+id/submissionTestResultConsentGivenFragment"
android:name="de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenFragment"
android:label="SubmissionTestResultConsentFragment" >
<action
android:id="@+id/action_submissionTestResultConsentGivenFragment_to_homeFragment"
app:popUpTo="@id/mainFragment"
app:popUpToInclusive="false"/>
<action
android:id="@+id/action_submissionTestResultConsentGivenFragment_to_submissionSymptomIntroductionFragment"
app:destination="@id/submissionSymptomIntroductionFragment" />
</fragment>
</navigation>
......@@ -926,6 +926,16 @@
<string name="submission_test_result_card_positive_title">"SARS-CoV-2 positiv"</string>
<!-- YTXT: Body text for test result card positive -->
<string name="submission_test_result_card_positive_body">"Das Virus SARS-CoV-2 wurde bei Ihnen nachgewiesen."</string>
<!-- XHED: Page headline for test result with consent given -->
<string name="submission_test_result_consent_given_heading">"Ihr Testergebnis"</string>
<!-- XHED: Subtitle text for test result card with consent given -->
<string name="submission_test_result_consent_given_subtitle">"Vielen Dank, dass Sie mithelfen, die Verbreitung von Corona zu bekämpfen."</string>
<!-- YTXT: body text for test result card with consent given -->
<string name="submission_test_result_consent_given_body">"<b>Ihre Mitmenschen werden jetzt gewarnt.</b> <br/><br/>Bitte helfen Sie nun, die Genauigkeit der Warnungen zu verbessern. Geben Sie hierfür im nächsten Schritt an, wann Sie erstmals Symptome hatten. Sie können diesen Schritt jederzeit abbrechen."</string>
<!-- XBUT: button text for the 'break up' button option on test result consent given page -->
<string name="submission_test_result_consent_given_breakup_button">"Beenden"</string>
<!-- Submission Tan -->
<!-- XHED: Page title for TAN submission pge -->
......
......@@ -12,13 +12,17 @@
<attr name="step_entry_icon" format="integer" />
<attr name="step_entry_final" format="boolean" />
</declare-styleable>
<declare-styleable name="SimpleStepEntry">
<attr name="simple_step_entry_title" format="string" />
<attr name="simple_step_entry_text" format="string" />
</declare-styleable>
<declare-styleable name="BulletPointList">
<attr name="entries" format="reference" />
</declare-styleable>
<declare-styleable name="TestResultSection">
<attr name="test_result_section_headline" format="string" />
<attr name="test_result_section_content" format="string" />
<attr name="test_result_section_status_icon" format="reference" />
<attr name="test_result_section_registered_at_text" format="string" />
</declare-styleable>
</resources>
\ No newline at end of file
......@@ -930,6 +930,15 @@
<string name="submission_test_result_card_positive_title">"SARS-CoV-2 positive"</string>
<!-- YTXT: Body text for test result card positive -->
<string name="submission_test_result_card_positive_body">"You have been diagnosed with the SARS-CoV-2 virus."</string>
<!-- XHED: Page headline for test result with consent given -->
<string name="submission_test_result_consent_given_heading">""</string>
<!-- YTXT: Subtitle text for test result card with consent given -->
<string name="submission_test_result_consent_given_subtitle">""</string>
<!-- YTXT: body text for test result card with consent given -->
<string name="submission_test_result_consent_given_body">""</string>
<!-- XBUT: button text for the 'break up' button option on test result consent given page -->
<string name="submission_test_result_consent_given_breakup_button">""</string>
<!-- Submission Tan -->
<!-- XHED: Page title for TAN submission pge -->
......
package de.rki.coronawarnapp.ui.submission.testresult
import de.rki.coronawarnapp.storage.SubmissionRepository
import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionNavigationEvents
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import testhelpers.BaseTest
import testhelpers.extensions.InstantExecutorExtension
@ExtendWith(InstantExecutorExtension::class)
class SubmissionTestResultConsentGivenViewModelTest : BaseTest() {
@MockK
lateinit var submissionRepository: SubmissionRepository
lateinit var viewModel: SubmissionTestResultConsentGivenViewModel
@BeforeEach
fun setUp() {
MockKAnnotations.init(this, relaxed = true)
}
private fun createViewModel() = SubmissionTestResultConsentGivenViewModel(submissionRepository)
@Test
fun testOnConsentProvideSymptomsButtonClick() {
viewModel = createViewModel()
viewModel.onContinuePressed()
viewModel.routeToScreen.value shouldBe SubmissionNavigationEvents.NavigateToSymptomIntroduction
}
@Test
fun testOnCancelled() {
viewModel = createViewModel()
viewModel.cancelTestSubmission()
viewModel.routeToScreen.value shouldBe SubmissionNavigationEvents.NavigateToMainActivity
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment