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

Commit

Permalink
Certification screen (EXPOSUREAPP-7433) (#3323)
Browse files Browse the repository at this point in the history
* CertificatesAdapter with some cards

* Update navigation

* remove old implementation

* update CertificatesViewModel

* update CreateVaccinationCard

* header card

* info card

* fix strings

* clean code

* update CertificatesFragment

* update strings

* Remove unused interfaces

* Update CreateVaccinationCard

Co-authored-by: BMItter <Berndus@gmx.de>
  • Loading branch information
jurajkusnier and BMItr committed Jun 1, 2021
1 parent 17ee826 commit 0195d1f
Show file tree
Hide file tree
Showing 34 changed files with 2,467 additions and 241 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ 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 de.rki.coronawarnapp.vaccination.ui.cards.ImmuneVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.VaccinationCard
import io.mockk.every
import io.mockk.mockk
import org.joda.time.Duration
Expand Down Expand Up @@ -186,7 +186,7 @@ object HomeData {
}

object Vaccination {
val INCOMPLETE = VaccinationHomeCard.Item(
val INCOMPLETE = VaccinationCard.Item(
vaccinatedPerson = mockk<VaccinatedPerson>().apply {
every { fullName } returns "Andrea Schneider"
every { identifier } returns mockk()
Expand All @@ -195,7 +195,7 @@ object HomeData {
},
onClickAction = {}
)
val COMPLETE = VaccinationHomeCard.Item(
val COMPLETE = VaccinationCard.Item(
vaccinatedPerson = mockk<VaccinatedPerson>().apply {
every { fullName } returns "Andrea Schneider"
every { identifier } returns mockk()
Expand All @@ -204,7 +204,7 @@ object HomeData {
},
onClickAction = {}
)
val IMMUNITY = ImmuneVaccinationHomeCard.Item(
val IMMUNITY = ImmuneVaccinationCard.Item(
vaccinatedPerson = mockk<VaccinatedPerson>().apply {
every { fullName } returns "Andrea Schneider"
every { identifier } returns mockk()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import de.rki.coronawarnapp.ui.main.home.items.FAQCard
import de.rki.coronawarnapp.ui.main.home.items.HomeItem
import de.rki.coronawarnapp.ui.statistics.Statistics
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
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
Expand Down Expand Up @@ -251,42 +249,6 @@ class HomeFragmentTest : BaseUITest() {
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()
Expand All @@ -306,8 +268,7 @@ class HomeFragmentTest : BaseUITest() {
// LiveData item for fragments
private fun homeFragmentItemsLiveData(
tracingStateItem: TracingStateItem = HomeData.Tracing.LOW_RISK_ITEM_WITH_ENCOUNTERS,
submissionTestResultItems: List<TestResultItem> = listOf(HomeData.Submission.TEST_UNREGISTERED_ITEM),
vaccinationStatus: VaccinationStatusItem? = null,
submissionTestResultItems: List<TestResultItem> = listOf(HomeData.Submission.TEST_UNREGISTERED_ITEM)
): LiveData<List<HomeItem>> =
MutableLiveData(
mutableListOf<HomeItem>().apply {
Expand All @@ -325,14 +286,8 @@ class HomeFragmentTest : BaseUITest() {
add(tracingStateItem)
}

vaccinationStatus?.let {
add(it)
}

addAll(submissionTestResultItems)

add(CreateVaccinationHomeCard.Item {})

Statistics.statisticsData?.let {
add(StatisticsHomeCard.Item(data = it, onHelpAction = { }))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package de.rki.coronawarnapp.greencertificate.ui.certificates

import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.viewbinding.ViewBinding
import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
import de.rki.coronawarnapp.util.lists.BindableVH
import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter
import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer
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.cards.BottomInfoVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.CreateVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.HeaderInfoVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.ImmuneVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.VaccinationCard

class CertificatesAdapter :
ModularAdapter<CertificatesAdapter.CertificatesItemVH<CertificatesItem, ViewBinding>>(),
AsyncDiffUtilAdapter<CertificatesItem> {

override val asyncDiffer: AsyncDiffer<CertificatesItem> = AsyncDiffer(adapter = this)

init {
modules.addAll(
listOf(
StableIdMod(data),
DataBinderMod<CertificatesItem, CertificatesItemVH<CertificatesItem, ViewBinding>>(data),
TypedVHCreatorMod({ data[it] is ImmuneVaccinationCard.Item }) {
ImmuneVaccinationCard(it)
},
TypedVHCreatorMod({ data[it] is VaccinationCard.Item }) {
VaccinationCard(it)
},
TypedVHCreatorMod({ data[it] is CreateVaccinationCard.Item }) { CreateVaccinationCard(it) },
TypedVHCreatorMod({ data[it] is HeaderInfoVaccinationCard.Item }) { HeaderInfoVaccinationCard(it) },
TypedVHCreatorMod({ data[it] is BottomInfoVaccinationCard.Item }) { BottomInfoVaccinationCard(it) },
)
)
}

override fun getItemCount(): Int = data.size

abstract class CertificatesItemVH<Item : CertificatesItem, VB : ViewBinding>(
@LayoutRes layoutRes: Int,
parent: ViewGroup
) : ModularAdapter.VH(layoutRes, parent), BindableVH<Item, VB>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ package de.rki.coronawarnapp.greencertificate.ui.certificates
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentCertificatesBinding
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.doNavigate
import de.rki.coronawarnapp.util.ui.findNestedGraph
import de.rki.coronawarnapp.util.ui.observe2
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
import javax.inject.Inject

class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInject {
Expand All @@ -17,9 +25,29 @@ class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInjec
private val viewModel by cwaViewModels<CertificatesViewModel> { viewModelFactory }
private val binding by viewBinding<FragmentCertificatesBinding>()

private val certificatesAdapter = CertificatesAdapter()

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

// TODO
binding.recyclerView.apply {
itemAnimator = DefaultItemAnimator()
addItemDecoration(TopBottomPaddingDecorator(topPadding = R.dimen.spacing_tiny))
adapter = certificatesAdapter
}

viewModel.screenItems.observe2(this) { items -> certificatesAdapter.update(items) }
viewModel.events.observe2(this) { event ->
when (event) {
is CertificatesFragmentEvents.GoToVaccinationList -> findNavController().navigate(
VaccinationListFragment.navigationUri(event.personIdentifierCodeSha256)
)
is CertificatesFragmentEvents.OpenVaccinationRegistrationGraph -> {
// TODO: update when certifications info screen is done
findNestedGraph(R.id.vaccination_nav_graph).startDestination = R.id.vaccinationQrCodeScanFragment
doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToVaccinationNavGraph())
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.rki.coronawarnapp.greencertificate.ui.certificates

sealed class CertificatesFragmentEvents {

data class OpenVaccinationRegistrationGraph(val registrationAcknowledged: Boolean) : CertificatesFragmentEvents()

data class GoToVaccinationList(val personIdentifierCodeSha256: String) : CertificatesFragmentEvents()
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,77 @@
package de.rki.coronawarnapp.greencertificate.ui.certificates

import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.greencertificate.ui.certificates.items.CertificatesItem
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
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.cards.BottomInfoVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.CreateVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.HeaderInfoVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.ImmuneVaccinationCard
import de.rki.coronawarnapp.vaccination.ui.cards.VaccinationCard
import kotlinx.coroutines.flow.map

class CertificatesViewModel @AssistedInject constructor() : CWAViewModel() {
class CertificatesViewModel @AssistedInject constructor(
vaccinationRepository: VaccinationRepository,
private val vaccinationSettings: VaccinationSettings
) : CWAViewModel() {

val events = SingleLiveEvent<CertificatesFragmentEvents>()

// TODO: cards should be adjusted in the following PR
val screenItems: LiveData<List<CertificatesItem>> =
vaccinationRepository.vaccinationInfos.map { vaccinatedPersons ->
mutableListOf<CertificatesItem>().apply {
add(HeaderInfoVaccinationCard.Item)

vaccinatedPersons.forEach { vaccinatedPerson ->
val card = when (vaccinatedPerson.getVaccinationStatus()) {
VaccinatedPerson.Status.COMPLETE,
VaccinatedPerson.Status.INCOMPLETE -> VaccinationCard.Item(
vaccinatedPerson = vaccinatedPerson,
onClickAction = {
events.postValue(
CertificatesFragmentEvents.GoToVaccinationList(
vaccinatedPerson.identifier.codeSHA256
)
)
}
)
VaccinatedPerson.Status.IMMUNITY -> ImmuneVaccinationCard.Item(
vaccinatedPerson = vaccinatedPerson,
onClickAction = {
events.postValue(
CertificatesFragmentEvents.GoToVaccinationList(
vaccinatedPerson.identifier.codeSHA256
)
)
}
)
}
add(card)
}

add(
CreateVaccinationCard.Item(
onClickAction = {
events.postValue(
CertificatesFragmentEvents.OpenVaccinationRegistrationGraph(
vaccinationSettings.registrationAcknowledged
)
)
}
)
)
add(BottomInfoVaccinationCard.Item)
}
}.asLiveData()

@AssistedFactory
interface Factory : SimpleCWAViewModelFactory<CertificatesViewModel>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package de.rki.coronawarnapp.greencertificate.ui.certificates.items

import de.rki.coronawarnapp.util.lists.HasStableId

interface CertificatesItem : HasStableId
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ 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.ImmuneVaccinationHomeCard
import de.rki.coronawarnapp.vaccination.ui.homecard.CreateVaccinationHomeCard
import de.rki.coronawarnapp.vaccination.ui.homecard.VaccinationHomeCard

class HomeAdapter :
ModularAdapter<HomeAdapter.HomeItemVH<HomeItem, ViewBinding>>(),
Expand Down Expand Up @@ -79,13 +76,6 @@ class HomeAdapter :
TypedVHCreatorMod({ data[it] is RapidTestOutdatedCard.Item }) { RapidTestOutdatedCard(it) },
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 ImmuneVaccinationHomeCard.Item }) {
ImmuneVaccinationHomeCard(it)
},
TypedVHCreatorMod({ data[it] is VaccinationHomeCard.Item }) {
VaccinationHomeCard(it)
},
SavedStateMod<HomeItemVH<HomeItem, ViewBinding>>() // For statistics card scroll position
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import de.rki.coronawarnapp.util.ui.observe2
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
import javax.inject.Inject

/**
Expand Down Expand Up @@ -159,7 +158,6 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
)
is HomeFragmentEvents.ShowDeleteTestDialog -> showRemoveTestDialog(event.type)
is HomeFragmentEvents.OpenIncompatibleUrl -> openUrl(getString(event.url))
is HomeFragmentEvents.OpenVaccinationRegistrationGraph -> openVaccinationGraph(event)
is HomeFragmentEvents.OpenTraceLocationOrganizerGraph -> openPresenceTracingOrganizerGraph(event)
is HomeFragmentEvents.GoToTestResultAvailableFragment -> doNavigate(
HomeFragmentDirections.actionMainFragmentToSubmissionTestResultAvailableFragment(event.type)
Expand All @@ -170,9 +168,6 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
is HomeFragmentEvents.GoToTestResultKeysSharedFragment -> doNavigate(
HomeFragmentDirections.actionMainFragmentToSubmissionTestResultKeysSharedFragment(event.type)
)
is HomeFragmentEvents.GoToVaccinationList -> findNavController().navigate(
VaccinationListFragment.navigationUri(event.personIdentifierCodeSha256)
)
is HomeFragmentEvents.GoToTestResultPositiveFragment -> doNavigate(
HomeFragmentDirections.actionMainFragmentToSubmissionResultPositiveOtherWarningNoConsentFragment(
event.type
Expand All @@ -193,11 +188,4 @@ class HomeFragment : Fragment(R.layout.home_fragment_layout), AutoInject {
}
doNavigate(HomeFragmentDirections.actionMainFragmentToTraceLocationOrganizerNavGraph())
}

private fun openVaccinationGraph(event: HomeFragmentEvents.OpenVaccinationRegistrationGraph) {
if (event.registrationAcknowledged) {
findNestedGraph(R.id.vaccination_nav_graph).startDestination = R.id.vaccinationQrCodeScanFragment
}
doNavigate(HomeFragmentDirections.actionMainFragmentToVaccinationNavGraph())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ sealed class HomeFragmentEvents {
}
}

data class OpenVaccinationRegistrationGraph(val registrationAcknowledged: Boolean) : HomeFragmentEvents()

data class OpenTraceLocationOrganizerGraph(val qrInfoAcknowledged: Boolean) : HomeFragmentEvents()

data class GoToTestResultPendingFragment(
Expand All @@ -49,6 +47,4 @@ sealed class HomeFragmentEvents {
data class GoToTestResultAvailableFragment(val type: CoronaTest.Type) : HomeFragmentEvents()

data class GoToTestResultPositiveFragment(val type: CoronaTest.Type) : HomeFragmentEvents()

data class GoToVaccinationList(val personIdentifierCodeSha256: String) : HomeFragmentEvents()
}

0 comments on commit 0195d1f

Please sign in to comment.