From ffa9c3f1675a6dc525ecdea279b33e25d4131ab1 Mon Sep 17 00:00:00 2001 From: Juraj Kusnier <jurajkusnier@users.noreply.github.com> Date: Fri, 9 Apr 2021 13:47:09 +0200 Subject: [PATCH] Event duplication from QR Code Details (EXPOSUREAPP-6252) (#2780) * Introduce event duplication from QR Code Detail Fragment * move category to NavigateToDuplicateFragment data class * update comment * catch exception from DefaultTraceLocationRepository Co-authored-by: Mohamed <mohamed.metwalli@sap.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> Co-authored-by: I502720 <axel.herbstreith@sap.com> --- .../create/TraceLocationCreateFragment.kt | 5 +- .../organizer/details/QrCodeDetailFragment.kt | 30 +++--- .../details/QrCodeDetailNavigationEvents.kt | 6 +- .../details/QrCodeDetailViewModel.kt | 99 ++++++++----------- .../trace_location_organizer_nav_graph.xml | 3 + 5 files changed, 71 insertions(+), 72 deletions(-) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/create/TraceLocationCreateFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/create/TraceLocationCreateFragment.kt index 69f056711..9fa2a6e40 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/create/TraceLocationCreateFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/create/TraceLocationCreateFragment.kt @@ -47,6 +47,7 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag } ) + @Suppress("NestedBlockDepth") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -121,8 +122,8 @@ class TraceLocationCreateFragment : Fragment(R.layout.trace_location_create_frag placeInputEdit.setText(it.address) } viewModel.apply { - begin = LocalDateTime(it.startDate) - end = LocalDateTime(it.endDate) + begin = it.startDate?.let { time -> LocalDateTime(time) } + end = it.endDate?.let { time -> LocalDateTime(time) } checkInLength = Duration.standardMinutes(it.defaultCheckInLengthInMinutes?.toLong() ?: 0L) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailFragment.kt index 82344e005..82521d81b 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailFragment.kt @@ -79,24 +79,23 @@ class QrCodeDetailFragment : Fragment(R.layout.trace_location_organizer_qr_code_ viewModel.onPrintQrCode() } - root.transitionName = navArgs.traceLocationId.toString() - } - - viewModel.qrCodeBitmap.observe2(this) { - binding.progressBar.hide() - binding.qrCodeImage.apply { - val resourceId = RoundedBitmapDrawableFactory.create(resources, it) - resourceId.cornerRadius = it.width * 0.1f - setImageDrawable(resourceId) + qrCodeCloneButton.setOnClickListener { + viewModel.duplicateTraceLocation() } + + root.transitionName = navArgs.traceLocationId.toString() } viewModel.routeToScreen.observe2(this) { when (it) { QrCodeDetailNavigationEvents.NavigateBack -> popBackStack() - QrCodeDetailNavigationEvents.NavigateToDuplicateFragment -> { /* TODO */ - } + is QrCodeDetailNavigationEvents.NavigateToDuplicateFragment -> doNavigate( + QrCodeDetailFragmentDirections.actionQrCodeDetailFragmentToTraceLocationCreateFragment( + it.category, + it.traceLocation + ) + ) is QrCodeDetailNavigationEvents.NavigateToQrCodePosterFragment -> doNavigate( QrCodeDetailFragmentDirections.actionQrCodeDetailFragmentToQrCodePosterFragment(it.locationId) @@ -134,6 +133,15 @@ class QrCodeDetailFragment : Fragment(R.layout.trace_location_organizer_qr_code_ } else { eventDate.isGone = true } + + uiState.bitmap?.let { + binding.progressBar.hide() + binding.qrCodeImage.apply { + val resourceId = RoundedBitmapDrawableFactory.create(resources, it) + resourceId.cornerRadius = it.width * 0.1f + setImageDrawable(resourceId) + } + } } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailNavigationEvents.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailNavigationEvents.kt index 68027a1fd..1939ed098 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailNavigationEvents.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailNavigationEvents.kt @@ -1,7 +1,11 @@ package de.rki.coronawarnapp.ui.eventregistration.organizer.details +import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.TraceLocationCategory + sealed class QrCodeDetailNavigationEvents { object NavigateBack : QrCodeDetailNavigationEvents() data class NavigateToQrCodePosterFragment(val locationId: Long) : QrCodeDetailNavigationEvents() - object NavigateToDuplicateFragment : QrCodeDetailNavigationEvents() + data class NavigateToDuplicateFragment(val traceLocation: TraceLocation, val category: TraceLocationCategory) : + QrCodeDetailNavigationEvents() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt index 739078b1e..30f3363da 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/details/QrCodeDetailViewModel.kt @@ -3,7 +3,6 @@ package de.rki.coronawarnapp.ui.eventregistration.organizer.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 @@ -12,15 +11,14 @@ import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.eventregistration.storage.repo.DefaultTraceLocationRepository import de.rki.coronawarnapp.exception.ExceptionCategory import de.rki.coronawarnapp.exception.reporting.report +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.traceLocationCategories 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.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filterNotNull import org.joda.time.Instant import timber.log.Timber +import java.lang.Exception class QrCodeDetailViewModel @AssistedInject constructor( @Assisted private val traceLocationId: Long, @@ -29,74 +27,38 @@ class QrCodeDetailViewModel @AssistedInject constructor( private val traceLocationRepository: DefaultTraceLocationRepository ) : CWAViewModel() { - private val traceLocationFlow = MutableStateFlow<TraceLocation?>(null) - private val titleFlow = MutableStateFlow<String?>(null) - private val subtitleFlow = MutableStateFlow<String?>(null) - private val startTimeFlow = MutableStateFlow<Instant?>(null) - private val endTimeFlow = MutableStateFlow<Instant?>(null) - private val bitmapLiveData = MutableLiveData<Bitmap>() + private var traceLocation: TraceLocation? = null + private val mutableUiState = MutableLiveData<UiState>() + val uiState: LiveData<UiState> + get() = mutableUiState + val routeToScreen: SingleLiveEvent<QrCodeDetailNavigationEvents> = SingleLiveEvent() init { - launch { - val traceLocation = traceLocationRepository.traceLocationForId(traceLocationId) - - if (titleFlow.value == null) { - titleFlow.value = traceLocation.description - } - - if (subtitleFlow.value == null) { - subtitleFlow.value = traceLocation.address - } - - if (startTimeFlow.value == null) { - startTimeFlow.value = traceLocation.startDate - } - - if (endTimeFlow.value == null) { - endTimeFlow.value = traceLocation.endDate - } - - traceLocationFlow.value = traceLocation - - createQrCode(traceLocation) + loadTraceLocation() } } - val uiState = combine( - traceLocationFlow.filterNotNull(), - startTimeFlow, - endTimeFlow - ) { traceLocation, startTime, endTime -> - UiState( - traceLocation = traceLocation, - startInstant = startTime ?: traceLocation.startDate, - endInstant = endTime ?: traceLocation.endDate - ) - }.asLiveData() - - data class UiState( - private val traceLocation: TraceLocation, - private val startInstant: Instant?, - private val endInstant: Instant? - ) { - val description: String get() = traceLocation.description - val address: String get() = traceLocation.address - val startDateTime: Instant? get() = startInstant - val endDateTime: Instant? get() = endInstant + private suspend fun loadTraceLocation() { + try { + traceLocation = traceLocationRepository.traceLocationForId(traceLocationId).also { + mutableUiState.postValue(UiState(it)) + createQrCode(it) + } + } catch (exception: Exception) { + Timber.d(exception, "No location found") + exception.report(ExceptionCategory.INTERNAL) + } } - val qrCodeBitmap: LiveData<Bitmap> = bitmapLiveData - val routeToScreen: SingleLiveEvent<QrCodeDetailNavigationEvents> = SingleLiveEvent() - /** - * Creates a QR Code [Bitmap] ,result is delivered by [qrCodeBitmap] + * Creates a QR Code [Bitmap] ,result is delivered by [uiState] */ private fun createQrCode(traceLocation: TraceLocation) = launch(context = dispatcher.IO) { try { val input = traceLocation.locationUrl Timber.d("input=$input") - bitmapLiveData.postValue(qrCodeGenerator.createQrCode(input)) + mutableUiState.postValue(UiState(traceLocation, qrCodeGenerator.createQrCode(input))) } catch (e: Exception) { Timber.d(e, "Qr code creation failed") e.report(ExceptionCategory.INTERNAL) @@ -113,6 +75,27 @@ class QrCodeDetailViewModel @AssistedInject constructor( ) } + fun duplicateTraceLocation() { + traceLocation?.let { + val category = traceLocationCategories.find { category -> category.type == it.type } + if (category == null) { + Timber.e("Category not found, traceLocation = $traceLocation") + } else { + routeToScreen.postValue(QrCodeDetailNavigationEvents.NavigateToDuplicateFragment(it, category)) + } + } + } + + data class UiState( + private val traceLocation: TraceLocation, + val bitmap: Bitmap? = null + ) { + val description: String get() = traceLocation.description + val address: String get() = traceLocation.address + val startDateTime: Instant? get() = traceLocation.startDate + val endDateTime: Instant? get() = traceLocation.endDate + } + @AssistedFactory interface Factory : CWAViewModelFactory<QrCodeDetailViewModel> { fun create( diff --git a/Corona-Warn-App/src/main/res/navigation/trace_location_organizer_nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/trace_location_organizer_nav_graph.xml index aa52e6cb3..ae96af2c6 100644 --- a/Corona-Warn-App/src/main/res/navigation/trace_location_organizer_nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/trace_location_organizer_nav_graph.xml @@ -82,6 +82,9 @@ <action android:id="@+id/action_qrCodeDetailFragment_to_qrCodePosterFragment" app:destination="@id/qrCodePosterFragment" /> + <action + android:id="@+id/action_qrCodeDetailFragment_to_traceLocationCreateFragment" + app:destination="@id/traceLocationCreateFragment" /> </fragment> <fragment -- GitLab