From 7c56e97ec603a2820e82facf56ccadaa66066e0e Mon Sep 17 00:00:00 2001 From: Lukas Lechner <lukas.lechner@sap.com> Date: Mon, 10 May 2021 16:15:59 +0200 Subject: [PATCH] Screen: Vaccination List (EXPOSUREAPP-6734) (#3082) * Create first version of incomplete vaccination list screen with mock data * Add UiState for VaccinationListFragment.kt * Set Toolbar Overlay * Fine tune fragment_vaccination_list.xml * Use ModularAdapter * Add click listener to navigate to detail fragment * Fix nav_graph issue * Adjust layouts for night mode * Fix vaccination card colors * Fix mock data * Revert changes in Project.xml * Add TODO * Show blue background on complete vaccination status * Show subtitle on complete vaccination status * Add VaccinationListCertificateCardItem.kt * Show Refresh button on complete vaccination status * Add fragment in vaccination_nav_graph.xml * Connect Vaccination List ViewModel to Vaccination Repository * Create new mock data * Adapt VaccinationTestFragment.kt * Try to make sonar happy * Use VaccinationCertificate and ProofCertificate interfaces instead of VaccinationCertificateV1 and ProofCertificateV1 * Adjust title+subtitle alignment * Adjust text size in vaccination_list_incomplete_top_card.xml * Use isEligibleForProofCertificate boolean to show 'refresh' or 'register new vaccination' button * Adjust subtitle color of vaccination_list_certificate_card.xml and vaccination_list_name_card.xml * Fix package declaration of VaccinationListAdapter * Update VaccinationListAdapter instead of re-creating a new one each time we observe a uiState change * Refactor Navigation * Show sample QR-code * Add some layout improvements * Adjust background height for COMPLETE and INCOMPLETE state * Show both buttons in VaccinationListFragment - Refresh button and register Vaccination button * Use separate flow to generate qrCode * Refactor CardItems to be inlined into their ViewHolders * Ignore onClick listener in equals() and hashCode() of VaccinationListVaccinationCardItem.kt to avoid re-drawings * Fix Lint * Fix Detekt Co-authored-by: Mohamed <mohamed.metwalli@sap.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> --- .../vaccination/ui/VaccinationTestFragment.kt | 9 + .../res/layout/fragment_test_vaccination.xml | 12 +- .../res/navigation/test_nav_graph.xml | 17 ++ .../util/TimeAndDateExtensions.kt | 13 ++ .../vaccination/ui/VaccinationUIModule.kt | 6 + .../ui/list/VaccinationListFragment.kt | 122 +++++++++++++ .../ui/list/VaccinationListFragmentModule.kt | 19 ++ .../ui/list/VaccinationListViewModel.kt | 168 ++++++++++++++++++ .../ui/list/VaccinationMockData.kt | 83 +++++++++ .../ui/list/adapter/VaccinationListAdapter.kt | 60 +++++++ .../VaccinationListCertificateCardItemVH.kt | 43 +++++ .../VaccinationListIncompleteTopCardItemVH.kt | 27 +++ .../VaccinationListNameCardItemVH.kt | 33 ++++ .../VaccinationListVaccinationCardItemVH.kt | 111 ++++++++++++ .../drawable-night/ic_arrow_right_grey.xml | 10 ++ .../main/res/drawable/ic_arrow_right_grey.xml | 11 ++ .../res/drawable/ic_vaccination_complete.xml | 47 +++++ .../ic_vaccination_complete_final.xml | 30 ++++ .../drawable/ic_vaccination_incomplete.xml | 15 ++ .../ic_vaccination_incomplete_final.xml | 15 ++ .../layout/fragment_vaccination_details.xml | 2 +- .../res/layout/fragment_vaccination_list.xml | 140 +++++++++++++++ .../vaccination_list_certificate_card.xml | 64 +++++++ .../vaccination_list_incomplete_top_card.xml | 30 ++++ .../res/layout/vaccination_list_name_card.xml | 29 +++ .../vaccination_list_vaccination_card.xml | 55 ++++++ .../res/navigation/vaccination_nav_graph.xml | 13 ++ .../res/values-de/vaccination_strings.xml | 25 +++ .../src/main/res/values-night/colors.xml | 4 + .../src/main/res/values/colors.xml | 4 +- .../src/main/res/values/styles.xml | 7 + .../main/res/values/vaccination_strings.xml | 25 +++ 32 files changed, 1246 insertions(+), 3 deletions(-) create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationMockData.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt create mode 100644 Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete_final.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml create mode 100644 Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml create mode 100644 Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml create mode 100644 Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml create mode 100644 Corona-Warn-App/src/main/res/layout/vaccination_list_name_card.xml create mode 100644 Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt index 93fe4ac72..5bea439e2 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/vaccination/ui/VaccinationTestFragment.kt @@ -24,6 +24,15 @@ class VaccinationTestFragment : Fragment(R.layout.fragment_test_vaccination), Au override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + binding.openVaccinationList.setOnClickListener { + doNavigate( + VaccinationTestFragmentDirections.actionVaccinationTestFragmentToVaccinationListFragment( + "vaccinated-person-identifier" + ) + ) + } + binding.openVaccinationDetailsIncomplete.setOnClickListener { doNavigate( VaccinationTestFragmentDirections diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml index 2c5298753..ca0a9a4d5 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_vaccination.xml @@ -31,6 +31,16 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + <com.google.android.material.button.MaterialButton + android:id="@+id/open_vaccination_list" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="Vaccination List" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textView2" /> + <com.google.android.material.button.MaterialButton android:id="@+id/open_vaccination_details_complete" android:layout_width="wrap_content" @@ -39,7 +49,7 @@ android:text="Vaccination details - complete" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/textView2" /> + app:layout_constraintTop_toBottomOf="@+id/open_vaccination_list" /> <com.google.android.material.button.MaterialButton android:id="@+id/open_vaccination_details_incomplete" diff --git a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml index 6056a4d1e..bbb72a602 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/navigation/test_nav_graph.xml @@ -170,9 +170,26 @@ android:name="de.rki.coronawarnapp.vaccination.ui.VaccinationTestFragment" android:label="VaccinationTestFragment" tools:layout="@layout/fragment_test_vaccination" > + <action android:id="@+id/action_vaccinationTestFragment_to_vaccinationDetailsFragment" app:destination="@id/vaccinationDetailsFragment" /> + <action + android:id="@+id/action_vaccinationTestFragment_to_vaccinationListFragment" + app:destination="@id/vaccinationListFragment" /> + </fragment> + + <fragment + android:id="@+id/vaccinationListFragment" + android:name="de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment" + android:label="fragment_vaccination_list" + tools:layout="@layout/fragment_vaccination_list"> + <argument + android:name="vaccinatedPersonId" + app:argType="string" /> + <action + android:id="@+id/action_vaccinationListFragment_to_vaccinationDetailsFragment" + app:destination="@id/vaccinationDetailsFragment" /> </fragment> <fragment diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt index 60b57e29d..7392f5fe7 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/TimeAndDateExtensions.kt @@ -16,12 +16,15 @@ import java.util.Date import java.util.TimeZone import java.util.concurrent.TimeUnit +@Suppress("TooManyFunctions") object TimeAndDateExtensions { private const val MS_TO_DAYS = (1000 * 60 * 60 * 24) private const val MS_TO_HOURS = (1000 * 60 * 60) private const val MS_TO_SECONDS = 1000 + private val dayFormatter = DateTimeFormat.forPattern("dd.MM.yyyy") + fun getCurrentHourUTC(): Int = DateTime(Instant.now(), DateTimeZone.UTC).hourOfDay().get() fun Date.toServerFormat(): String = @@ -104,6 +107,16 @@ object TimeAndDateExtensions { fun Instant.toUserTimeZone() = this.toDateTime(DateTimeZone.forTimeZone(TimeZone.getDefault())) fun Instant.toLocalDateUserTz(): LocalDate = this.toUserTimeZone().toLocalDate() + + /** + * Returns a readable date String with the format "dd.MM.yyyy" like 23.05.1989 of an Instant + */ + fun Instant.toDayFormat() = toString(dayFormatter) + + /** + * Returns a readable date String with the format "dd.MM.yyyy" like 23.05.1989 of a LocalDate + */ + fun LocalDate.toDayFormat() = toString(dayFormatter) } typealias HourInterval = Long diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt index ddbd04c76..78afda0dd 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/VaccinationUIModule.kt @@ -4,9 +4,15 @@ import dagger.Module import dagger.android.ContributesAndroidInjector import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragment import de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragmentModule +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragmentModule @Module abstract class VaccinationUIModule { + + @ContributesAndroidInjector(modules = [VaccinationListFragmentModule::class]) + abstract fun vaccinationListFragment(): VaccinationListFragment + @ContributesAndroidInjector(modules = [VaccinationDetailsFragmentModule::class]) abstract fun vaccinationDetailsFragment(): VaccinationDetailsFragment } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt new file mode 100644 index 000000000..93ce6c491 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragment.kt @@ -0,0 +1,122 @@ +package de.rki.coronawarnapp.vaccination.ui.list + +import android.os.Bundle +import android.view.View +import android.widget.LinearLayout +import android.widget.Toast +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs +import com.google.android.material.appbar.AppBarLayout +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentVaccinationListBinding +import de.rki.coronawarnapp.ui.view.onOffsetChange +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.lists.diffutil.update +import de.rki.coronawarnapp.util.ui.doNavigate +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.cwaViewModelsAssisted +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson +import de.rki.coronawarnapp.vaccination.ui.list.VaccinationListViewModel.Event.NavigateToVaccinationCertificateDetails +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import javax.inject.Inject + +class VaccinationListFragment : Fragment(R.layout.fragment_vaccination_list), AutoInject { + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + + private val args by navArgs<VaccinationListFragmentArgs>() + private val binding: FragmentVaccinationListBinding by viewBindingLazy() + private val viewModel: VaccinationListViewModel by cwaViewModelsAssisted( + factoryProducer = { viewModelFactory }, + constructorCall = { factory, _ -> + factory as VaccinationListViewModel.Factory + factory.create( + vaccinatedPersonIdentifier = args.vaccinatedPersonId + ) + } + ) + + private val adapter = VaccinationListAdapter() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + with(binding) { + toolbar.setNavigationOnClickListener { + popBackStack() + } + + recyclerViewVaccinationList.adapter = adapter + + viewModel.uiState.observe(viewLifecycleOwner) { uiState -> + bindViews(uiState) + } + + viewModel.events.observe(viewLifecycleOwner) { event -> + when (event) { + is NavigateToVaccinationCertificateDetails -> doNavigate( + VaccinationListFragmentDirections.actionVaccinationListFragmentToVaccinationDetailsFragment( + event.vaccinationCertificateId + ) + ) + } + } + + registerNewVaccinationButton.setOnClickListener { + Toast.makeText(requireContext(), "TODO \uD83D\uDEA7", Toast.LENGTH_LONG).show() + } + + refreshButton.setOnClickListener { + Toast.makeText(requireContext(), "TODO \uD83D\uDEA7", Toast.LENGTH_LONG).show() + } + } + } + + private fun FragmentVaccinationListBinding.bindViews(uiState: VaccinationListViewModel.UiState) = with(uiState) { + + adapter.update(listItems) + + val isVaccinationComplete = vaccinationStatus == VaccinatedPerson.Status.COMPLETE + + val background = if (isVaccinationComplete) { + R.drawable.vaccination_compelete_gradient + } else { + R.drawable.vaccination_incomplete + } + + expandedImage.setImageResource(background) + + subtitle.isVisible = isVaccinationComplete + + appBarLayout.onOffsetChange { titleAlpha, subtitleAlpha -> + title.alpha = titleAlpha + subtitle.alpha = subtitleAlpha + } + + setToolbarOverlay(isVaccinationComplete) + } + + private fun setToolbarOverlay(isVaccinationComplete: Boolean) { + + // subtitle is only visible when vaccination is complete + val bottomTextView = if (isVaccinationComplete) binding.subtitle else binding.title + + val deviceWidth = requireContext().resources.displayMetrics.widthPixels + + val params: CoordinatorLayout.LayoutParams = binding.recyclerViewVaccinationList.layoutParams + as (CoordinatorLayout.LayoutParams) + + val textParams = bottomTextView.layoutParams as (LinearLayout.LayoutParams) + + val divider = if (isVaccinationComplete) 2 else 3 + textParams.bottomMargin = (deviceWidth / divider) - 24 /* 24 is space between screen border and Card */ + bottomTextView.requestLayout() + + val behavior: AppBarLayout.ScrollingViewBehavior = params.behavior as (AppBarLayout.ScrollingViewBehavior) + behavior.overlayTop = (deviceWidth / divider) - 24 + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt new file mode 100644 index 000000000..86c2cb094 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListFragmentModule.kt @@ -0,0 +1,19 @@ +package de.rki.coronawarnapp.vaccination.ui.list + +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 VaccinationListFragmentModule { + + @Binds + @IntoMap + @CWAViewModelKey(VaccinationListViewModel::class) + abstract fun vaccinationListFragment( + factory: VaccinationListViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt new file mode 100644 index 000000000..dada5d174 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationListViewModel.kt @@ -0,0 +1,168 @@ +package de.rki.coronawarnapp.vaccination.ui.list + +import android.graphics.Bitmap +import androidx.lifecycle.LiveData +import androidx.lifecycle.asLiveData +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUserTz +import de.rki.coronawarnapp.util.TimeStamper +import de.rki.coronawarnapp.util.ui.SingleLiveEvent +import de.rki.coronawarnapp.util.viewmodel.CWAViewModel +import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory +import de.rki.coronawarnapp.vaccination.core.ProofCertificate +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE +import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate +import de.rki.coronawarnapp.vaccination.core.repository.VaccinationRepository +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListCertificateCardItemVH.VaccinationListCertificateCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH.VaccinationListIncompleteTopCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.transform +import org.joda.time.Days +import org.joda.time.LocalDate + +class VaccinationListViewModel @AssistedInject constructor( + private val vaccinationRepository: VaccinationRepository, + private val timeStamper: TimeStamper, + private val qrCodeGenerator: QrCodeGenerator, + @Assisted private val vaccinatedPersonIdentifier: String +) : CWAViewModel() { + + val events = SingleLiveEvent<Event>() + + val vaccinationInfoFlow = vaccinationRepository.vaccinationInfos.map { vaccinatedPersonSet -> + // TODO: use the line below once the repository returns actual values + // val vaccinatedPerson = vaccinatedPersonSet.single { it.identifier.code == vaccinatedPersonIdentifier } + } + + private val proofQrCode: Flow<Bitmap?> = vaccinationRepository.vaccinationInfos.transform { vaccinationInfos -> + + emit(null) + + // TODO: use actual values from repository instead of these mocked ones + val proofCertificates = setOf( + getMockProofCertificate() + ) + + if (proofCertificates.isNotEmpty()) { + emit(qrCodeGenerator.createQrCode("TODO create qrCode from actual value")) + } + } + + val uiState: LiveData<UiState> = combine(vaccinationInfoFlow, proofQrCode) { vaccinatedPerson, proofQrCode -> + + // For now, use mock data + val vaccinationStatus = COMPLETE + // val vaccinationStatus = COMPLETE + + val vaccinationCertificates = setOf( + getMockVaccinationCertificate(), + getMockVaccinationCertificate().copy( + doseNumber = 2 + ) + ) + + val proofCertificates = setOf( + getMockProofCertificate() + ) + + val listItems = assembleItemList( + vaccinationCertificates = vaccinationCertificates, + proofCertificates = proofCertificates, + firstName = "François-Joan", + lastName = "d'Arsøns - van Halen", + dateOfBirth = LocalDate.parse("2009-02-28"), + vaccinationStatus, + proofQrCode + ) + + UiState( + listItems, + vaccinationStatus = vaccinationStatus + ) + }.catch { + // TODO Error Handling in an upcoming subtask + }.asLiveData() + + // TODO: after using actual values from the repository, we only pass VaccinatedPerson here instead of all these + // arguments + @Suppress("LongParameterList") + private fun assembleItemList( + vaccinationCertificates: Set<VaccinationCertificate>, + proofCertificates: Set<ProofCertificate>, + firstName: String, + lastName: String, + dateOfBirth: LocalDate, + vaccinationStatus: VaccinatedPerson.Status, + proofQrCode: Bitmap? + ) = mutableListOf<VaccinationListItem>().apply { + if (vaccinationStatus == COMPLETE) { + if (proofCertificates.isNotEmpty()) { + + val proofCertificate = proofCertificates.first() + val expiresAt = proofCertificate.expiresAt.toLocalDateUserTz() + val today = timeStamper.nowUTC.toLocalDateUserTz() + val remainingValidityInDays = Days.daysBetween(today, expiresAt).days + + add( + VaccinationListCertificateCardItem( + qrCode = proofQrCode, + remainingValidityInDays = remainingValidityInDays + ) + ) + } + } else { + add(VaccinationListIncompleteTopCardItem) + } + add( + VaccinationListNameCardItem( + fullName = "$firstName $lastName", + dayOfBirth = dateOfBirth.toDayFormat() + ) + ) + vaccinationCertificates.forEach { vaccinationCertificate -> + with(vaccinationCertificate) { + add( + VaccinationListVaccinationCardItem( + vaccinationCertificateId = certificateId, + doseNumber = doseNumber.toString(), + totalSeriesOfDoses = totalSeriesOfDoses.toString(), + vaccinatedAt = vaccinatedAt.toDayFormat(), + vaccinationStatus = vaccinationStatus, + isFinalVaccination = + doseNumber == totalSeriesOfDoses, + onCardClick = { certificateId -> + events.postValue(Event.NavigateToVaccinationCertificateDetails(certificateId)) + } + ) + ) + } + } + }.toList() + + data class UiState( + val listItems: List<VaccinationListItem>, + val vaccinationStatus: VaccinatedPerson.Status + ) + + sealed class Event { + data class NavigateToVaccinationCertificateDetails(val vaccinationCertificateId: String) : Event() + } + + @AssistedFactory + interface Factory : CWAViewModelFactory<VaccinationListViewModel> { + fun create( + vaccinatedPersonIdentifier: String + ): VaccinationListViewModel + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationMockData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationMockData.kt new file mode 100644 index 000000000..b8d84a56c --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/VaccinationMockData.kt @@ -0,0 +1,83 @@ +package de.rki.coronawarnapp.vaccination.ui.list + +import de.rki.coronawarnapp.ui.Country +import de.rki.coronawarnapp.vaccination.core.ProofCertificate +import de.rki.coronawarnapp.vaccination.core.VaccinatedPersonIdentifier +import de.rki.coronawarnapp.vaccination.core.VaccinationCertificate +import org.joda.time.Duration +import org.joda.time.Instant +import org.joda.time.LocalDate + +/** + * Mock Data needed for UI development while backend connection is not yet available + * Can be removed later + */ +internal fun getMockVaccinationCertificate() = MockVaccinationCertificate( + firstName = "François-Joan", + lastName = "FRANCOIS<JOAN", + dateOfBirth = LocalDate.parse("2009-02-28"), + vaccinatedAt = LocalDate.parse("2021-04-22"), + vaccineName = "vaccineName", + vaccineManufacturer = "vaccineManufactorer", + medicalProductName = "medicalProductName", + doseNumber = 1, + totalSeriesOfDoses = 2, + certificateIssuer = "certificateIssuer", + certificateCountry = Country.AT, + certificateId = "certificate Id", + personIdentifier = getPersonIdentifier() +) + +internal fun getMockProofCertificate() = MockProofCertificate( + personIdentifier = getPersonIdentifier(), + expiresAt = Instant.now().plus(Duration.standardDays(3)), + firstName = "François-Joan", + lastName = "FRANCOIS<JOAN", + dateOfBirth = LocalDate.parse("2009-02-28"), + vaccinatedAt = LocalDate.parse("2021-04-22"), + vaccineName = "vaccineName", + vaccineManufacturer = "vaccineManufactorer", + medicalProductName = "medicalProductName", + doseNumber = 1, + totalSeriesOfDoses = 2, + certificateIssuer = "certificateIssuer", + certificateId = "certificate Id" +) + +fun getPersonIdentifier() = VaccinatedPersonIdentifier( + dateOfBirth = LocalDate.parse("2009-02-28"), + lastNameStandardized = "DARSONS<VAN<HALEN", + firstNameStandardized = "FRANCOIS<JOAN" +) + +internal data class MockProofCertificate( + override val personIdentifier: VaccinatedPersonIdentifier, + override val expiresAt: Instant, + override val firstName: String?, + override val lastName: String, + override val dateOfBirth: LocalDate, + override val vaccineName: String, + override val medicalProductName: String, + override val vaccineManufacturer: String, + override val doseNumber: Int, + override val totalSeriesOfDoses: Int, + override val vaccinatedAt: LocalDate, + override val certificateIssuer: String, + override val certificateId: String +) : ProofCertificate + +internal data class MockVaccinationCertificate( + override val firstName: String?, + override val lastName: String, + override val dateOfBirth: LocalDate, + override val vaccinatedAt: LocalDate, + override val vaccineName: String, + override val vaccineManufacturer: String, + override val medicalProductName: String, + override val doseNumber: Int, + override val totalSeriesOfDoses: Int, + override val certificateIssuer: String, + override val certificateCountry: Country, + override val certificateId: String, + override val personIdentifier: VaccinatedPersonIdentifier +) : VaccinationCertificate diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt new file mode 100644 index 000000000..e152edbe9 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/VaccinationListAdapter.kt @@ -0,0 +1,60 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter + +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.viewbinding.ViewBinding +import de.rki.coronawarnapp.util.lists.BindableVH +import de.rki.coronawarnapp.util.lists.HasStableId +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.list.adapter.viewholder.VaccinationListCertificateCardItemVH +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListCertificateCardItemVH.VaccinationListCertificateCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH.VaccinationListIncompleteTopCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem + +class VaccinationListAdapter : + ModularAdapter<VaccinationListAdapter.ItemVH<VaccinationListItem, ViewBinding>>(), + AsyncDiffUtilAdapter<VaccinationListItem> { + + override val asyncDiffer: AsyncDiffer<VaccinationListItem> = AsyncDiffer(adapter = this) + + init { + modules.addAll( + listOf( + StableIdMod(data), + DataBinderMod<VaccinationListItem, ItemVH<VaccinationListItem, ViewBinding>>(data), + TypedVHCreatorMod({ data[it] is VaccinationListIncompleteTopCardItem }) { + VaccinationListIncompleteTopCardItemVH(it) + }, + TypedVHCreatorMod({ data[it] is VaccinationListNameCardItem }) { + VaccinationListNameCardItemVH(it) + }, + TypedVHCreatorMod({ data[it] is VaccinationListVaccinationCardItem }) { + VaccinationListVaccinationCardItemVH(it) + }, + TypedVHCreatorMod({ data[it] is VaccinationListCertificateCardItem }) { + VaccinationListCertificateCardItemVH(it) + } + ) + ) + } + + override fun getItemCount(): Int { + return data.size + } + + abstract class ItemVH<Item : VaccinationListItem, VB : ViewBinding>( + @LayoutRes layoutRes: Int, + parent: ViewGroup + ) : ModularAdapter.VH(layoutRes, parent), BindableVH<Item, VB> +} + +interface VaccinationListItem : HasStableId diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt new file mode 100644 index 000000000..2a67a41e4 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListCertificateCardItemVH.kt @@ -0,0 +1,43 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder + +import android.graphics.Bitmap +import android.view.ViewGroup +import androidx.core.view.isVisible +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationListCertificateCardBinding +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListCertificateCardItemVH.VaccinationListCertificateCardItem + +class VaccinationListCertificateCardItemVH(parent: ViewGroup) : + VaccinationListAdapter.ItemVH<VaccinationListCertificateCardItem, VaccinationListCertificateCardBinding>( + layoutRes = R.layout.vaccination_list_certificate_card, + parent = parent + ) { + + override val viewBinding: Lazy<VaccinationListCertificateCardBinding> = lazy { + VaccinationListCertificateCardBinding.bind(itemView) + } + + override val onBindData: VaccinationListCertificateCardBinding + .(item: VaccinationListCertificateCardItem, payloads: List<Any>) -> Unit = + { item, _ -> + when (item.qrCode) { + null -> progressBar.isVisible = true + else -> { + qrCodeImage.setImageBitmap(item.qrCode) + progressBar.isVisible = false + } + } + certificateCardSubtitle.text = + context.getString(R.string.vaccination_list_certificate_card_subtitle, item.remainingValidityInDays) + } + + data class VaccinationListCertificateCardItem( + val qrCode: Bitmap?, + val remainingValidityInDays: Int + ) : + VaccinationListItem { + override val stableId = this.hashCode().toLong() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt new file mode 100644 index 000000000..dd9ec7bba --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListIncompleteTopCardItemVH.kt @@ -0,0 +1,27 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationListIncompleteTopCardBinding +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListIncompleteTopCardItemVH.VaccinationListIncompleteTopCardItem + +class VaccinationListIncompleteTopCardItemVH(parent: ViewGroup) : + VaccinationListAdapter.ItemVH<VaccinationListIncompleteTopCardItem, VaccinationListIncompleteTopCardBinding>( + layoutRes = R.layout.vaccination_list_incomplete_top_card, + parent = parent + ) { + + override val viewBinding: Lazy<VaccinationListIncompleteTopCardBinding> = lazy { + VaccinationListIncompleteTopCardBinding.bind(itemView) + } + + override val onBindData: VaccinationListIncompleteTopCardBinding + .(item: VaccinationListIncompleteTopCardItem, payloads: List<Any>) -> Unit = { _, _ -> // NOOP + } + + object VaccinationListIncompleteTopCardItem : VaccinationListItem { + override val stableId = this.hashCode().toLong() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt new file mode 100644 index 000000000..5cd1501ca --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListNameCardItemVH.kt @@ -0,0 +1,33 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationListNameCardBinding +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListNameCardItemVH.VaccinationListNameCardItem + +class VaccinationListNameCardItemVH(parent: ViewGroup) : + VaccinationListAdapter.ItemVH<VaccinationListNameCardItem, VaccinationListNameCardBinding>( + layoutRes = R.layout.vaccination_list_name_card, + parent = parent + ) { + + override val viewBinding: Lazy<VaccinationListNameCardBinding> = lazy { + VaccinationListNameCardBinding.bind(itemView) + } + + override val onBindData: VaccinationListNameCardBinding + .(item: VaccinationListNameCardItem, payloads: List<Any>) -> Unit = + { item, _ -> + nameCardTitle.text = item.fullName + nameCardSubtitle.text = context.getString( + R.string.vaccination_list_name_card_subtitle, + item.dayOfBirth + ) + } + + data class VaccinationListNameCardItem(val fullName: String, val dayOfBirth: String) : VaccinationListItem { + override val stableId = this.hashCode().toLong() + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt new file mode 100644 index 000000000..340a86e7a --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/ui/list/adapter/viewholder/VaccinationListVaccinationCardItemVH.kt @@ -0,0 +1,111 @@ +package de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder + +import android.view.ViewGroup +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.VaccinationListVaccinationCardBinding +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.COMPLETE +import de.rki.coronawarnapp.vaccination.core.VaccinatedPerson.Status.INCOMPLETE +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListAdapter +import de.rki.coronawarnapp.vaccination.ui.list.adapter.VaccinationListItem +import de.rki.coronawarnapp.vaccination.ui.list.adapter.viewholder.VaccinationListVaccinationCardItemVH.VaccinationListVaccinationCardItem +import java.util.Objects + +class VaccinationListVaccinationCardItemVH( + parent: ViewGroup, +) : + VaccinationListAdapter.ItemVH<VaccinationListVaccinationCardItem, VaccinationListVaccinationCardBinding>( + layoutRes = R.layout.vaccination_list_vaccination_card, + parent = parent + ) { + + override val viewBinding: Lazy<VaccinationListVaccinationCardBinding> = lazy { + VaccinationListVaccinationCardBinding.bind(itemView) + } + override val onBindData: + VaccinationListVaccinationCardBinding.(item: VaccinationListVaccinationCardItem, payloads: List<Any>) -> Unit = + { item, _ -> + with(item) { + root.setOnClickListener { + onCardClick.invoke(vaccinationCertificateId) + } + vaccinationCardTitle.text = context.getString( + R.string.vaccination_list_vaccination_card_title, + doseNumber, + totalSeriesOfDoses + ) + vaccinationCardSubtitle.text = context.getString( + R.string.vaccination_list_vaccination_card_subtitle, + vaccinatedAt + ) + + val iconRes = when (item.vaccinationStatus) { + INCOMPLETE -> { + if (isFinalVaccination) { + R.drawable.ic_vaccination_incomplete_final + } else { + R.drawable.ic_vaccination_incomplete + } + } + COMPLETE -> { + if (isFinalVaccination) { + R.drawable.ic_vaccination_complete_final + } else { + R.drawable.ic_vaccination_complete + } + } + } + vaccinationIcon.setImageResource(iconRes) + } + } + + data class VaccinationListVaccinationCardItem( + val vaccinationCertificateId: String, + val doseNumber: String, + val totalSeriesOfDoses: String, + val vaccinatedAt: String, + val vaccinationStatus: VaccinatedPerson.Status, + val isFinalVaccination: Boolean, + val onCardClick: (String) -> Unit + ) : VaccinationListItem { + + override val stableId: Long = Objects.hash( + vaccinationCertificateId, + doseNumber, + totalSeriesOfDoses, + vaccinatedAt, + vaccinationStatus, + isFinalVaccination + ).toLong() + + // Ignore onCardClick Listener in equals() to avoid re-drawing when only the click listener is updated + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as VaccinationListVaccinationCardItem + + if (vaccinationCertificateId != other.vaccinationCertificateId) return false + if (doseNumber != other.doseNumber) return false + if (totalSeriesOfDoses != other.totalSeriesOfDoses) return false + if (vaccinatedAt != other.vaccinatedAt) return false + if (vaccinationStatus != other.vaccinationStatus) return false + if (isFinalVaccination != other.isFinalVaccination) return false + if (stableId != other.stableId) return false + + return true + } + + // Ignore onCardClick Listener in equals() to avoid re-drawing when only the click listener is updated + override fun hashCode(): Int { + var result = vaccinationCertificateId.hashCode() + result = 31 * result + doseNumber.hashCode() + result = 31 * result + totalSeriesOfDoses.hashCode() + result = 31 * result + vaccinatedAt.hashCode() + result = 31 * result + vaccinationStatus.hashCode() + result = 31 * result + isFinalVaccination.hashCode() + result = 31 * result + stableId.hashCode() + return result + } + } +} diff --git a/Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml b/Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml new file mode 100644 index 000000000..40001f61b --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable-night/ic_arrow_right_grey.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="19dp" + android:height="16dp" + android:viewportWidth="19" + android:viewportHeight="16"> + <path + android:pathData="M11.9186,0.7474L10.4286,2.3179L14.9685,7.103H0.9918V9.197H14.9685L10.4286,13.9821L11.9186,15.5525L18.9419,8.15L11.9186,0.7474Z" + android:fillColor="#A7A7A7" + android:fillType="evenOdd"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml b/Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml new file mode 100644 index 000000000..fea245299 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_arrow_right_grey.xml @@ -0,0 +1,11 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="19dp" + android:height="16dp" + android:viewportWidth="19" + android:viewportHeight="16"> + <path + android:pathData="M11.9186,0.7475L10.4286,2.318L14.9685,7.1031H0.9918V9.197H14.9685L10.4286,13.9821L11.9186,15.5526L18.9419,8.15L11.9186,0.7475Z" + android:fillColor="#17191A" + android:fillAlpha="0.6" + android:fillType="evenOdd"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete.xml b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete.xml new file mode 100644 index 000000000..38ca300a8 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete.xml @@ -0,0 +1,47 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="88dp" + android:height="95dp" + android:viewportWidth="88" + android:viewportHeight="95"> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z" + android:fillColor="#FDD207"/> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z"> + <aapt:attr name="android:fillColor"> + <gradient + android:startY="35.3456" + android:startX="-1.95773E-6" + android:endY="57.3292" + android:endX="82.1951" + android:type="linear"> + <item android:offset="0" android:color="#FF0093C8"/> + <item android:offset="1" android:color="#FF007FAD"/> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z" + android:fillColor="#FDD207"/> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z"> + <aapt:attr name="android:fillColor"> + <gradient + android:startY="35.3456" + android:startX="-1.95773E-6" + android:endY="57.3292" + android:endX="82.1951" + android:type="linear"> + <item android:offset="0" android:color="#FF0093C8"/> + <item android:offset="1" android:color="#FF007FAD"/> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M44.6667,21L23,29.125V45.6188C23,59.2958 32.2354,72.0521 44.6667,75.1667C57.0979,72.0521 66.3333,59.2958 66.3333,45.6188V29.125L44.6667,21ZM60.9167,45.6188C60.9167,56.4521 54.0104,66.4729 44.6667,69.5333C35.3229,66.4729 28.4167,56.4792 28.4167,45.6188V32.8896L44.6667,26.7958L60.9167,32.8896V45.6188Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M44.6665,71.0834V26.5834V24.0834L26.1665,32.0834V49.0834L31.1665,63.0834L44.6665,71.0834Z" + android:fillColor="#ffffff"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete_final.xml b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete_final.xml new file mode 100644 index 000000000..81e5a5d1c --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_complete_final.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="88dp" + android:height="95dp" + android:viewportWidth="88" + android:viewportHeight="95"> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z" + android:fillColor="#FDD207"/> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z"> + <aapt:attr name="android:fillColor"> + <gradient + android:startY="35.3456" + android:startX="-1.95773E-6" + android:endY="57.3292" + android:endX="82.1951" + android:type="linear"> + <item android:offset="0" android:color="#FF0093C8"/> + <item android:offset="1" android:color="#FF007FAD"/> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M44.5,21L23,30.8182V45.5455C23,59.1682 32.1733,71.9073 44.5,75C56.8267,71.9073 66,59.1682 66,45.5455V30.8182L44.5,21Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M32.525,46.7909L29,50.2335L39,60L59,40.4671L55.475,37L39,53.0902L32.525,46.7909Z" + android:fillColor="#0186B6"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete.xml b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete.xml new file mode 100644 index 000000000..8a6cdf9e1 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="88dp" + android:height="95dp" + android:viewportWidth="88" + android:viewportHeight="95"> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z" + android:fillColor="#616F7E"/> + <path + android:pathData="M44.6667,21L23,29.125V45.6188C23,59.2958 32.2354,72.0521 44.6667,75.1667C57.0979,72.0521 66.3333,59.2958 66.3333,45.6188V29.125L44.6667,21ZM60.9167,45.6188C60.9167,56.4521 54.0104,66.4729 44.6667,69.5333C35.3229,66.4729 28.4167,56.4792 28.4167,45.6188V32.8896L44.6667,26.7958L60.9167,32.8896V45.6188Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M44.6665,71.0834V26.5834V24.0834L26.1665,32.0834V49.0834L31.1665,63.0834L44.6665,71.0834Z" + android:fillColor="#ffffff"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml new file mode 100644 index 000000000..ea2e7488d --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_vaccination_incomplete_final.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="88dp" + android:height="95dp" + android:viewportWidth="88" + android:viewportHeight="95"> + <path + android:pathData="M0,4C0,1.7909 1.7909,0 4,0H84C86.2091,0 88,1.7909 88,4V91C88,93.2091 86.2091,95 84,95H4C1.7909,95 0,93.2091 0,91V4Z" + android:fillColor="#616F7E"/> + <path + android:pathData="M44.5,21L23,30.8182V45.5455C23,59.1682 32.1733,71.9073 44.5,75C56.8267,71.9073 66,59.1682 66,45.5455V30.8182L44.5,21Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M32.525,46.7909L29,50.2335L39,60L59,40.4671L55.475,37L39,53.0902L32.525,46.7909Z" + android:fillColor="#616F7E"/> +</vector> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml index 63afd133b..544a647db 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_details.xml @@ -108,7 +108,7 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout - style="@style/Card.NoElevation" + style="@style/Card.Vaccination" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="24dp" diff --git a/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml new file mode 100644 index 000000000..ec70295fc --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_vaccination_list.xml @@ -0,0 +1,140 @@ +<?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" + android:id="@+id/content_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/trace_location_gradient_background"> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/coordinator_layout" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_marginBottom="12dp" + android:nestedScrollingEnabled="true" + app:layout_constraintBottom_toTopOf="@id/refresh_button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <com.google.android.material.appbar.AppBarLayout + android:id="@+id/appBarLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.appbar.CollapsingToolbarLayout + android:id="@+id/collapsing_toolbar_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:nestedScrollingEnabled="true" + app:layout_scrollFlags="scroll|exitUntilCollapsed"> + + <ImageView + android:id="@+id/expandedImage" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:importantForAccessibility="no" + app:layout_collapseMode="parallax" + app:srcCompat="@drawable/vaccination_incomplete" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_collapseMode="parallax"> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="80dp" + android:layout_marginBottom="12dp" + android:gravity="center" + android:text="@string/vaccination_list_title" + android:textColor="@android:color/white" + android:textSize="20sp" + android:textStyle="bold"/> + + <TextView + android:id="@+id/subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginHorizontal="24dp" + android:gravity="center" + android:text="@string/vaccination_list_complete_vaccination_subtitle" + android:textColor="@android:color/white" + android:textSize="18sp" + android:visibility="visible"/> + + </LinearLayout> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + app:layout_collapseMode="pin" + app:layout_scrollFlags="scroll|enterAlways" + app:navigationIcon="@drawable/ic_close_white" + app:titleTextColor="@color/colorAccentTintButton"> + + <LinearLayout + android:id="@+id/header_text_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:orientation="horizontal"> + <ImageView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginEnd="72dp" + android:importantForAccessibility="no" + app:srcCompat="@drawable/ic_cwa_logo_white" /> + </LinearLayout> + + </com.google.android.material.appbar.MaterialToolbar> + + </com.google.android.material.appbar.CollapsingToolbarLayout> + + </com.google.android.material.appbar.AppBarLayout> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_view_vaccination_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + tools:listitem="@layout/vaccination_list_incomplete_top_card" /> + + </androidx.coordinatorlayout.widget.CoordinatorLayout> + + <Button + android:id="@+id/refresh_button" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + android:layout_marginBottom="8dp" + android:text="@string/vaccination_list_refresh_button" + app:layout_constraintBottom_toTopOf="@id/register_new_vaccination_button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent"/> + + <Button + android:id="@+id/register_new_vaccination_button" + style="@style/buttonPrimary" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginEnd="@dimen/spacing_normal" + android:layout_marginBottom="8dp" + android:text="@string/vaccination_list_register_new_vaccination_button" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml new file mode 100644 index 000000000..25aea54b9 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_certificate_card.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + style="@style/Card.Vaccination" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="16dp" + android:padding="0dp" + android:orientation="vertical"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="4dp"> + + <ImageView + android:id="@+id/qrCodeImage" + android:layout_width="0dp" + android:layout_height="0dp" + android:contentDescription="@string/vaccination_list_qr_code_accessibility" + app:layout_constraintDimensionRatio="H,1:1" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:src="@drawable/ic_qrcode" + tools:tint="@android:color/black" /> + + <com.google.android.material.progressindicator.LinearProgressIndicator + android:id="@+id/progress_bar" + android:layout_width="150dp" + android:layout_height="wrap_content" + android:indeterminate="true" + app:hideAnimationBehavior="inward" + app:indicatorColor="@color/colorAccent" + app:layout_constraintBottom_toBottomOf="@id/qrCodeImage" + app:layout_constraintEnd_toEndOf="@id/qrCodeImage" + app:layout_constraintStart_toStartOf="@id/qrCodeImage" + app:layout_constraintTop_toTopOf="@id/qrCodeImage" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <TextView + android:id="@+id/certificate_card_title" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="16dp" + android:textSize="18sp" + android:textStyle="bold" + android:text="@string/vaccination_list_certificate_card_title" /> + + <TextView + android:id="@+id/certificate_card_subtitle" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:layout_marginBottom="16dp" + android:layout_marginHorizontal="16dp" + tools:text="Noch 3 Tage gültig" /> + +</LinearLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml new file mode 100644 index 000000000..b5238b92d --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_incomplete_top_card.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/Card.Vaccination" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="16dp" + android:orientation="vertical" + android:paddingHorizontal="16dp" + android:paddingTop="24dp" + android:paddingBottom="12dp"> + + <TextView + android:id="@+id/top_card_title" + style="@style/headline4Bold" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/vaccination_list_top_card_title" + android:textSize="30sp"/> + + <TextView + android:id="@+id/top_card_subtitle" + style="@style/body2Medium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:text="@string/vaccination_list_top_card_subtitle" + android:textSize="18sp" /> + +</LinearLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_name_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_name_card.xml new file mode 100644 index 000000000..a749f7d47 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_name_card.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + style="@style/Card.Vaccination" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="8dp" + android:orientation="vertical" + android:padding="16dp"> + + <TextView + android:id="@+id/name_card_title" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:textStyle="bold" + tools:text="Andrea Schneider" /> + + <TextView + android:id="@+id/name_card_subtitle" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + tools:text="geboren am 18.04.1943" /> + +</LinearLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml new file mode 100644 index 000000000..2078b26bd --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/vaccination_list_vaccination_card.xml @@ -0,0 +1,55 @@ +<?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" + android:id="@+id/vaccination_card" + style="@style/Card.Vaccination.Ripple" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="8dp" + android:padding="16dp"> + + <ImageView + android:id="@+id/vaccination_icon" + android:layout_width="88dp" + android:layout_height="95dp" + android:importantForAccessibility="no" + app:srcCompat="@drawable/ic_vaccination_incomplete" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/vaccination_card_title" + style="@style/body2" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:text="@string/vaccination_list_vaccination_card_title" + android:textSize="18sp" + android:textStyle="bold" + app:layout_constraintEnd_toStartOf="@id/arrow_right" + app:layout_constraintStart_toEndOf="@id/vaccination_icon" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/vaccination_card_subtitle" + style="@style/body2Medium" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="4dp" + android:text="@string/vaccination_list_vaccination_card_subtitle" + app:layout_constraintEnd_toStartOf="@id/arrow_right" + app:layout_constraintStart_toEndOf="@id/vaccination_icon" + app:layout_constraintTop_toBottomOf="@id/vaccination_card_title" /> + + <ImageView + android:id="@+id/arrow_right" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:importantForAccessibility="no" + app:srcCompat="@drawable/ic_arrow_right_grey" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml index f6f5b0450..d446e1d2d 100644 --- a/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/vaccination_nav_graph.xml @@ -5,6 +5,19 @@ android:id="@+id/vaccination_nav_graph" app:startDestination="@id/vaccinationDetailsFragment"> + <fragment + android:id="@+id/vaccinationListFragment" + android:name="de.rki.coronawarnapp.vaccination.ui.list.VaccinationListFragment" + android:label="fragment_vaccination_list" + tools:layout="@layout/fragment_vaccination_list"> + <argument + android:name="vaccinatedPersonId" + app:argType="string" /> + <action + android:id="@+id/action_vaccinationListFragment_to_vaccinationDetailsFragment" + app:destination="@id/vaccinationDetailsFragment" /> + </fragment> + <fragment android:id="@+id/vaccinationDetailsFragment" android:name="de.rki.coronawarnapp.vaccination.ui.details.VaccinationDetailsFragment" diff --git a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml index a84d67249..509205f64 100644 --- a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml @@ -28,4 +28,29 @@ <string name="vaccination_details_deletion_dialog_positive_button">Entfernen</string> <!-- XBUT: Vaccination Details deletion dialog negative button--> <string name="vaccination_details_deletion_dialog_negative_button">Abbrechen</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">Digitaler Impfnachweis</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">SARS-CoV-2-Impfschutz</string> + <!-- XTXT: Vaccination List top card title--> + <string name="vaccination_list_top_card_title">SARS-CoV-2 Impfung</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_top_card_subtitle">Unvollständiger Impfschutz</string> + <!-- XTXT: Vaccination List name card subtitle--> + <string name="vaccination_list_name_card_subtitle">geboren %1$s</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">Impfung %1$s von %2$s</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">durchgeführt am %1$s</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_certificate_card_title">COVID-19-Prüfzertifikat</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_certificate_card_subtitle">Noch %1$d Tage gültig</string> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">Weitere Impfung registrieren</string> + <!-- XBUT: Vaccination List refresh button --> + <string name="vaccination_list_refresh_button">Aktualisieren</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">Qr-Code</string> </resources> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/values-night/colors.xml b/Corona-Warn-App/src/main/res/values-night/colors.xml index 98ab8628d..9f357cf9d 100644 --- a/Corona-Warn-App/src/main/res/values-night/colors.xml +++ b/Corona-Warn-App/src/main/res/values-night/colors.xml @@ -77,4 +77,8 @@ <!-- QR Code Scan --> <color name="colorQrCodeScanToolbar">#FFFFFF</color> <color name="colorQrCodeScanMask">#BF000000</color> + + <!-- Vaccination --> + <color name="colorVaccinationCardBackground">#434445</color> + </resources> diff --git a/Corona-Warn-App/src/main/res/values/colors.xml b/Corona-Warn-App/src/main/res/values/colors.xml index 0c537ee78..0e27295b4 100644 --- a/Corona-Warn-App/src/main/res/values/colors.xml +++ b/Corona-Warn-App/src/main/res/values/colors.xml @@ -98,7 +98,6 @@ <color name="colorTraceLocationGradientBackground">#F5F5F5</color> <color name="colorTraceLocationButtonTextColor">#F5F5F5</color> - <!-- QR Code Scan --> <color name="colorQrCodeScanToolbar">#000000</color> <color name="colorQrCodeScanMask">#BFFFFFFF</color> @@ -106,5 +105,8 @@ <!-- Swipe to delete background color --> <color name="swipeDeleteBackgroundColor">#EB4D3D</color> + <!-- Vaccination --> + <color name="colorVaccinationCardBackground">#FFFFFF</color> + <color name="whiteAlpha60">#99FFFFFF</color> </resources> diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index 5d15c3486..3923b66d0 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -237,6 +237,13 @@ <item name="android:elevation">@dimen/elevation_none</item> </style> + <style name="Card.Vaccination" parent="Card.NoElevation"> + <item name="android:backgroundTint">@color/colorVaccinationCardBackground</item> + </style> + + <style name="Card.Vaccination.Ripple"> + <item name="android:background">@drawable/grey_card_ripple</item> + </style> <style name="Card.NoPadding"> <item name="android:padding">@dimen/no_padding</item> diff --git a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml index 63c692c41..19d6084dc 100644 --- a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml +++ b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml @@ -28,4 +28,29 @@ <string name="vaccination_details_deletion_dialog_positive_button">Entfernen</string> <!-- XBUT: Vaccination Details deletion dialog negative button--> <string name="vaccination_details_deletion_dialog_negative_button">Abbrechen</string> + + <!-- XTXT: Vaccination List title--> + <string name="vaccination_list_title">Digitaler Impfnachweis</string> + <!-- XTXT: Vaccination List complete vaccination subtitle--> + <string name="vaccination_list_complete_vaccination_subtitle">SARS-CoV-2-Impfschutz</string> + <!-- XTXT: Vaccination List top card title--> + <string name="vaccination_list_top_card_title">SARS-CoV-2 Impfung</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_top_card_subtitle">Unvollständiger Impfschutz</string> + <!-- XTXT: Vaccination List name card subtitle--> + <string name="vaccination_list_name_card_subtitle">geboren %1$s</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_title">Impfung %1$s von %2$s</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_vaccination_card_subtitle">durchgeführt am %1$s</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_certificate_card_title">COVID-19-Prüfzertifikat</string> + <!-- XTXT: Vaccination List top card subtitle--> + <string name="vaccination_list_certificate_card_subtitle">Noch %1$d Tage gültig</string> + <!-- XBUT: Vaccination List register additional vaccination button --> + <string name="vaccination_list_register_new_vaccination_button">Weitere Impfung registrieren</string> + <!-- XBUT: Vaccination List refresh button --> + <string name="vaccination_list_refresh_button">Aktualisieren</string> + <!-- XACT: Vaccination List Qr-Code for screen readers --> + <string name="vaccination_list_qr_code_accessibility">Qr-Code</string> </resources> \ No newline at end of file -- GitLab