From e9c75459fa20d932d5b29f3b002ec7bad419aff2 Mon Sep 17 00:00:00 2001 From: Juraj Kusnier <jurajkusnier@users.noreply.github.com> Date: Thu, 8 Apr 2021 12:22:22 +0200 Subject: [PATCH] Implement Self-CheckIn (EXPOSUREAPP-5747) (#2757) * Create self-checkin event * navigation to check-in * Prevent multiple self-check-ins * Fix merge * Update layout * Allow check-in multiple times * fix lint * Update test menu * Force onboarding before check-in by deeplink * fix typos Co-authored-by: Lukas Lechner <lukas.lechner@sap.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> Co-authored-by: I502720 <axel.herbstreith@sap.com> --- .../ui/DeltaOnboardingFragmentViewModel.kt | 15 ++++++++++- .../ui/DeltaonboardingFragment.kt | 7 ++++- .../layout/fragment_test_deltaonboarding.xml | 27 +++++++++++++++++++ .../onboarding/CheckInOnboardingFragment.kt | 6 ++++- .../organizer/list/TraceLocationEvent.kt | 2 ++ .../organizer/list/TraceLocationsFragment.kt | 10 +++++++ .../organizer/list/TraceLocationsViewModel.kt | 18 ++++++++++--- .../organizer/list/items/TraceLocationVH.kt | 3 +++ ...ocation_organizer_trace_locations_item.xml | 5 ++++ .../trace_location_attendee_nav_graph.xml | 7 ++++- 10 files changed, 93 insertions(+), 7 deletions(-) diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt index 49daaf6fa..9152f953a 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaOnboardingFragmentViewModel.kt @@ -6,6 +6,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings import de.rki.coronawarnapp.environment.BuildConfigWrap +import de.rki.coronawarnapp.eventregistration.TraceLocationSettings import de.rki.coronawarnapp.main.CWASettings import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.viewmodel.CWAViewModel @@ -13,6 +14,7 @@ import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory class DeltaOnboardingFragmentViewModel @AssistedInject constructor( private val settings: CWASettings, + private val traceLocationSettings: TraceLocationSettings, private val contactDiarySettings: ContactDiarySettings, dispatcherProvider: DispatcherProvider ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { @@ -43,10 +45,21 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor( fun isDeltaOnboardingDone() = settings.wasInteroperabilityShownAtLeastOnce - fun setDeltaOboardinDone(value: Boolean) { + fun setDeltaOnboardingDone(value: Boolean) { settings.wasInteroperabilityShownAtLeastOnce = value } + fun isAttendeeOnboardingDone() = + traceLocationSettings.onboardingStatus == TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0 + + fun setAttendeeOnboardingDone(value: Boolean) { + traceLocationSettings.onboardingStatus = + if (value) + TraceLocationSettings.OnboardingStatus.ONBOARDED_2_0 + else + TraceLocationSettings.OnboardingStatus.NOT_ONBOARDED + } + @AssistedFactory interface Factory : SimpleCWAViewModelFactory<DeltaOnboardingFragmentViewModel> } diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt index 1179e8e07..1308cff1b 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/deltaonboarding/ui/DeltaonboardingFragment.kt @@ -26,6 +26,7 @@ class DeltaonboardingFragment : Fragment(R.layout.fragment_test_deltaonboarding) binding.switchContactJournalOnboarding.isChecked = viewModel.isContactJournalOnboardingDone() binding.switchDeltaOnboarding.isChecked = viewModel.isDeltaOnboardingDone() + binding.switchAttendeeOnboarding.isChecked = viewModel.isAttendeeOnboardingDone() viewModel.changelogVersion.observe(viewLifecycleOwner) { binding.lastChangelogEdittext.setText(it.toString()) } @@ -48,7 +49,11 @@ class DeltaonboardingFragment : Fragment(R.layout.fragment_test_deltaonboarding) } binding.switchDeltaOnboarding.setOnCheckedChangeListener { _, value -> - viewModel.setDeltaOboardinDone(value) + viewModel.setDeltaOnboardingDone(value) + } + + binding.switchAttendeeOnboarding.setOnCheckedChangeListener { _, value -> + viewModel.setAttendeeOnboardingDone(value) } } diff --git a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_deltaonboarding.xml b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_deltaonboarding.xml index 374995566..b1305ae31 100644 --- a/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_deltaonboarding.xml +++ b/Corona-Warn-App/src/deviceForTesters/res/layout/fragment_test_deltaonboarding.xml @@ -146,5 +146,32 @@ </androidx.constraintlayout.widget.ConstraintLayout> + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/debug_container4" + style="@style/Card" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="@dimen/spacing_tiny"> + + <TextView + android:id="@+id/event_creation_title" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Event Creation Onboarding" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <com.google.android.material.switchmaterial.SwitchMaterial + android:id="@+id/switch_attendee_onboarding" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + android:text="Attendee onboarding finished" + app:layout_constraintTop_toBottomOf="@id/event_creation_title" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + </LinearLayout> </androidx.core.widget.NestedScrollView> diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/onboarding/CheckInOnboardingFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/onboarding/CheckInOnboardingFragment.kt index c66e18b87..3f00d809e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/onboarding/CheckInOnboardingFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/onboarding/CheckInOnboardingFragment.kt @@ -26,6 +26,10 @@ class CheckInOnboardingFragment : Fragment(R.layout.fragment_trace_location_onbo override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + if (viewModel.isOnboardingComplete && args.uri != null) { + doNavigate(CheckInOnboardingFragmentDirections.actionCheckInOnboardingFragmentToCheckInsFragment(args.uri)) + } + with(binding) { checkInOnboardingAcknowledge.setOnClickListener { viewModel.onAcknowledged() } // TODO if consent is already given: should the text be changed? @@ -45,7 +49,7 @@ class CheckInOnboardingFragment : Fragment(R.layout.fragment_trace_location_onbo doNavigate( when (navEvent) { CheckInOnboardingNavigation.AcknowledgedNavigation -> - CheckInOnboardingFragmentDirections.actionCheckInOnboardingFragmentToCheckInsFragment() + CheckInOnboardingFragmentDirections.actionCheckInOnboardingFragmentToCheckInsFragment(args.uri) CheckInOnboardingNavigation.DataProtectionNavigation -> CheckInOnboardingFragmentDirections.actionCheckInOnboardingFragmentToPrivacyFragment() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationEvent.kt index 5909c9829..a4576f0ae 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationEvent.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationEvent.kt @@ -6,6 +6,8 @@ sealed class TraceLocationEvent { data class DuplicateItem(val traceLocation: TraceLocation) : TraceLocationEvent() + data class SelfCheckIn(val traceLocation: TraceLocation) : TraceLocationEvent() + data class ConfirmDeleteItem(val traceLocation: TraceLocation) : TraceLocationEvent() data class ConfirmSwipeItem(val traceLocation: TraceLocation, val position: Int) : TraceLocationEvent() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsFragment.kt index 1847e8f7b..35ad5d4c4 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsFragment.kt @@ -7,12 +7,14 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.Toolbar import androidx.core.view.isGone import androidx.fragment.app.Fragment +import androidx.navigation.NavOptions import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.findNavController import com.google.android.material.transition.Hold import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.TraceLocationOrganizerTraceLocationsListFragmentBinding import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation +import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.CheckInsFragment import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.traceLocationCategories import de.rki.coronawarnapp.ui.eventregistration.organizer.details.QrCodeDetailFragmentArgs import de.rki.coronawarnapp.util.DialogHelper @@ -105,6 +107,14 @@ class TraceLocationsFragment : Fragment(R.layout.trace_location_organizer_trace_ it.traceLocation.id ) ) + is TraceLocationEvent.SelfCheckIn -> { + findNavController().navigate( + CheckInsFragment.createCheckInUri(it.traceLocation.locationUrl), + NavOptions.Builder() + .setPopUpTo(R.id.checkInsFragment, true) + .build() + ) + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsViewModel.kt index d4167ccd5..dbbb8ad2d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/TraceLocationsViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.eventregistration.storage.repo.TraceLocationRepository import de.rki.coronawarnapp.ui.eventregistration.organizer.list.items.TraceLocationItem @@ -13,10 +14,12 @@ 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.combine import kotlinx.coroutines.flow.map class TraceLocationsViewModel @AssistedInject constructor( dispatcherProvider: DispatcherProvider, + checkInsRepository: CheckInRepository, private val traceLocationRepository: TraceLocationRepository, private val timeStamper: TimeStamper ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { @@ -29,11 +32,20 @@ class TraceLocationsViewModel @AssistedInject constructor( .filter { it.endDate == null || it.endDate.isAfter(timeStamper.nowUTC.toDateTime().minusDays(15)) } .sortedBy { it.description } } - .map { traceLocations -> + .combine(checkInsRepository.allCheckIns) { traceLocations, checkIns -> traceLocations.map { traceLocation -> + Pair( + traceLocation, + checkIns.firstOrNull { traceLocation.locationId == it.traceLocationId && !it.completed } == null + ) + } + } + .map { traceLocations -> + traceLocations.map { item -> TraceLocationVH.Item( - traceLocation = traceLocation, - onCheckIn = { /* TODO */ }, + traceLocation = item.first, + canCheckIn = item.second, + onCheckIn = { events.postValue(TraceLocationEvent.SelfCheckIn(it)) }, onDuplicate = { events.postValue(TraceLocationEvent.DuplicateItem(it)) }, onShowPrint = { events.postValue(TraceLocationEvent.StartQrCodePosterFragment(it)) }, onDeleteItem = { events.postValue(TraceLocationEvent.ConfirmDeleteItem(it)) }, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/items/TraceLocationVH.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/items/TraceLocationVH.kt index da8cca474..8756cf1d0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/items/TraceLocationVH.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/list/items/TraceLocationVH.kt @@ -2,6 +2,7 @@ package de.rki.coronawarnapp.ui.eventregistration.organizer.list.items import android.view.ViewGroup import androidx.core.view.isGone +import androidx.core.view.isVisible import de.rki.coronawarnapp.R import de.rki.coronawarnapp.databinding.TraceLocationOrganizerTraceLocationsItemBinding import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation @@ -62,12 +63,14 @@ class TraceLocationVH(parent: ViewGroup) : } } + checkinAction.isVisible = item.canCheckIn checkinAction.setOnClickListener { item.onCheckIn(item.traceLocation) } itemView.setOnClickListener { item.onCardClicked(item.traceLocation, adapterPosition) } } data class Item( val traceLocation: TraceLocation, + val canCheckIn: Boolean, val onCheckIn: (TraceLocation) -> Unit, val onDuplicate: (TraceLocation) -> Unit, val onShowPrint: (TraceLocation) -> Unit, diff --git a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_trace_locations_item.xml b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_trace_locations_item.xml index 8434f98f0..867ff0249 100644 --- a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_trace_locations_item.xml +++ b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_trace_locations_item.xml @@ -85,6 +85,11 @@ app:barrierDirection="bottom" app:constraint_referenced_ids="address,duration,icon" /> + <Space + android:layout_width="match_parent" + android:layout_height="16dp" + app:layout_constraintTop_toBottomOf="@id/button_barrier" /> + <com.google.android.material.button.MaterialButton android:id="@+id/checkin_action" style="@style/Widget.MaterialComponents.Button.OutlinedButton" diff --git a/Corona-Warn-App/src/main/res/navigation/trace_location_attendee_nav_graph.xml b/Corona-Warn-App/src/main/res/navigation/trace_location_attendee_nav_graph.xml index cb34d6759..bbf7abe77 100644 --- a/Corona-Warn-App/src/main/res/navigation/trace_location_attendee_nav_graph.xml +++ b/Corona-Warn-App/src/main/res/navigation/trace_location_attendee_nav_graph.xml @@ -9,6 +9,7 @@ android:name="de.rki.coronawarnapp.ui.eventregistration.attendee.onboarding.CheckInOnboardingFragment" android:label="CheckInOnboardingFragment" tools:layout="@layout/fragment_trace_location_onboarding"> + <deepLink app:uri="coronawarnapp://check-ins/{uri}" /> <action android:id="@+id/action_checkInOnboardingFragment_to_checkInsFragment" app:destination="@id/checkInsFragment" @@ -21,6 +22,11 @@ android:name="showBottomNav" android:defaultValue="true" app:argType="boolean" /> + <argument + android:name="uri" + android:defaultValue="@null" + app:argType="string" + app:nullable="true" /> </fragment> <fragment android:id="@+id/checkInPrivacyFragment" @@ -56,7 +62,6 @@ android:name="de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.CheckInsFragment" android:label="CheckInsFragment" tools:layout="@layout/trace_location_attendee_checkins_fragment"> - <deepLink app:uri="coronawarnapp://check-ins/{uri}" /> <action android:id="@+id/action_checkInsFragment_to_scanCheckInQrCodeFragment" app:destination="@id/scanCheckInQrCodeFragment" /> -- GitLab