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

Family Test skeleton P2 (EXPOSUREAPP-12323) #4948

Merged
merged 14 commits into from
Mar 18, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class RequestCovidCertificateFragmentTest : BaseUITest() {
override fun create(
testRegistrationRequest: TestRegistrationRequest,
coronaTestConsent: Boolean,
deleteOldTest: Boolean
allowTestReplacement: Boolean,
personName: String?
): RequestCovidCertificateViewModel = viewModel
}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.rki.coronawarnapp.coronatest

import android.os.Parcelable
import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
import de.rki.coronawarnapp.coronatest.type.CoronaTest
import org.joda.time.LocalDate

Expand All @@ -11,3 +12,6 @@ interface TestRegistrationRequest : Parcelable {
val isDccConsentGiven: Boolean
val dateOfBirth: LocalDate?
}

val TestRegistrationRequest.isFamilyTest: Boolean
get() = this is CoronaTestQRCode && this.categoryType == CoronaTestQRCode.CategoryType.FAMILY
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ sealed class CoronaTestQRCode : Parcelable, TestRegistrationRequest, QrCode {
abstract override val type: CoronaTest.Type
abstract val registrationIdentifier: String
abstract val rawQrCode: String
abstract val categoryType: CoronaTest.CategoryType
abstract val categoryType: CategoryType

@Parcelize
data class PCR(
val qrCodeGUID: CoronaTestGUID,
override val isDccConsentGiven: Boolean = false,
override val dateOfBirth: LocalDate? = null,
override val rawQrCode: String,
override val categoryType: CoronaTest.CategoryType = CoronaTest.CategoryType.NOT_SELECTED
override val categoryType: CategoryType = CategoryType.NOT_SELECTED
) : CoronaTestQRCode() {

@IgnoredOnParcel
Expand Down Expand Up @@ -68,7 +68,7 @@ sealed class CoronaTestQRCode : Parcelable, TestRegistrationRequest, QrCode {
override val lastName: String? = null,
override val testId: String? = null,
override val salt: String? = null,
override val categoryType: CoronaTest.CategoryType = CoronaTest.CategoryType.NOT_SELECTED
override val categoryType: CategoryType = CategoryType.NOT_SELECTED
) : Rapid() {
@IgnoredOnParcel
override val type: CoronaTest.Type = CoronaTest.Type.RAPID_ANTIGEN
Expand All @@ -86,11 +86,17 @@ sealed class CoronaTestQRCode : Parcelable, TestRegistrationRequest, QrCode {
override val lastName: String? = null,
override val testId: String? = null,
override val salt: String? = null,
override val categoryType: CoronaTest.CategoryType = CoronaTest.CategoryType.NOT_SELECTED
override val categoryType: CategoryType = CategoryType.NOT_SELECTED
) : Rapid() {
@IgnoredOnParcel
override val type: CoronaTest.Type = CoronaTest.Type.PCR
}

enum class CategoryType {
FAMILY,
OWN,
NOT_SELECTED,
}
}

typealias CoronaTestGUID = String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,6 @@ interface CoronaTest : Recyclable {
@SerializedName("RAPID_ANTIGEN")
RAPID_ANTIGEN("RAPID_ANTIGEN"),
}

enum class CategoryType(val raw: String) {
@SerializedName("FAMILY")
FAMILY("FAMILY"),

@SerializedName("OWN")
OWN("OWN"),

@SerializedName("NOT_SELECTED")
NOT_SELECTED("NOT_SELECTED"),
}
}

typealias RegistrationToken = String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package de.rki.coronawarnapp.familytest.core

import dagger.Module

@Module
class FamilyTestModule
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.rki.coronawarnapp.familytest.core.model

import de.rki.coronawarnapp.coronatest.type.CoronaTest

data class FamilyTest(
val coronaTest: CoronaTest,
val personName: String,
) : CoronaTest by coronaTest // To be manipulated as CoronaTest where needed
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package de.rki.coronawarnapp.familytest.core.repository

import de.rki.coronawarnapp.coronatest.TestRegistrationRequest
import de.rki.coronawarnapp.coronatest.type.TestIdentifier
import de.rki.coronawarnapp.familytest.core.model.FamilyTest
import de.rki.coronawarnapp.util.coroutine.AppScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import javax.inject.Inject

class FamilyTestRepository @Inject constructor(
@AppScope private val appScope: CoroutineScope
) {

val familyTests: Flow<Set<FamilyTest>> = flowOf()
val recycledFamilyTests: Flow<Set<FamilyTest>> = flowOf()

suspend fun registerTest(
request: TestRegistrationRequest,
personName: String
): FamilyTest {
// TBD
throw NotImplementedError()
}

suspend fun restoreTest(
identifier: TestIdentifier
) {
// TBD
}

suspend fun recycleTest(
identifier: TestIdentifier
) {
// TBD
}

suspend fun deleteTest(
identifier: TestIdentifier
) {
// TBD
}

/**
* Try to refresh available family tests
* Does not throw any error
*/
suspend fun refresh() {
// TBD
}

suspend fun markBadgeAsViewed(
identifier: TestIdentifier
) {
// TBD
}

suspend fun updateResultNotification(
identifier: TestIdentifier,
sent: Boolean
) {
// TBD
}

suspend fun markDccAsCreated(
identifier: TestIdentifier,
created: Boolean
) {
// TBD
}

suspend fun clear() {
// TBD
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package de.rki.coronawarnapp.familytest.ui

import dagger.Module

@Module
class FamilyTestUiModule
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ 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.exception.reporting.report
import de.rki.coronawarnapp.familytest.core.repository.FamilyTestRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex
Expand All @@ -24,6 +25,7 @@ import javax.inject.Inject

class TestRegistrationStateProcessor @Inject constructor(
private val submissionRepository: SubmissionRepository,
private val familyTestRepository: FamilyTestRepository,
private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector,
) {

Expand Down Expand Up @@ -88,19 +90,17 @@ class TestRegistrationStateProcessor @Inject constructor(
private val stateInternal = MutableStateFlow<State>(State.Idle)
val state: Flow<State> = stateInternal

suspend fun startRegistration(
suspend fun startTestRegistration(
request: TestRegistrationRequest,
isSubmissionConsentGiven: Boolean,
allowReplacement: Boolean,
allowTestReplacement: Boolean,
): CoronaTest? = mutex.withLock {
return try {
stateInternal.value = State.Working

PcrQrCodeCensor.dateOfBirth = request.dateOfBirth
val coronaTest = if (allowReplacement) {
submissionRepository.tryReplaceTest(request)
} else {
submissionRepository.registerTest(request)
val coronaTest = with(submissionRepository) {
if (allowTestReplacement) tryReplaceTest(request) else registerTest(request)
}

if (isSubmissionConsentGiven) {
Expand All @@ -120,4 +120,24 @@ class TestRegistrationStateProcessor @Inject constructor(
null
}
}

suspend fun startFamilyTestRegistration(
request: TestRegistrationRequest,
personName: String
): CoronaTest? = mutex.withLock {
return try {
stateInternal.value = State.Working

PcrQrCodeCensor.dateOfBirth = request.dateOfBirth
val coronaTest = familyTestRepository.registerTest(request, personName)
stateInternal.value = State.TestRegistered(test = coronaTest)
coronaTest
} catch (err: Exception) {
stateInternal.value = State.Error(exception = err)
if (err !is CwaWebException && err !is AlreadyRedeemedException) {
err.report(ExceptionCategory.INTERNAL)
}
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import de.rki.coronawarnapp.covidcertificate.DigitalCovidCertificateUIModule
import de.rki.coronawarnapp.datadonation.analytics.ui.AnalyticsUIModule
import de.rki.coronawarnapp.dccreissuance.DccReissuanceUiModule
import de.rki.coronawarnapp.dccticketing.DccTicketingUIModule
import de.rki.coronawarnapp.familytest.ui.FamilyTestUiModule
import de.rki.coronawarnapp.qrcode.ui.QrCodeScannerFragment
import de.rki.coronawarnapp.qrcode.ui.QrCodeScannerFragmentModule
import de.rki.coronawarnapp.release.NewReleaseInfoFragment
Expand Down Expand Up @@ -54,7 +55,8 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
DigitalCovidCertificateUIModule::class,
RecyclerBinUIModule::class,
DccTicketingUIModule::class,
DccReissuanceUiModule::class
DccReissuanceUiModule::class,
FamilyTestUiModule::class,
]
)
abstract class MainActivityModule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import de.rki.coronawarnapp.coronatest.type.pcr.toSubmissionState
import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest
import de.rki.coronawarnapp.coronatest.type.rapidantigen.SubmissionStateRAT
import de.rki.coronawarnapp.coronatest.type.rapidantigen.toSubmissionState
import de.rki.coronawarnapp.familytest.core.repository.FamilyTestRepository
import de.rki.coronawarnapp.main.CWASettings
import de.rki.coronawarnapp.reyclebin.coronatest.RecycledCoronaTestsProvider
import de.rki.coronawarnapp.risk.RiskCardDisplayInfo
Expand Down Expand Up @@ -111,7 +112,8 @@ class HomeFragmentViewModel @AssistedInject constructor(
private val bluetoothSupport: BluetoothSupport,
private val localStatisticsConfigStorage: LocalStatisticsConfigStorage,
private val recycledTestProvider: RecycledCoronaTestsProvider,
private val riskCardDisplayInfo: RiskCardDisplayInfo
private val riskCardDisplayInfo: RiskCardDisplayInfo,
private val familyTestRepository: FamilyTestRepository,
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {

private var isLoweredRiskLevelDialogBeingShown = false
Expand Down Expand Up @@ -190,8 +192,9 @@ class HomeFragmentViewModel @AssistedInject constructor(
coronaTestRepository.latestPCRT,
coronaTestRepository.latestRAT,
combinedStatistics,
appConfigProvider.currentConfig.map { it.coronaTestParameters }.distinctUntilChanged()
) { tracingItem, testPCR, testRAT, statsData, coronaTestParameters ->
appConfigProvider.currentConfig.map { it.coronaTestParameters }.distinctUntilChanged(),
familyTestRepository.familyTests
) { tracingItem, testPCR, testRAT, statsData, coronaTestParameters, familyTests ->
val statePCR = testPCR.toSubmissionState()
val stateRAT = testRAT.toSubmissionState(timeStamper.nowUTC, coronaTestParameters)
val pcrIdentifier = testPCR?.identifier ?: ""
Expand Down Expand Up @@ -220,6 +223,7 @@ class HomeFragmentViewModel @AssistedInject constructor(
)
}

// My own tests
when (statePCR) {
SubmissionStatePCR.NoTest -> {
if (stateRAT == SubmissionStateRAT.NoTest) {
Expand All @@ -244,6 +248,12 @@ class HomeFragmentViewModel @AssistedInject constructor(
}
}

// Family tests tile
if (familyTests.isNotEmpty()) {
val badgeCount = familyTests.count { !it.didShowBadge }
// TBD family tests tile
}

if (statsData.isDataAvailable) {
add(
StatisticsHomeCard.Item(
Expand Down Expand Up @@ -310,6 +320,7 @@ class HomeFragmentViewModel @AssistedInject constructor(
launch {
try {
submissionRepository.refreshTest()
familyTestRepository.refresh()
} catch (e: CoronaTestNotFoundException) {
Timber.e(e, "refreshTest failed")
errorEvent.postValue(e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ class RequestCovidCertificateFragment : Fragment(R.layout.fragment_request_covid
factoryProducer = { viewModelFactory },
constructorCall = { factory, _ ->
factory as RequestCovidCertificateViewModel.Factory
factory.create(args.testRegistrationRequest, args.coronaTestConsent, args.allowTestReplacement)
factory.create(
testRegistrationRequest = args.testRegistrationRequest,
coronaTestConsent = args.coronaTestConsent,
allowTestReplacement = args.allowTestReplacement,
personName = args.personName
)
}
)
private val binding by viewBinding<FragmentRequestCovidCertificateBinding>()
Expand Down
Loading