Skip to content
Snippets Groups Projects
Unverified Commit dcefa6cb authored by axelherbstreith's avatar axelherbstreith Committed by GitHub
Browse files

DGC Detail Screen (EXPOSUREAPP-7478) (#3345)


* added menu

* removed static menu string

* added deletion message

* recentered title icon

* fixed menu icon onclick

* linting

* add code to fullscreen qr code

* linting

* Renaming - refactoring

* Renaming

* More renaming

* Dummy Qr code

* Pass args + connect to repo

* Small chunks

* Update translation_v2.json

* Bind data

* Add to covid certificate graph

* Generate Qr Code

* Certificate card subtitle

* Use sampleCollectedAt

* Unify date formatting and fix typo

* wiring

* removed from test nav graph

* lint

* lint

* lint 2

* fix crash

Co-authored-by: default avatarMohamed Metwalli <mohamed.metwalli@sap.com>
parent 6adc6bf4
No related branches found
No related tags found
No related merge requests found
Showing
with 323 additions and 199 deletions
...@@ -8,7 +8,6 @@ import de.rki.coronawarnapp.R ...@@ -8,7 +8,6 @@ import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestGreenCertificateBinding import de.rki.coronawarnapp.databinding.FragmentTestGreenCertificateBinding
import de.rki.coronawarnapp.test.menu.ui.TestMenuItem import de.rki.coronawarnapp.test.menu.ui.TestMenuItem
import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.ui.doNavigate
import de.rki.coronawarnapp.util.ui.viewBinding import de.rki.coronawarnapp.util.ui.viewBinding
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
...@@ -23,15 +22,6 @@ class GreenCertificateTestFragment : Fragment(R.layout.fragment_test_green_certi ...@@ -23,15 +22,6 @@ class GreenCertificateTestFragment : Fragment(R.layout.fragment_test_green_certi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.apply {
detailsScreen.setOnClickListener {
doNavigate(
GreenCertificateTestFragmentDirections
.actionGreenCertificateTestFragmentToGreenCertificateDetailsFragment()
)
}
}
} }
companion object { companion object {
......
...@@ -17,11 +17,5 @@ ...@@ -17,11 +17,5 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Request DCC screen" /> android:text="Request DCC screen" />
<com.google.android.material.button.MaterialButton
android:id="@+id/details_screen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Details screen" />
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
...@@ -194,14 +194,6 @@ ...@@ -194,14 +194,6 @@
android:name="de.rki.coronawarnapp.test.greencertificate.GreenCertificateTestFragment" android:name="de.rki.coronawarnapp.test.greencertificate.GreenCertificateTestFragment"
android:label="GreenCertificateTestFragment" android:label="GreenCertificateTestFragment"
tools:layout="@layout/fragment_test_green_certificate" > tools:layout="@layout/fragment_test_green_certificate" >
<action
android:id="@+id/action_greenCertificateTestFragment_to_greenCertificateDetailsFragment"
app:destination="@id/greenCertificateDetailsFragment" />
</fragment> </fragment>
<fragment
android:id="@+id/greenCertificateDetailsFragment"
android:name="de.rki.coronawarnapp.greencertificate.ui.certificates.details.GreenCertificateDetailsFragment"
android:label="GreenCertificateDetailsFragment"
tools:layout="@layout/fragment_greencertificate_details" />
</navigation> </navigation>
...@@ -4,15 +4,15 @@ import dagger.Module ...@@ -4,15 +4,15 @@ import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragment import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragment
import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragmentModule import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragmentModule
import de.rki.coronawarnapp.greencertificate.ui.certificates.details.GreenCertificateDetailsFragment import de.rki.coronawarnapp.greencertificate.ui.certificates.details.CovidCertificateDetailsFragment
import de.rki.coronawarnapp.greencertificate.ui.certificates.details.GreenCertificateDetailsModule import de.rki.coronawarnapp.greencertificate.ui.certificates.details.CovidCertificateDetailsModule
@Module @Module
abstract class GreenCertificateUIModule { abstract class CovidCertificateUIModule {
@ContributesAndroidInjector(modules = [CertificatesFragmentModule::class]) @ContributesAndroidInjector(modules = [CertificatesFragmentModule::class])
abstract fun certificatesFragment(): CertificatesFragment abstract fun certificatesFragment(): CertificatesFragment
@ContributesAndroidInjector(modules = [GreenCertificateDetailsModule::class]) @ContributesAndroidInjector(modules = [CovidCertificateDetailsModule::class])
abstract fun certificateDetailsFragment(): GreenCertificateDetailsFragment abstract fun certificateDetailsFragment(): CovidCertificateDetailsFragment
} }
...@@ -47,6 +47,12 @@ class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInjec ...@@ -47,6 +47,12 @@ class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInjec
findNestedGraph(R.id.vaccination_nav_graph).startDestination = R.id.vaccinationQrCodeScanFragment findNestedGraph(R.id.vaccination_nav_graph).startDestination = R.id.vaccinationQrCodeScanFragment
doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToVaccinationNavGraph()) doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToVaccinationNavGraph())
} }
is CertificatesFragmentEvents.GoToCovidCertificateDetailScreen -> {
doNavigate(
CertificatesFragmentDirections
.actionCertificatesFragmentToCovidCertificateDetailsFragment(event.identifier)
)
}
} }
} }
} }
......
...@@ -5,4 +5,6 @@ sealed class CertificatesFragmentEvents { ...@@ -5,4 +5,6 @@ sealed class CertificatesFragmentEvents {
data class OpenVaccinationRegistrationGraph(val registrationAcknowledged: Boolean) : CertificatesFragmentEvents() data class OpenVaccinationRegistrationGraph(val registrationAcknowledged: Boolean) : CertificatesFragmentEvents()
data class GoToVaccinationList(val personIdentifierCodeSha256: String) : CertificatesFragmentEvents() data class GoToVaccinationList(val personIdentifierCodeSha256: String) : CertificatesFragmentEvents()
data class GoToCovidCertificateDetailScreen(val identifier: String) : CertificatesFragmentEvents()
} }
...@@ -106,7 +106,14 @@ class CertificatesViewModel @AssistedInject constructor( ...@@ -106,7 +106,14 @@ class CertificatesViewModel @AssistedInject constructor(
testDate = certificate.registeredAt, testDate = certificate.registeredAt,
testPerson = testPerson =
certificate.toTestCertificate(null)?.firstName + " " + certificate.toTestCertificate(null)?.firstName + " " +
certificate.toTestCertificate(null)?.lastName certificate.toTestCertificate(null)?.lastName,
onClickAction = {
events.postValue(
CertificatesFragmentEvents.GoToCovidCertificateDetailScreen(
certificate.identifier
)
)
}
) )
) )
} }
......
...@@ -4,9 +4,10 @@ import android.view.ViewGroup ...@@ -4,9 +4,10 @@ import android.view.ViewGroup
import de.rki.coronawarnapp.R import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.CovidTestSuccessCardBinding import de.rki.coronawarnapp.databinding.CovidTestSuccessCardBinding
import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortTimeFormat
import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
import org.joda.time.Instant import org.joda.time.Instant
import org.joda.time.format.DateTimeFormat
class CovidTestCertificateCard(parent: ViewGroup) : class CovidTestCertificateCard(parent: ViewGroup) :
CertificatesAdapter.CertificatesItemVH<CovidTestCertificateCard.Item, CovidTestSuccessCardBinding>( CertificatesAdapter.CertificatesItemVH<CovidTestCertificateCard.Item, CovidTestSuccessCardBinding>(
...@@ -23,14 +24,10 @@ class CovidTestCertificateCard(parent: ViewGroup) : ...@@ -23,14 +24,10 @@ class CovidTestCertificateCard(parent: ViewGroup) :
payloads: List<Any> payloads: List<Any>
) -> Unit = { item, _ -> ) -> Unit = { item, _ ->
val dateTime = item.testDate.toDateTime()
val dateFormat = DateTimeFormat.shortDate()
val timeFormat = DateTimeFormat.shortTime()
testTime.text = context.getString( testTime.text = context.getString(
R.string.test_certificate_time, R.string.test_certificate_time,
dateTime.toString(dateFormat), item.testDate.toShortDayFormat(),
dateTime.toString(timeFormat), item.testDate.toShortTimeFormat(),
) )
personName.text = item.testPerson personName.text = item.testPerson
...@@ -39,6 +36,7 @@ class CovidTestCertificateCard(parent: ViewGroup) : ...@@ -39,6 +36,7 @@ class CovidTestCertificateCard(parent: ViewGroup) :
data class Item( data class Item(
override val testDate: Instant, override val testDate: Instant,
val testPerson: String, val testPerson: String,
val onClickAction: (Item) -> Unit,
) : CovidCertificateTestItem, HasPayloadDiffer { ) : CovidCertificateTestItem, HasPayloadDiffer {
override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null override fun diffPayload(old: Any, new: Any): Any? = if (old::class == new::class) new else null
} }
......
...@@ -4,9 +4,10 @@ import android.view.ViewGroup ...@@ -4,9 +4,10 @@ import android.view.ViewGroup
import de.rki.coronawarnapp.R import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.CovidTestErrorCardBinding import de.rki.coronawarnapp.databinding.CovidTestErrorCardBinding
import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter import de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesAdapter
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortTimeFormat
import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer import de.rki.coronawarnapp.util.lists.diffutil.HasPayloadDiffer
import org.joda.time.Instant import org.joda.time.Instant
import org.joda.time.format.DateTimeFormat
class CovidTestCertificateErrorCard(parent: ViewGroup) : class CovidTestCertificateErrorCard(parent: ViewGroup) :
CertificatesAdapter.CertificatesItemVH<CovidTestCertificateErrorCard.Item, CovidTestErrorCardBinding>( CertificatesAdapter.CertificatesItemVH<CovidTestCertificateErrorCard.Item, CovidTestErrorCardBinding>(
...@@ -23,14 +24,10 @@ class CovidTestCertificateErrorCard(parent: ViewGroup) : ...@@ -23,14 +24,10 @@ class CovidTestCertificateErrorCard(parent: ViewGroup) :
payloads: List<Any> payloads: List<Any>
) -> Unit = { item, _ -> ) -> Unit = { item, _ ->
val dateTime = item.testDate.toDateTime()
val dateFormat = DateTimeFormat.shortDate()
val timeFormat = DateTimeFormat.shortTime()
testTime.text = context.getString( testTime.text = context.getString(
R.string.test_certificate_time, R.string.test_certificate_time,
dateTime.toString(dateFormat), item.testDate.toShortDayFormat(),
dateTime.toString(timeFormat), item.testDate.toShortTimeFormat(),
) )
retryButton.setOnClickListener { item.onClickAction(item) } retryButton.setOnClickListener { item.onClickAction(item) }
......
package de.rki.coronawarnapp.greencertificate.ui.certificates.details
import android.graphics.Bitmap
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.google.android.material.appbar.AppBarLayout
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
import de.rki.coronawarnapp.covidcertificate.test.TestCertificate
import de.rki.coronawarnapp.databinding.FragmentCovidCertificateDetailsBinding
import de.rki.coronawarnapp.ui.qrcode.fullscreen.QrCodeFullScreenFragmentArgs
import de.rki.coronawarnapp.ui.view.onOffsetChange
import de.rki.coronawarnapp.util.DialogHelper
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toDayFormat
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortDayFormat
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toShortTimeFormat
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.setUrl
import de.rki.coronawarnapp.util.ui.popBackStack
import de.rki.coronawarnapp.util.ui.viewBinding
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModelsAssisted
import javax.inject.Inject
class CovidCertificateDetailsFragment : Fragment(R.layout.fragment_covid_certificate_details), AutoInject {
@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val binding by viewBinding<FragmentCovidCertificateDetailsBinding>()
private val args by navArgs<CovidCertificateDetailsFragmentArgs>()
private val viewModel: CovidCertificateDetailsViewModel by cwaViewModelsAssisted(
factoryProducer = { viewModelFactory },
constructorCall = { factory, _ ->
factory as CovidCertificateDetailsViewModel.Factory
factory.create(
testCertificateIdentifier = args.testCertificateIdentifier
)
}
)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) {
qrCodeCard.title.setText(R.string.detail_green_certificate_card_title)
appBarLayout.onOffsetChange { titleAlpha, subtitleAlpha ->
title.alpha = titleAlpha
subtitle.alpha = subtitleAlpha
}
bindTravelNoticeViews()
bindToolbar()
setToolbarOverlay()
viewModel.qrCode.observe(viewLifecycleOwner) { onQrCodeReady(it) }
viewModel.errors.observe(viewLifecycleOwner) { onError(it) }
viewModel.events.observe(viewLifecycleOwner) { onNavEvent(it) }
viewModel.covidCertificate.observe(viewLifecycleOwner) { it?.let { onCertificateReady(it) } }
}
private fun FragmentCovidCertificateDetailsBinding.onCertificateReady(
testCertificate: TestCertificate
) {
qrCodeCard.subtitle.text = getString(
R.string.detail_green_certificate_card_subtitle,
testCertificate.sampleCollectedAt.toShortDayFormat(),
testCertificate.sampleCollectedAt.toShortTimeFormat(),
)
name.text = testCertificate.run { "$firstName $lastName" }
birthDate.text = testCertificate.dateOfBirth.toDayFormat()
diseaseType.text = testCertificate.targetName
testType.text = testCertificate.testType
testName.text = testCertificate.testName
testManufacturer.text = testCertificate.testNameAndManufactor
testDate.text = "%s %s".format(
testCertificate.sampleCollectedAt.toShortDayFormat(),
testCertificate.sampleCollectedAt.toShortTimeFormat()
)
testResult.text = testCertificate.testResult
testCenter.text = testCertificate.testCenter
certificateCountry.text = testCertificate.certificateCountry
certificateIssuer.text = testCertificate.certificateIssuer
certificateId.text = testCertificate.certificateId
}
private fun FragmentCovidCertificateDetailsBinding.onQrCodeReady(bitmap: Bitmap?) {
qrCodeCard.apply {
image.setImageBitmap(bitmap)
progressBar.hide()
bitmap?.let { image.setOnClickListener { viewModel.openFullScreen() } }
}
}
private fun FragmentCovidCertificateDetailsBinding.onError(error: Throwable) {
qrCodeCard.progressBar.hide()
error.toErrorDialogBuilder(requireContext()).show()
}
private fun FragmentCovidCertificateDetailsBinding.onNavEvent(event: CovidCertificateDetailsNavigation) {
when (event) {
CovidCertificateDetailsNavigation.Back -> popBackStack()
is CovidCertificateDetailsNavigation.FullQrCode -> findNavController().navigate(
R.id.action_global_qrCodeFullScreenFragment,
QrCodeFullScreenFragmentArgs(event.qrCodeText).toBundle(),
null,
FragmentNavigatorExtras(qrCodeCard.image to qrCodeCard.image.transitionName)
)
}
}
private fun FragmentCovidCertificateDetailsBinding.bindTravelNoticeViews() {
if (travelNoticeGerman.text ==
getString(R.string.green_certificate_attribute_certificate_travel_notice_german)
) {
travelNoticeGerman.setUrl(
R.string.green_certificate_attribute_certificate_travel_notice_german,
R.string.green_certificate_travel_notice_link_de,
R.string.green_certificate_travel_notice_link_de
)
}
if (travelNoticeEnglish.text ==
getString(R.string.green_certificate_attribute_certificate_travel_notice_english)
) {
travelNoticeEnglish.setUrl(
R.string.green_certificate_attribute_certificate_travel_notice_english,
R.string.green_certificate_travel_notice_link_en,
R.string.green_certificate_travel_notice_link_en
)
}
}
private fun FragmentCovidCertificateDetailsBinding.bindToolbar() = toolbar.apply {
setNavigationOnClickListener { popBackStack() }
setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_covid_certificate_delete -> {
DialogHelper.showDialog(deleteTestConfirmationDialog)
true
}
else -> onOptionsItemSelected(it)
}
}
}
private fun setToolbarOverlay() {
val width = requireContext().resources.displayMetrics.widthPixels
val params: CoordinatorLayout.LayoutParams = binding.scrollView.layoutParams as (CoordinatorLayout.LayoutParams)
val textParams = binding.subtitle.layoutParams as (LinearLayout.LayoutParams)
textParams.bottomMargin = (width / 3) + 170
binding.subtitle.requestLayout()
val behavior: AppBarLayout.ScrollingViewBehavior = params.behavior as (AppBarLayout.ScrollingViewBehavior)
behavior.overlayTop = (width / 3) + 170
}
private val deleteTestConfirmationDialog by lazy {
DialogHelper.DialogInstance(
requireActivity(),
R.string.green_certificate_details_dialog_remove_test_title,
R.string.green_certificate_details_dialog_remove_test_message,
R.string.green_certificate_details_dialog_remove_test_button_positive,
R.string.green_certificate_details_dialog_remove_test_button_negative,
positiveButtonFunction = {
viewModel.onDeleteTestConfirmed()
}
)
}
}
...@@ -8,12 +8,12 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory ...@@ -8,12 +8,12 @@ import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey import de.rki.coronawarnapp.util.viewmodel.CWAViewModelKey
@Module @Module
abstract class GreenCertificateDetailsModule { abstract class CovidCertificateDetailsModule {
@Binds @Binds
@IntoMap @IntoMap
@CWAViewModelKey(GreenCertificateDetailsViewModel::class) @CWAViewModelKey(CovidCertificateDetailsViewModel::class)
abstract fun greenCertificateDetailsFragment( abstract fun greenCertificateDetailsFragment(
factory: GreenCertificateDetailsViewModel.Factory factory: CovidCertificateDetailsViewModel.Factory
): CWAViewModelFactory<out CWAViewModel> ): CWAViewModelFactory<out CWAViewModel>
} }
package de.rki.coronawarnapp.greencertificate.ui.certificates.details package de.rki.coronawarnapp.greencertificate.ui.certificates.details
sealed class GreenCertificateDetailsNavigation { sealed class CovidCertificateDetailsNavigation {
object Back : GreenCertificateDetailsNavigation() object Back : CovidCertificateDetailsNavigation()
data class FullQrCode(val qrCodeText: String) : GreenCertificateDetailsNavigation() data class FullQrCode(val qrCodeText: String) : CovidCertificateDetailsNavigation()
} }
package de.rki.coronawarnapp.greencertificate.ui.certificates.details
import android.graphics.Bitmap
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.coronatest.TestCertificateRepository
import de.rki.coronawarnapp.coronatest.type.TestCertificateIdentifier
import de.rki.coronawarnapp.covidcertificate.test.TestCertificate
import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import kotlinx.coroutines.flow.map
import timber.log.Timber
class CovidCertificateDetailsViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
@Assisted private val testCertificateIdentifier: TestCertificateIdentifier,
private val qrCodeGenerator: QrCodeGenerator,
private val testCertificateRepository: TestCertificateRepository
) : CWAViewModel(dispatcherProvider) {
private var qrCodeText: String? = null
private val bitmapStateData = MutableLiveData<Bitmap>()
val qrCode: LiveData<Bitmap> = bitmapStateData
val events = SingleLiveEvent<CovidCertificateDetailsNavigation>()
val errors = SingleLiveEvent<Throwable>()
val covidCertificate = testCertificateRepository.certificates.map { certificates ->
certificates.find { it.identifier == testCertificateIdentifier }?.toTestCertificate(null)
.also { generateQrCode(it) }
}.asLiveData(dispatcherProvider.Default)
fun onClose() = events.postValue(CovidCertificateDetailsNavigation.Back)
fun openFullScreen() = qrCodeText?.let { events.postValue(CovidCertificateDetailsNavigation.FullQrCode(it)) }
fun onDeleteTestConfirmed() = launch {
Timber.d("Removing Test Certificate=$testCertificateIdentifier")
testCertificateRepository.deleteCertificate(testCertificateIdentifier)
events.postValue(CovidCertificateDetailsNavigation.Back)
}
private fun generateQrCode(testCertificate: TestCertificate?) = launch {
try {
bitmapStateData.postValue(
testCertificate?.let { certificate ->
qrCodeGenerator.createQrCode(certificate.qrCode.also { qrCodeText = it })
}
)
} catch (e: Exception) {
Timber.d(e, "generateQrCode failed for covidCertificate=%s", testCertificateIdentifier)
bitmapStateData.postValue(null)
errors.postValue(e)
}
}
@AssistedFactory
interface Factory : CWAViewModelFactory<CovidCertificateDetailsViewModel> {
fun create(testCertificateIdentifier: TestCertificateIdentifier): CovidCertificateDetailsViewModel
}
}
package de.rki.coronawarnapp.greencertificate.ui.certificates.details
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.Fragment
import com.google.android.material.appbar.AppBarLayout
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentGreencertificateDetailsBinding
import de.rki.coronawarnapp.ui.view.onOffsetChange
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.setUrl
import de.rki.coronawarnapp.util.ui.popBackStack
import de.rki.coronawarnapp.util.ui.viewBinding
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactoryProvider
import de.rki.coronawarnapp.util.viewmodel.cwaViewModels
import javax.inject.Inject
class GreenCertificateDetailsFragment : Fragment(R.layout.fragment_greencertificate_details), AutoInject {
@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
private val binding: FragmentGreencertificateDetailsBinding by viewBinding()
private val viewModel: GreenCertificateDetailsViewModel by cwaViewModels { viewModelFactory }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) =
with(binding) {
toolbar.setNavigationOnClickListener { popBackStack() }
qrCodeCard.title.text = getString(R.string.detail_green_certificate_card_title)
qrCodeCard.subtitle.text = "Test durchgeführt am 12.05.21 18:01" // will be changed
appBarLayout.onOffsetChange { titleAlpha, subtitleAlpha ->
title.alpha = titleAlpha
subtitle.alpha = subtitleAlpha
}
if (travelNoticeGerman.text ==
requireContext().getString(R.string.green_certificate_attribute_certificate_travel_notice_german)
) {
travelNoticeGerman.setUrl(
R.string.green_certificate_attribute_certificate_travel_notice_german,
R.string.green_certificate_travel_notice_link_de,
R.string.green_certificate_travel_notice_link_de
)
}
if (travelNoticeEnglish.text ==
requireContext().getString(R.string.green_certificate_attribute_certificate_travel_notice_english)
) {
travelNoticeEnglish.setUrl(
R.string.green_certificate_attribute_certificate_travel_notice_english,
R.string.green_certificate_travel_notice_link_en,
R.string.green_certificate_travel_notice_link_en
)
}
setToolbarOverlay()
viewModel.qrCode.observe(viewLifecycleOwner) {
qrCodeCard.image.setImageBitmap(it)
it?.let {
qrCodeCard.image.setOnClickListener { viewModel.openFullScreen() }
qrCodeCard.progressBar.hide()
}
}
// TODO: Will in the future be called when the data is loaded from the database
viewModel.generateQrCode()
}
private fun setToolbarOverlay() {
val width = requireContext().resources.displayMetrics.widthPixels
val params: CoordinatorLayout.LayoutParams = binding.scrollView.layoutParams
as (CoordinatorLayout.LayoutParams)
val textParams = binding.subtitle.layoutParams as (LinearLayout.LayoutParams)
textParams.bottomMargin = (width / 3) + 170
binding.subtitle.requestLayout()
val behavior: AppBarLayout.ScrollingViewBehavior = params.behavior as (AppBarLayout.ScrollingViewBehavior)
behavior.overlayTop = (width / 3) + 170
}
}
package de.rki.coronawarnapp.greencertificate.ui.certificates.details
import android.graphics.Bitmap
import androidx.lifecycle.asLiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QrCodeGenerator
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import kotlinx.coroutines.flow.MutableStateFlow
import timber.log.Timber
class GreenCertificateDetailsViewModel @AssistedInject constructor(
private val qrCodeGenerator: QrCodeGenerator,
dispatcherProvider: DispatcherProvider,
) : CWAViewModel(dispatcherProvider) {
private var qrCodeText: String? = null
private val mutableStateFlow = MutableStateFlow<Bitmap?>(null)
val qrCode = mutableStateFlow.asLiveData(dispatcherProvider.Default)
val events = SingleLiveEvent<GreenCertificateDetailsNavigation>()
fun onClose() = events.postValue(GreenCertificateDetailsNavigation.Back)
fun openFullScreen() = qrCodeText?.let { events.postValue(GreenCertificateDetailsNavigation.FullQrCode(it)) }
/* TODO: Adapt to Green Certificate */
fun generateQrCode() = launch {
try {
mutableStateFlow.value = qrCodeGenerator.createQrCode("Sample String")
} catch (e: Exception) {
Timber.d(e, "generateQrCode failed for greenCertificate=%s", "Sample Certificate")
mutableStateFlow.value = null
}
}
@AssistedFactory
interface Factory : SimpleCWAViewModelFactory<GreenCertificateDetailsViewModel>
}
...@@ -5,7 +5,7 @@ import dagger.Module ...@@ -5,7 +5,7 @@ import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap import dagger.multibindings.IntoMap
import de.rki.coronawarnapp.datadonation.analytics.ui.AnalyticsUIModule import de.rki.coronawarnapp.datadonation.analytics.ui.AnalyticsUIModule
import de.rki.coronawarnapp.greencertificate.ui.GreenCertificateUIModule import de.rki.coronawarnapp.greencertificate.ui.CovidCertificateUIModule
import de.rki.coronawarnapp.release.NewReleaseInfoFragment import de.rki.coronawarnapp.release.NewReleaseInfoFragment
import de.rki.coronawarnapp.release.NewReleaseInfoFragmentModule import de.rki.coronawarnapp.release.NewReleaseInfoFragmentModule
import de.rki.coronawarnapp.tracing.ui.details.TracingDetailsFragmentModule import de.rki.coronawarnapp.tracing.ui.details.TracingDetailsFragmentModule
...@@ -42,7 +42,7 @@ import de.rki.coronawarnapp.vaccination.ui.VaccinationUIModule ...@@ -42,7 +42,7 @@ import de.rki.coronawarnapp.vaccination.ui.VaccinationUIModule
PresenceTracingUIModule::class, PresenceTracingUIModule::class,
RATProfileUIModule::class, RATProfileUIModule::class,
VaccinationUIModule::class, VaccinationUIModule::class,
GreenCertificateUIModule::class, CovidCertificateUIModule::class,
] ]
) )
abstract class MainActivityModule { abstract class MainActivityModule {
......
...@@ -25,6 +25,7 @@ object TimeAndDateExtensions { ...@@ -25,6 +25,7 @@ object TimeAndDateExtensions {
private val dayFormatter = DateTimeFormat.forPattern("dd.MM.yyyy") private val dayFormatter = DateTimeFormat.forPattern("dd.MM.yyyy")
private val dayFormatter2DigitYear = DateTimeFormat.forPattern("dd.MM.yy") private val dayFormatter2DigitYear = DateTimeFormat.forPattern("dd.MM.yy")
private val shortTime = DateTimeFormat.shortTime()
fun getCurrentHourUTC(): Int = DateTime(Instant.now(), DateTimeZone.UTC).hourOfDay().get() fun getCurrentHourUTC(): Int = DateTime(Instant.now(), DateTimeZone.UTC).hourOfDay().get()
...@@ -119,6 +120,16 @@ object TimeAndDateExtensions { ...@@ -119,6 +120,16 @@ object TimeAndDateExtensions {
*/ */
fun LocalDate.toDayFormat(): String = toString(dayFormatter) fun LocalDate.toDayFormat(): String = toString(dayFormatter)
/**
* Returns a readable time String with the format "hh:mm" like 12:00 of a LocalDate
*/
fun LocalDate.toShortTimeFormat(): String = toString(shortTime)
/**
* Returns a readable time String with the format "hh:mm" like 12:00 of a LocalDate
*/
fun Instant.toShortTimeFormat(): String = toString(shortTime)
/** /**
* Returns a readable date String with the format "dd.MM.yy" like 23.05.89 of an Instant * Returns a readable date String with the format "dd.MM.yy" like 23.05.89 of an Instant
*/ */
......
...@@ -44,10 +44,10 @@ ...@@ -44,10 +44,10 @@
android:layout_marginTop="90dp" android:layout_marginTop="90dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="12dp"
android:gravity="center" android:gravity="center"
android:text="@string/detail_green_certificate_title"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="20sp" android:textSize="20sp"
android:textStyle="bold" android:textStyle="bold" />
android:text="@string/detail_green_certificate_title"/>
<TextView <TextView
android:id="@+id/subtitle" android:id="@+id/subtitle"
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
android:gravity="center" android:gravity="center"
android:text="@string/detail_green_certificate_test_type" android:text="@string/detail_green_certificate_test_type"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="18sp"/> android:textSize="18sp" />
</LinearLayout> </LinearLayout>
...@@ -67,8 +67,10 @@ ...@@ -67,8 +67,10 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:theme="@style/CWAToolbar.Theme"
app:layout_collapseMode="pin" app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways" app:layout_scrollFlags="scroll|enterAlways"
app:menu="@menu/menu_covid_certificate_detail"
app:navigationIcon="@drawable/ic_back" app:navigationIcon="@drawable/ic_back"
app:navigationIconTint="@android:color/white"> app:navigationIconTint="@android:color/white">
...@@ -82,7 +84,7 @@ ...@@ -82,7 +84,7 @@
<ImageView <ImageView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="72dp" android:layout_marginEnd="32dp"
android:importantForAccessibility="no" android:importantForAccessibility="no"
app:srcCompat="@drawable/ic_cwa_logo_white" /> app:srcCompat="@drawable/ic_cwa_logo_white" />
...@@ -115,7 +117,7 @@ ...@@ -115,7 +117,7 @@
android:layout_marginBottom="6dp" /> android:layout_marginBottom="6dp" />
<LinearLayout <LinearLayout
style="@style/Card.Greencertificate" style="@style/Card.GreenCertificate"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"
...@@ -134,7 +136,6 @@ ...@@ -134,7 +136,6 @@
style="@style/body1" style="@style/body1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Andrea Schneider"
tools:text="Andrea Schneider" /> tools:text="Andrea Schneider" />
<TextView <TextView
...@@ -150,7 +151,6 @@ ...@@ -150,7 +151,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="18.04.1943"
tools:text="18.04.1943" /> tools:text="18.04.1943" />
<TextView <TextView
...@@ -166,7 +166,6 @@ ...@@ -166,7 +166,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="SARS-CoV-2"
tools:text="SARS-CoV-2" /> tools:text="SARS-CoV-2" />
<TextView <TextView
...@@ -182,7 +181,6 @@ ...@@ -182,7 +181,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="Rapid Antigen Test"
tools:text="Rapid Antigen Test" /> tools:text="Rapid Antigen Test" />
<TextView <TextView
...@@ -193,12 +191,11 @@ ...@@ -193,12 +191,11 @@
android:text="@string/green_certificate_attribute_test_name" /> android:text="@string/green_certificate_attribute_test_name" />
<TextView <TextView
android:id="@+id/medical_product_name" android:id="@+id/test_name"
style="@style/body1" style="@style/body1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="Xep"
tools:text="Xep" /> tools:text="Xep" />
<TextView <TextView
...@@ -214,7 +211,6 @@ ...@@ -214,7 +211,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="Xup"
tools:text="Xup" /> tools:text="Xup" />
<TextView <TextView
...@@ -230,7 +226,6 @@ ...@@ -230,7 +226,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="12.05.21 19:00"
tools:text="12.05.21 19:00" /> tools:text="12.05.21 19:00" />
<TextView <TextView
...@@ -246,7 +241,6 @@ ...@@ -246,7 +241,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="negative"
tools:text="negative" /> tools:text="negative" />
<TextView <TextView
...@@ -262,7 +256,6 @@ ...@@ -262,7 +256,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="AB123"
tools:text="AB123" /> tools:text="AB123" />
<TextView <TextView
...@@ -273,12 +266,11 @@ ...@@ -273,12 +266,11 @@
android:text="@string/green_certificate_attribute_state_of_testing" /> android:text="@string/green_certificate_attribute_state_of_testing" />
<TextView <TextView
android:id="@+id/test_country" android:id="@+id/certificate_country"
style="@style/body1" style="@style/body1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="Germany"
tools:text="Germany" /> tools:text="Germany" />
<TextView <TextView
...@@ -294,7 +286,6 @@ ...@@ -294,7 +286,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="G05930482748454836478695764787840"
tools:text="G05930482748454836478695764787840" /> tools:text="G05930482748454836478695764787840" />
...@@ -311,14 +302,13 @@ ...@@ -311,14 +302,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="05930482748454836478695764787840"
tools:text="05930482748454836478695764787840" /> tools:text="05930482748454836478695764787840" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
style="@style/Card.Greencertificate" style="@style/Card.GreenCertificate"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp" android:layout_marginHorizontal="24dp"
...@@ -332,7 +322,7 @@ ...@@ -332,7 +322,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:text="@string/green_certificate_attribute_certificate_travel_notice_german"/> android:text="@string/green_certificate_attribute_certificate_travel_notice_german" />
<TextView <TextView
android:id="@+id/travel_notice_english" android:id="@+id/travel_notice_english"
...@@ -340,7 +330,7 @@ ...@@ -340,7 +330,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:text="@string/green_certificate_attribute_certificate_travel_notice_english"/> android:text="@string/green_certificate_attribute_certificate_travel_notice_english" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
......
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_covid_certificate_delete"
android:title="@string/green_certificate_details_menu_item_delete" />
</menu>
...@@ -9,11 +9,14 @@ ...@@ -9,11 +9,14 @@
android:id="@+id/certificatesFragment" android:id="@+id/certificatesFragment"
android:name="de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragment" android:name="de.rki.coronawarnapp.greencertificate.ui.certificates.CertificatesFragment"
android:label="fragment_certificates" android:label="fragment_certificates"
tools:layout="@layout/fragment_certificates" > tools:layout="@layout/fragment_certificates">
<action <action
android:id="@+id/action_certificatesFragment_to_vaccinationNavGraph" android:id="@+id/action_certificatesFragment_to_vaccinationNavGraph"
app:destination="@id/vaccination_nav_graph" /> app:destination="@id/vaccination_nav_graph" />
<action
android:id="@+id/action_certificatesFragment_to_covidCertificateDetailsFragment"
app:destination="@id/covidCertificateDetailsFragment" />
</fragment> </fragment>
...@@ -21,7 +24,7 @@ ...@@ -21,7 +24,7 @@
android:id="@+id/vaccinationConsentFragment" android:id="@+id/vaccinationConsentFragment"
android:name="de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment" android:name="de.rki.coronawarnapp.vaccination.ui.consent.VaccinationConsentFragment"
android:label="vaccination_consent_fragment" android:label="vaccination_consent_fragment"
tools:layout="@layout/vaccination_consent_fragment" > tools:layout="@layout/vaccination_consent_fragment">
<argument <argument
android:name="showBottomNav" android:name="showBottomNav"
android:defaultValue="true" android:defaultValue="true"
...@@ -42,4 +45,14 @@ ...@@ -42,4 +45,14 @@
android:label="privacyFragment" android:label="privacyFragment"
tools:layout="@layout/fragment_information_privacy" /> tools:layout="@layout/fragment_information_privacy" />
<fragment
android:id="@+id/covidCertificateDetailsFragment"
android:name="de.rki.coronawarnapp.greencertificate.ui.certificates.details.CovidCertificateDetailsFragment"
android:label="CovidCertificateDetailsFragment"
tools:layout="@layout/fragment_covid_certificate_details">
<argument
android:name="testCertificateIdentifier"
app:argType="string" />
</fragment>
</navigation> </navigation>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment