Skip to content
Snippets Groups Projects
Unverified Commit e9c75459 authored by Juraj Kusnier's avatar Juraj Kusnier Committed by GitHub
Browse files

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: default avatarLukas Lechner <lukas.lechner@sap.com>
Co-authored-by: default avatarharambasicluka <64483219+harambasicluka@users.noreply.github.com>
Co-authored-by: default avatarI502720 <axel.herbstreith@sap.com>
parent a4ccf034
No related branches found
No related tags found
No related merge requests found
Showing
with 93 additions and 7 deletions
......@@ -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>
}
......@@ -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)
}
}
......
......@@ -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>
......@@ -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()
}
......
......@@ -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()
......
......@@ -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()
)
}
}
}
......
......@@ -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)) },
......
......@@ -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,
......
......@@ -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"
......
......@@ -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" />
......
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