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

[UI] Family test selection and consent screen (EXPOSUREAPP-12316, EXPOSUREAPP-12317) #4951

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
71fcf47
Setup UI flow from scanner
mtwalli Mar 17, 2022
4936c0a
Lint
mtwalli Mar 17, 2022
5ef6e3d
Normal and legal texts, layout and icons for submission test type sel…
AlexanderAlferov Mar 17, 2022
c7ee698
Merge remote-tracking branch 'origin/release/2.21.x' into feature/123…
AlexanderAlferov Mar 17, 2022
85e5268
Merge branch 'release/2.21.x' into feature/12316-12317-family-test-se…
mtwalli Mar 21, 2022
855fc5c
Basic logic
AlexanderAlferov Mar 21, 2022
d7d46b8
Merge branch 'feature/12316-12317-family-test-selection-and-consent' …
AlexanderAlferov Mar 21, 2022
de235f8
Strings aligned with iOS version
AlexanderAlferov Mar 22, 2022
3a3b727
Merge remote-tracking branch 'origin/release/2.21.x' into feature/123…
AlexanderAlferov Mar 22, 2022
a6aa1f8
Tests and fixes
AlexanderAlferov Mar 22, 2022
3dec0e9
Merge remote-tracking branch 'origin/release/2.21.x' into feature/123…
AlexanderAlferov Mar 22, 2022
ae80f9c
Legal strings fix
AlexanderAlferov Mar 22, 2022
a11326b
Merge branch 'release/2.21.x' into feature/12316-12317-family-test-se…
AlexanderAlferov Mar 22, 2022
38c137a
Merge branch 'release/2.21.x' into feature/12316-12317-family-test-se…
SamuraiKek Mar 23, 2022
ce8994f
Fix
AlexanderAlferov Mar 23, 2022
8b29c86
Merge branch 'feature/12316-12317-family-test-selection-and-consent' …
AlexanderAlferov Mar 23, 2022
0c8ea45
Merge branch 'release/2.21.x' into feature/12316-12317-family-test-se…
mtwalli Mar 23, 2022
a02406d
Lint
mtwalli Mar 23, 2022
c7ae7d4
Navigation fix
AlexanderAlferov Mar 24, 2022
1062088
Lint fix
AlexanderAlferov Mar 24, 2022
d05599d
Merge branch 'release/2.21.x' into feature/12316-12317-family-test-se…
mtwalli Mar 24, 2022
a5118a9
Fix
AlexanderAlferov Mar 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,103 @@
package de.rki.coronawarnapp.familytest.ui.consent

import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.Fragment
import androidx.navigation.NavOptions
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import de.rki.coronawarnapp.NavGraphDirections
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.contactdiary.util.focusAndShowKeyboard
import de.rki.coronawarnapp.contactdiary.util.hideKeyboard
import de.rki.coronawarnapp.databinding.FragmentFamilyTestConsentBinding
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.viewBinding
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
import javax.inject.Inject

class FamilyTestConsentFragment : Fragment(R.layout.fragment_family_test_consent)
class FamilyTestConsentFragment : Fragment(R.layout.fragment_family_test_consent), AutoInject {

@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val navArgs by navArgs<FamilyTestConsentFragmentArgs>()
private val viewModel: FamilyTestConsentViewModel by cwaViewModelsAssisted(
factoryProducer = { viewModelFactory },
constructorCall = { factory, _ ->
factory as FamilyTestConsentViewModel.Factory
factory.create(navArgs.coronaTestQrCode)
}
)
private val binding: FragmentFamilyTestConsentBinding by viewBinding()
private val navOptions = NavOptions.Builder().setPopUpTo(R.id.familyTestConsentFragment, true).build()

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

viewModel.routeToScreen.observe2(this) {
when (it) {
is FamilyTestConsentNavigationEvents.NavigateBack -> {
binding.root.hideKeyboard()
popBackStack()
}
is FamilyTestConsentNavigationEvents.NavigateToDataPrivacy -> doNavigate(
FamilyTestConsentFragmentDirections.actionFamilyTestConsentFragmentToInformationPrivacyFragment()
)
is FamilyTestConsentNavigationEvents.NavigateToCertificateRequest -> findNavController().navigate(
NavGraphDirections.actionRequestCovidCertificateFragment(
testRegistrationRequest = it.coronaTestQRCode,
coronaTestConsent = it.consentGiven,
allowTestReplacement = it.allowReplacement
),
navOptions
)
else -> Unit
}
}

binding.apply {
nameInputEdit.focusAndShowKeyboard()
nameInputEdit.doAfterTextChanged {
viewModel.nameChanged(it.toString())
}
nameInputEdit.setOnEditorActionListener { _, actionId, _ ->
return@setOnEditorActionListener when (actionId) {
EditorInfo.IME_ACTION_DONE -> {
if (viewModel.isValid.value == true) {
binding.consentButton.performClick()
}
false
}
else -> true
}
}
toolbar.setOnClickListener {
viewModel.onNavigateBack()
}
dataPrivacy.setOnClickListener {
viewModel.onDataPrivacyClick()
}
consentButton.setOnClickListener {
viewModel.onConsentButtonClick()
}
}

viewModel.isValid.observe2(this) {
binding.consentButton.isEnabled = it
}
// TODO: FOR TEST ONLY
viewModel.registrationState.observe2(this) { state ->
val isWorking = state is FamilyTestConsentViewModel.State.Working
binding.apply {
progressSpinner.isVisible = isWorking
consentButton.isEnabled = !isWorking
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.rki.coronawarnapp.familytest.ui.consent

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 FamilyTestConsentModule {
@Binds
@IntoMap
@CWAViewModelKey(FamilyTestConsentViewModel::class)
abstract fun familyTestConsentFragment(
factory: FamilyTestConsentViewModel.Factory
): CWAViewModelFactory<out CWAViewModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.rki.coronawarnapp.familytest.ui.consent

import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode

sealed class FamilyTestConsentNavigationEvents {

data class NavigateToCertificateRequest(
val coronaTestQRCode: CoronaTestQRCode,
val consentGiven: Boolean,
val allowReplacement: Boolean
) : FamilyTestConsentNavigationEvents()

object NavigateToDataPrivacy : FamilyTestConsentNavigationEvents()

object NavigateBack : FamilyTestConsentNavigationEvents()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package de.rki.coronawarnapp.familytest.ui.consent

import androidx.lifecycle.asLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import timber.log.Timber
import java.lang.Exception

class FamilyTestConsentViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
@Assisted private val coronaTestQRCode: CoronaTestQRCode,
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {

private val registrationStateInternal = MutableStateFlow<State>(State.Idle) // TODO: FOR TEST ONLY
val registrationState = registrationStateInternal.asLiveData() // TODO: FOR TEST ONLY

val routeToScreen = SingleLiveEvent<FamilyTestConsentNavigationEvents>()

private val personName = MutableStateFlow("")

val isValid = personName
.map { it.isNotEmpty() }
.asLiveData()

fun nameChanged(value: String) {
personName.value = value
}

fun onDataPrivacyClick() {
routeToScreen.postValue(FamilyTestConsentNavigationEvents.NavigateToDataPrivacy)
}

fun onNavigateBack() {
routeToScreen.postValue(FamilyTestConsentNavigationEvents.NavigateBack)
}

fun onConsentButtonClick() = launch {
try {
// TODO: Replace with proper test registration process
registrationStateInternal.value = State.Working // TODO: FOR TEST ONLY
delay(2000) // TODO: FOR TEST ONLY
FamilyTestConsentNavigationEvents.NavigateToCertificateRequest(
coronaTestQRCode = coronaTestQRCode,
consentGiven = true,
allowReplacement = false // TODO: check if it should be passed as navArg
).run { routeToScreen.postValue(this) }
} catch (exception: Exception) {
// TODO: exception handler
Timber.d(exception, "Something went wrong...")
}
}

// TODO: FOR TEST ONLY
sealed class State {
object Idle : State()
object Working : State()
}

@AssistedFactory
interface Factory : CWAViewModelFactory<FamilyTestConsentViewModel> {
fun create(
coronaTestQRCode: CoronaTestQRCode
): FamilyTestConsentViewModel
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
package de.rki.coronawarnapp.familytest.ui.selection

import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.navArgs
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestRegistrationSelectionBinding
import de.rki.coronawarnapp.util.ui.doNavigate
import de.rki.coronawarnapp.util.ui.popBackStack
import de.rki.coronawarnapp.util.ui.viewBinding

class TestRegistrationSelectionFragment : Fragment(R.layout.fragment_test_registration_selection)
class TestRegistrationSelectionFragment : Fragment(R.layout.fragment_test_registration_selection) {

private val navArgs by navArgs<TestRegistrationSelectionFragmentArgs>()
private val binding: FragmentTestRegistrationSelectionBinding by viewBinding()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.toolbar.setNavigationOnClickListener { popBackStack() }
binding.person.setOnClickListener {
doNavigate(
TestRegistrationSelectionFragmentDirections
.actionTestRegistrationSelectionFragmentToSubmissionConsentFragment(
mtwalli marked this conversation as resolved.
Show resolved Hide resolved
coronaTestQrCode = navArgs.coronaTestQrCode
mtwalli marked this conversation as resolved.
Show resolved Hide resolved
)
)
}
binding.family.setOnClickListener {
doNavigate(
TestRegistrationSelectionFragmentDirections
.actionTestRegistrationSelectionFragmentToFamilyTestConsentFragment(
coronaTestQrCode = navArgs.coronaTestQrCode
mtwalli marked this conversation as resolved.
Show resolved Hide resolved
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package de.rki.coronawarnapp.ui.submission.viewmodel

import dagger.Module
import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.familytest.ui.consent.FamilyTestConsentFragment
import de.rki.coronawarnapp.familytest.ui.consent.FamilyTestConsentModule
import de.rki.coronawarnapp.submission.ui.testresults.negative.RATResultNegativeFragment
import de.rki.coronawarnapp.submission.ui.testresults.negative.RATResultNegativeModule
import de.rki.coronawarnapp.ui.submission.fragment.SubmissionContactFragment
Expand Down Expand Up @@ -110,4 +112,7 @@ internal abstract class SubmissionFragmentModule {

@ContributesAndroidInjector(modules = [RequestCovidCertificateFragmentModule::class])
abstract fun requestCovidCertificateFragment(): RequestCovidCertificateFragment

@ContributesAndroidInjector(modules = [FamilyTestConsentModule::class])
abstract fun familyTestConsentFragment(): FamilyTestConsentFragment
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:pathData="M0,15.6341a16,15.6341 0,1 0,32 0a16,15.6341 0,1 0,-32 0z"
android:fillColor="#434445"/>
<path
android:pathData="M26.6104,16.3141L24.2136,13.5735L24.5476,9.9488L21.0015,9.1433L19.145,6L15.8052,7.4342L12.4654,6L10.6089,9.1335L7.0628,9.9292L7.3968,13.5636L5,16.3141L7.3968,19.0547L7.0628,22.6891L10.6089,23.4946L12.4654,26.6281L15.8052,25.1842L19.145,26.6183L21.0015,23.4848L24.5476,22.6793L24.2136,19.0547L26.6104,16.3141ZM13.929,20.9505L10.1963,17.2079L11.6501,15.7542L13.929,18.0429L19.6754,12.2768L21.1292,13.7306L13.929,20.9505Z"
android:fillColor="#83D2F2"/>
</vector>
Loading