From 883bab15c3959da5befd0f2adbe22f3479c019ea Mon Sep 17 00:00:00 2001 From: Kolya Opahle <k.opahle@sap.com> Date: Wed, 31 Mar 2021 19:08:02 +0200 Subject: [PATCH] Event Checkin and Event Edit Fragments (EXPOSUREAPP-5743/5953) (#2692) * Added white cwa logo drawable Initial changes to fragment_confirm_check_in to align with figma design Removed old binding references from ConfirmCheckInFragment * Added logic for checkin handling and trace location info display to the ConfirmCheckInFragment * Added card for too late or too early check in to check in fragment * Added layouts and texts for the checkin edit functionality (no fragment and viewmodel code yet) * Separated ConfirmCheckInFragment and EditCheckInFragment Implemented CheckIn Editing in EditCheckInFragment * Fixed linting * Fixed tests in ConfirmCheckInViewModelTest * Added mocks for default unit tests in ConfirmCheckInViewModelTest * cleaned up the checkin and edit strings * First round of pr comments * Added check to EditCheckInFragment that disables save button if checkInDate is after checkOutDate * added StringRes annotation to getter * updated layout * changed switch styling * refactored checkIn layout * updated layout of edit checkIn screen * updated strings * added new style for cards without elevation and applied it to card on event info screens * Switched confirm card row to ConstraintLayout to fix issues with varying screen sizes * Made checkin time and label top aligned * Fixed issues created by merge Co-authored-by: I502720 <axel.herbstreith@sap.com> Co-authored-by: Mohamed <mohamed.metwalli@sap.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> --- .../checkins/CheckInRepository.kt | 7 + .../EventRegistrationUIModule.kt | 7 +- .../attendee/checkins/CheckInsFragment.kt | 8 +- .../confirm/ConfirmCheckInFragment.kt | 89 ++++-- .../confirm/ConfirmCheckInViewModel.kt | 86 +++++- .../attendee/edit/EditCheckInFragment.kt | 181 +++++++++++ .../attendee/edit/EditCheckInModule.kt | 18 ++ .../attendee/edit/EditCheckInNavigation.kt | 6 + .../attendee/edit/EditCheckInViewModel.kt | 162 ++++++++++ .../adapter/category/TraceLocationCategory.kt | 10 + .../ic_corona_warn_app_icon_white.xml | 72 ----- .../main/res/drawable/ic_cwa_logo_white.xml | 60 ++++ .../res/layout/fragment_confirm_check_in.xml | 281 +++++++++++++++--- .../res/layout/fragment_edit_check_in.xml | 256 ++++++++++++++++ ...tion_organizer_qr_code_detail_fragment.xml | 2 +- .../trace_location_attendee_nav_graph.xml | 12 +- .../values-de/event_registration_strings.xml | 28 ++ .../src/main/res/values/dimens.xml | 1 + .../res/values/event_registration_strings.xml | 29 ++ .../src/main/res/values/styles.xml | 5 + .../confirm/ConfirmCheckInViewModelTest.kt | 11 +- 21 files changed, 1185 insertions(+), 146 deletions(-) create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInFragment.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInModule.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInNavigation.kt create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInViewModel.kt delete mode 100644 Corona-Warn-App/src/main/res/drawable/ic_corona_warn_app_icon_white.xml create mode 100644 Corona-Warn-App/src/main/res/drawable/ic_cwa_logo_white.xml create mode 100644 Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInRepository.kt index 2e48fa57c..ae8bc05a0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/eventregistration/checkins/CheckInRepository.kt @@ -49,4 +49,11 @@ class CheckInRepository @Inject constructor( Timber.d("clear()") checkInDao.deleteAll() } + + suspend fun checkInForId(checkInId: Long): CheckIn { + val checkIn = checkInDao.entryForId(checkInId) + ?: throw IllegalArgumentException("No checkIn found for ID=$checkInId") + + return checkIn.toCheckIn() + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt index 09f3e8853..4155d9059 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/EventRegistrationUIModule.kt @@ -2,15 +2,17 @@ package de.rki.coronawarnapp.ui.eventregistration import dagger.Module import dagger.android.ContributesAndroidInjector -import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragment import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.CheckInsFragment import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.CheckInsModule import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInFragment import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInModule +import de.rki.coronawarnapp.ui.eventregistration.attendee.edit.EditCheckInFragment +import de.rki.coronawarnapp.ui.eventregistration.attendee.edit.EditCheckInModule import de.rki.coronawarnapp.ui.eventregistration.attendee.scan.ScanCheckInQrCodeFragment import de.rki.coronawarnapp.ui.eventregistration.attendee.scan.ScanCheckInQrCodeModule import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryFragment import de.rki.coronawarnapp.ui.eventregistration.organizer.category.TraceLocationCategoryFragmentModule +import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragment import de.rki.coronawarnapp.ui.eventregistration.organizer.create.TraceLocationCreateFragmentModule import de.rki.coronawarnapp.ui.eventregistration.organizer.qrinfo.TraceLocationQRInfoFragment import de.rki.coronawarnapp.ui.eventregistration.organizer.qrinfo.TraceLocationQRInfoFragmentModule @@ -26,6 +28,9 @@ internal abstract class EventRegistrationUIModule { @ContributesAndroidInjector(modules = [ConfirmCheckInModule::class]) abstract fun confirmCheckInFragment(): ConfirmCheckInFragment + @ContributesAndroidInjector(modules = [EditCheckInModule::class]) + abstract fun editCheckInFragment(): EditCheckInFragment + @ContributesAndroidInjector(modules = [CheckInsModule::class]) abstract fun checkInsFragment(): CheckInsFragment diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt index 2e37fe368..6bf054474 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/checkins/CheckInsFragment.kt @@ -93,8 +93,7 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag when (event) { is CheckInEvent.ConfirmCheckIn -> doNavigate( CheckInsFragmentDirections.actionCheckInsFragmentToConfirmCheckInFragment( - verifiedTraceLocation = event.verifiedTraceLocation, - editCheckInId = 0, + verifiedTraceLocation = event.verifiedTraceLocation ) ) @@ -105,9 +104,8 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag is CheckInEvent.ConfirmRemoveAll -> showRemovalConfirmation(null, null) is CheckInEvent.EditCheckIn -> doNavigate( - CheckInsFragmentDirections.actionCheckInsFragmentToConfirmCheckInFragment( - verifiedTraceLocation = null, - editCheckInId = event.checkInId, + CheckInsFragmentDirections.actionCheckInsFragmentToEditCheckInFragment( + editCheckInId = event.checkInId ) ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInFragment.kt index a22c989af..a411d1b2e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInFragment.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInFragment.kt @@ -2,64 +2,111 @@ package de.rki.coronawarnapp.ui.eventregistration.attendee.confirm import android.os.Bundle import android.view.View -import android.widget.Toast +import androidx.core.view.isGone 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.FragmentConfirmCheckInBinding +import de.rki.coronawarnapp.ui.durationpicker.DurationPicker import de.rki.coronawarnapp.util.di.AutoInject import de.rki.coronawarnapp.util.ui.observe2 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 org.joda.time.Duration import javax.inject.Inject +import kotlin.math.abs class ConfirmCheckInFragment : Fragment(R.layout.fragment_confirm_check_in), AutoInject { - private val navArgs by navArgs<ConfirmCheckInFragmentArgs>() @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory - private val viewModel: ConfirmCheckInViewModel by cwaViewModelsAssisted( factoryProducer = { viewModelFactory }, - constructorCall = { factory, savedState -> + constructorCall = { factory, _ -> factory as ConfirmCheckInViewModel.Factory - val editId = if (navArgs.editCheckInId == 0L) null else navArgs.editCheckInId - factory.create(navArgs.verifiedTraceLocation, editId) + factory.create(navArgs.verifiedTraceLocation) } ) + private val binding: FragmentConfirmCheckInBinding by viewBindingLazy() - private val args by navArgs<ConfirmCheckInFragmentArgs>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) with(binding) { + appBarLayout.addOnOffsetChangedListener( + AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> + title.alpha = ( + 1.0f - abs(verticalOffset / (appBarLayout.totalScrollRange.toFloat() * 0.6f)) + ) + } + ) + toolbar.setNavigationOnClickListener { viewModel.onClose() } - confirmButton.setOnClickListener { viewModel.onConfirmTraceLocation() } - // TODO bind final UI - args.verifiedTraceLocation?.let { - val traceLocation = it.traceLocation - eventGuid.text = "ID: %s".format(traceLocation.id) - startTime.text = "Start time: %s".format(traceLocation.startDate) - endTime.text = "End time: %s".format(traceLocation.endDate) - description.text = "Description: %s".format(traceLocation.description) + + confirmCheckinSettingsCardCheckoutToggle.setOnCheckedChangeListener { _, isChecked -> + viewModel.createJournalEntryToggled(isChecked) } - if (navArgs.editCheckInId != 0L) { - Toast.makeText(requireContext(), "EDIT CHECKIN MODE", Toast.LENGTH_SHORT).show() + confirmCheckinSettingsCardCheckoutTime.setOnClickListener { + viewModel.dateSelectorClicked() + } + + confirmCheckinConfirmButton.setOnClickListener { + viewModel.onConfirmTraceLocation() } } viewModel.events.observe2(this) { navEvent -> when (navEvent) { ConfirmCheckInNavigation.BackNavigation -> popBackStack() - ConfirmCheckInNavigation.ConfirmNavigation -> { - // TODO Navigate to the rightful destination - popBackStack() - } + ConfirmCheckInNavigation.ConfirmNavigation -> popBackStack() } } + + viewModel.uiState.observe2(this) { uiState -> + with(binding) { + confirmCheckinInfoCardHeader.text = getString(uiState.typeRes) + confirmCheckinInfoCardTitle.text = uiState.description + confirmCheckinInfoCardAddress.text = uiState.address + confirmCheckinSettingsCardCheckoutToggle.isChecked = uiState.createJournalEntry + confirmCheckinSettingsCardCheckoutTime.text = uiState.checkInEnd + + confirmCheckinEventInPastCard.isGone = !uiState.eventInPastVisible + + confirmCheckinEventInFutureCard.isGone = !uiState.eventInFutureVisible + confirmCheckinEventInFutureCardText.text = getString( + R.string.confirm_checkin_event_in_future_card_text, + uiState.eventInFutureDateText, + uiState.eventInFutureTimeText + ) + } + } + + viewModel.openDatePickerEvent.observe2(this) { time -> + showDurationPicker(time) { + viewModel.durationUpdated(it) + } + } + } + + private fun showDurationPicker( + defaultValue: String?, + callback: (Duration) -> Unit + ) { + val durationPicker = DurationPicker.Builder() + .duration(defaultValue ?: "00:00") + .minutes() + .title(getString(R.string.duration_dialog_title)) + .build() + durationPicker.show(parentFragmentManager, DURATION_PICKER_TAG) + durationPicker.setDurationChangeListener(callback) + } + + companion object { + private const val DURATION_PICKER_TAG = "duration_picker" } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt index e0f8e2d8b..ba77ca1bc 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/confirm/ConfirmCheckInViewModel.kt @@ -1,38 +1,86 @@ package de.rki.coronawarnapp.ui.eventregistration.attendee.confirm +import androidx.lifecycle.asLiveData import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import de.rki.coronawarnapp.eventregistration.checkins.CheckIn import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository +import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation +import de.rki.coronawarnapp.ui.durationpicker.toContactDiaryFormat +import de.rki.coronawarnapp.ui.durationpicker.toReadableDuration +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.mapTraceLocationToTitleRes +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 kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine import org.joda.time.Duration import org.joda.time.Instant +import org.joda.time.format.DateTimeFormat class ConfirmCheckInViewModel @AssistedInject constructor( - @Assisted private val verifiedTraceLocation: VerifiedTraceLocation?, - @Assisted private val editCheckInId: Long?, - private val checkInRepository: CheckInRepository + @Assisted private val verifiedTraceLocation: VerifiedTraceLocation, + private val checkInRepository: CheckInRepository, + private val timeStamper: TimeStamper ) : CWAViewModel() { + private val traceLocation = MutableStateFlow(verifiedTraceLocation.traceLocation) + private val createJournalEntry = MutableStateFlow(true) + private val checkInLength = MutableStateFlow( + Duration.standardMinutes( + verifiedTraceLocation.traceLocation.defaultCheckInLengthInMinutes?.toLong() ?: 0L + ) + ) + val openDatePickerEvent = SingleLiveEvent<String>() val events = SingleLiveEvent<ConfirmCheckInNavigation>() + val uiState = combine( + traceLocation, + createJournalEntry, + checkInLength + ) { traceLocation, createEntry, checkInLength -> + UiState( + traceLocation = traceLocation, + createJournalEntry = createEntry, + checkInEndOffset = checkInLength, + eventInPastVisible = traceLocation.isAfterEndTime(timeStamper.nowUTC), + eventInFutureVisible = traceLocation.isBeforeStartTime(timeStamper.nowUTC) + ) + }.asLiveData() + fun onClose() { events.value = ConfirmCheckInNavigation.BackNavigation } fun onConfirmTraceLocation() { - if (verifiedTraceLocation == null) return launch { - // TODO This is only for testing - checkInRepository.addCheckIn(verifiedTraceLocation.toCheckIn(checkInStart = Instant.now())) + val now = timeStamper.nowUTC + checkInRepository.addCheckIn( + verifiedTraceLocation.toCheckIn( + checkInStart = now, + createJournalEntry = createJournalEntry.value, + checkInEnd = now + checkInLength.value + ) + ) events.postValue(ConfirmCheckInNavigation.ConfirmNavigation) } } + fun createJournalEntryToggled(state: Boolean) { + createJournalEntry.value = state + } + + fun dateSelectorClicked() { + openDatePickerEvent.value = checkInLength.value.toContactDiaryFormat() + } + + fun durationUpdated(duration: Duration) { + checkInLength.value = duration + } + private fun VerifiedTraceLocation.toCheckIn( checkInStart: Instant, checkInEnd: Instant = checkInStart.plus( @@ -60,8 +108,30 @@ class ConfirmCheckInViewModel @AssistedInject constructor( @AssistedFactory interface Factory : CWAViewModelFactory<ConfirmCheckInViewModel> { fun create( - verifiedTraceLocation: VerifiedTraceLocation?, - editCheckInId: Long? + verifiedTraceLocation: VerifiedTraceLocation ): ConfirmCheckInViewModel } + + data class UiState( + private val traceLocation: TraceLocation, + private val checkInEndOffset: Duration, + val createJournalEntry: Boolean, + val eventInPastVisible: Boolean, + val eventInFutureVisible: Boolean + ) { + val description get() = traceLocation.description + val typeRes get() = mapTraceLocationToTitleRes(traceLocation.type) + val address get() = traceLocation.address + val checkInEnd get() = checkInEndOffset.toReadableDuration() + val eventInFutureDateText get() = traceLocation.startDate?.toDateTime()?.toString(dateFormatter) ?: "" + val eventInFutureTimeText get() = traceLocation.startDate?.toDateTime()?.toString(timeFormatter) ?: "" + } +} + +private val dateFormatter by lazy { + DateTimeFormat.forPattern("EE, dd.MM.yy") +} + +private val timeFormatter by lazy { + DateTimeFormat.forPattern("HH:mm") } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInFragment.kt new file mode 100644 index 000000000..0e822c842 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInFragment.kt @@ -0,0 +1,181 @@ +package de.rki.coronawarnapp.ui.eventregistration.attendee.edit + +import android.os.Bundle +import android.text.format.DateFormat +import android.view.View +import androidx.core.view.isGone +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.navArgs +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.datepicker.MaterialDatePicker +import com.google.android.material.timepicker.MaterialTimePicker +import com.google.android.material.timepicker.TimeFormat +import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.databinding.FragmentEditCheckInBinding +import de.rki.coronawarnapp.util.di.AutoInject +import de.rki.coronawarnapp.util.ui.observe2 +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 org.joda.time.DateTimeZone +import org.joda.time.LocalDate +import org.joda.time.LocalTime +import javax.inject.Inject +import kotlin.math.abs + +class EditCheckInFragment : Fragment(R.layout.fragment_edit_check_in), AutoInject { + private val navArgs by navArgs<EditCheckInFragmentArgs>() + + @Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory + private val viewModel: EditCheckInViewModel by cwaViewModelsAssisted( + factoryProducer = { viewModelFactory }, + constructorCall = { factory, _ -> + factory as EditCheckInViewModel.Factory + factory.create(if (navArgs.editCheckInId == 0L) null else navArgs.editCheckInId) + } + ) + + private val binding: FragmentEditCheckInBinding by viewBindingLazy() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + with(binding) { + appBarLayout.addOnOffsetChangedListener( + AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> + title.alpha = ( + 1.0f - abs(verticalOffset / (appBarLayout.totalScrollRange.toFloat() * 0.6f)) + ) + } + ) + + toolbar.setNavigationOnClickListener { viewModel.onClose() } + + editCheckinEditCardCheckinDate.setOnClickListener { + viewModel.onStartDateClicked() + } + + editCheckinEditCardCheckinTime.setOnClickListener { + viewModel.onStartTimeClicked() + } + + editCheckinEditCardCheckoutDate.setOnClickListener { + viewModel.onEndDateClicked() + } + + editCheckinEditCardCheckoutTime.setOnClickListener { + viewModel.onEndTimeClicked() + } + + editCheckinConfirmButton.setOnClickListener { + viewModel.onSaveClicked() + } + } + + viewModel.events.observe2(this) { navEvent -> + when (navEvent) { + EditCheckInNavigation.BackNavigation -> popBackStack() + EditCheckInNavigation.ConfirmNavigation -> popBackStack() + } + } + + viewModel.uiState.observe2(this) { uiState -> + with(binding) { + editCheckinInfoCardHeader.text = getString(uiState.typeRes) + editCheckinInfoCardTitle.text = uiState.description + editCheckinInfoCardAddress.text = uiState.address + + editCheckinEditCardCheckinDate.text = uiState.checkInStartDate + editCheckinEditCardCheckinTime.text = uiState.checkInStartTime + + editCheckinEditCardCheckoutDate.text = uiState.checkInEndDate + editCheckinEditCardCheckoutTime.text = uiState.checkInEndTime + + editCheckinDurationEditHintCard.isGone = !uiState.diaryWarningVisible + + editCheckinConfirmButton.isEnabled = uiState.canSaveChanges + } + } + + viewModel.openStartPickerEvent.observe2(this) { event -> + when (event) { + is EditCheckInViewModel.DateTimePickerEvent.DatePickerEvent -> + showDatePicker(event.localDate) { + viewModel.onStartTimeChanged( + EditCheckInViewModel.DateTimePickerEvent.DatePickerEvent(it) + ) + } + is EditCheckInViewModel.DateTimePickerEvent.TimePickerEvent -> + showTimePicker(event.localTime) { + viewModel.onStartTimeChanged( + EditCheckInViewModel.DateTimePickerEvent.TimePickerEvent(it) + ) + } + } + } + + viewModel.openEndPickerEvent.observe2(this) { event -> + when (event) { + is EditCheckInViewModel.DateTimePickerEvent.DatePickerEvent -> + showDatePicker(event.localDate) { + viewModel.onEndTimeChanged( + EditCheckInViewModel.DateTimePickerEvent.DatePickerEvent(it) + ) + } + is EditCheckInViewModel.DateTimePickerEvent.TimePickerEvent -> + showTimePicker(event.localTime) { + viewModel.onEndTimeChanged( + EditCheckInViewModel.DateTimePickerEvent.TimePickerEvent(it) + ) + } + } + } + } + + private fun showDatePicker( + defaultValue: LocalDate?, + callback: (LocalDate) -> Unit + ) { + MaterialDatePicker + .Builder + .datePicker() + .setSelection(defaultValue?.toDateTimeAtStartOfDay(DateTimeZone.UTC)?.millis) + .build() + .apply { + addOnPositiveButtonClickListener { + callback(LocalDate(it, DateTimeZone.UTC)) + } + } + .show(childFragmentManager, DATE_PICKER_TAG) + } + + private fun showTimePicker( + defaultValue: LocalTime?, + callback: (LocalTime) -> Unit + ) { + MaterialTimePicker + .Builder() + .setTimeFormat( + if (DateFormat.is24HourFormat(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H + ) + .apply { + if (defaultValue != null) { + setHour(defaultValue.hourOfDay) + setMinute(defaultValue.minuteOfHour) + } + } + .build() + .apply { + addOnPositiveButtonClickListener { + callback(LocalTime(this.hour, this.minute)) + } + } + .show(childFragmentManager, TIME_PICKER_TAG) + } + + companion object { + private const val DATE_PICKER_TAG = "date_picker" + private const val TIME_PICKER_TAG = "time_picker" + } +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInModule.kt new file mode 100644 index 000000000..6a7862e25 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInModule.kt @@ -0,0 +1,18 @@ +package de.rki.coronawarnapp.ui.eventregistration.attendee.edit + +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 EditCheckInModule { + @Binds + @IntoMap + @CWAViewModelKey(EditCheckInViewModel::class) + abstract fun editCheckInFragment( + factory: EditCheckInViewModel.Factory + ): CWAViewModelFactory<out CWAViewModel> +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInNavigation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInNavigation.kt new file mode 100644 index 000000000..05b11d1ad --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInNavigation.kt @@ -0,0 +1,6 @@ +package de.rki.coronawarnapp.ui.eventregistration.attendee.edit + +sealed class EditCheckInNavigation { + object BackNavigation : EditCheckInNavigation() + object ConfirmNavigation : EditCheckInNavigation() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInViewModel.kt new file mode 100644 index 000000000..a266e7e6d --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/attendee/edit/EditCheckInViewModel.kt @@ -0,0 +1,162 @@ +package de.rki.coronawarnapp.ui.eventregistration.attendee.edit + +import androidx.annotation.StringRes +import androidx.lifecycle.asLiveData +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import de.rki.coronawarnapp.eventregistration.checkins.CheckIn +import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository +import de.rki.coronawarnapp.ui.eventregistration.organizer.category.adapter.category.mapTraceLocationToTitleRes +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 org.joda.time.LocalDate +import org.joda.time.LocalTime +import org.joda.time.format.DateTimeFormat + +class EditCheckInViewModel @AssistedInject constructor( + @Assisted private val editCheckInId: Long?, + private val checkInRepository: CheckInRepository +) : CWAViewModel() { + private val checkInFlow = MutableStateFlow<CheckIn?>(null) + + private val checkInStartTime = MutableStateFlow<Instant?>(null) + private val checkInEndTime = MutableStateFlow<Instant?>(null) + + init { + launch { + val checkIn = checkInRepository.checkInForId(editCheckInId ?: 0) + + if (checkInStartTime.value == null) { + checkInStartTime.value = checkIn.checkInStart + } + if (checkInEndTime.value == null) { + checkInEndTime.value = checkIn.checkInEnd + } + + checkInFlow.value = checkIn + } + } + + val openStartPickerEvent = SingleLiveEvent<DateTimePickerEvent>() + val openEndPickerEvent = SingleLiveEvent<DateTimePickerEvent>() + + val events = SingleLiveEvent<EditCheckInNavigation>() + + val uiState = combine( + checkInFlow.filterNotNull(), + checkInStartTime, + checkInEndTime + ) { checkIn, checkInStartTime, checkInEndTime -> + UiState( + checkIn = checkIn, + checkInStartInstant = checkInStartTime ?: checkIn.checkInStart, + checkInEndInstant = checkInEndTime ?: checkIn.checkInEnd + ) + }.asLiveData() + + fun onClose() { + events.value = EditCheckInNavigation.BackNavigation + } + + fun onStartDateClicked() { + val utcDateTime = checkInStartTime.value?.toDateTime() + openStartPickerEvent.value = DateTimePickerEvent.DatePickerEvent(utcDateTime?.toLocalDate()) + } + + fun onStartTimeClicked() { + val utcDateTime = checkInStartTime.value?.toDateTime() + openStartPickerEvent.value = DateTimePickerEvent.TimePickerEvent(utcDateTime?.toLocalTime()) + } + + fun onEndDateClicked() { + val utcDateTime = checkInEndTime.value?.toDateTime() + openEndPickerEvent.value = DateTimePickerEvent.DatePickerEvent(utcDateTime?.toLocalDate()) + } + + fun onEndTimeClicked() { + val utcDateTime = checkInEndTime.value?.toDateTime() + openEndPickerEvent.value = DateTimePickerEvent.TimePickerEvent(utcDateTime?.toLocalTime()) + } + + fun onStartTimeChanged(event: DateTimePickerEvent) { + val startDateTime = checkInStartTime.value?.toDateTime() + + when (event) { + is DateTimePickerEvent.TimePickerEvent -> + checkInStartTime.value = startDateTime?.withTime(event.localTime)?.toInstant() + is DateTimePickerEvent.DatePickerEvent -> + checkInStartTime.value = startDateTime?.withDate(event.localDate)?.toInstant() + } + } + + fun onEndTimeChanged(event: DateTimePickerEvent) { + val endDateTime = checkInEndTime.value?.toDateTime() + + when (event) { + is DateTimePickerEvent.TimePickerEvent -> + checkInEndTime.value = endDateTime?.withTime(event.localTime)?.toInstant() + is DateTimePickerEvent.DatePickerEvent -> + checkInEndTime.value = endDateTime?.withDate(event.localDate)?.toInstant() + } + } + + fun onSaveClicked() { + launch { + val oldCheckIn = checkInFlow.value + val newCheckInTime = checkInStartTime.value + val newCheckOutTime = checkInEndTime.value + + if (oldCheckIn != null && newCheckInTime != null && newCheckOutTime != null) { + checkInRepository.updateCheckIn(checkInId = oldCheckIn.id) { + it.copy( + checkInStart = newCheckInTime, + checkInEnd = newCheckOutTime + ) + } + } + events.postValue(EditCheckInNavigation.ConfirmNavigation) + } + } + + @AssistedFactory + interface Factory : CWAViewModelFactory<EditCheckInViewModel> { + fun create( + editCheckInId: Long? + ): EditCheckInViewModel + } + + data class UiState( + private val checkIn: CheckIn, + private val checkInStartInstant: Instant, + private val checkInEndInstant: Instant + ) { + val description: String get() = checkIn.description + @get:StringRes val typeRes: Int get() = mapTraceLocationToTitleRes(checkIn.type) + val address: String get() = checkIn.address + val diaryWarningVisible: Boolean get() = checkIn.createJournalEntry + val checkInStartDate: String get() = checkInStartInstant.toDateTime().toString(dateFormatter) + val checkInStartTime: String get() = checkInStartInstant.toDateTime().toString(timeFormatter) + val checkInEndDate: String get() = checkInEndInstant.toDateTime().toString(dateFormatter) + val checkInEndTime: String get() = checkInEndInstant.toDateTime().toString(timeFormatter) + val canSaveChanges: Boolean get() = checkInStartInstant.isBefore(checkInEndInstant) + } + + sealed class DateTimePickerEvent { + open class DatePickerEvent(val localDate: LocalDate?) : DateTimePickerEvent() + open class TimePickerEvent(val localTime: LocalTime?) : DateTimePickerEvent() + } +} + +private val dateFormatter by lazy { + DateTimeFormat.forPattern("EE, dd.MM.yy") +} + +private val timeFormatter by lazy { + DateTimeFormat.forPattern("HH:mm") +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt index 9d9bc2ac3..31f49804d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/eventregistration/organizer/category/adapter/category/TraceLocationCategory.kt @@ -106,3 +106,13 @@ val traceLocationCategories = listOf( R.string.tracelocation_organizer_category_other_event_title ) ) + +@StringRes +fun mapTraceLocationToTitleRes(type: TraceLocationOuterClass.TraceLocationType) = + mapTraceLocationToTitleRes(type.number) + +@StringRes +fun mapTraceLocationToTitleRes(type: Int): Int { + val category = traceLocationCategories.find { it.type.ordinal == type } + return category?.title ?: R.string.tracelocation_organizer_category_other_location_title +} diff --git a/Corona-Warn-App/src/main/res/drawable/ic_corona_warn_app_icon_white.xml b/Corona-Warn-App/src/main/res/drawable/ic_corona_warn_app_icon_white.xml deleted file mode 100644 index 4e4ddebd4..000000000 --- a/Corona-Warn-App/src/main/res/drawable/ic_corona_warn_app_icon_white.xml +++ /dev/null @@ -1,72 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:aapt="http://schemas.android.com/aapt" - android:width="76dp" - android:height="26dp" - android:viewportWidth="76" - android:viewportHeight="26"> - <path - android:pathData="M25.0703,15.396H25.8939L26.9581,18.7117L28.3576,15.2891H28.4014L29.8081,18.7117L30.8505,15.396H31.6231L29.8883,20.6598H29.8446L28.3795,17.0385L26.8779,20.6598H26.8415L25.0703,15.396Z" - android:fillColor="#ffffff"/> - <path - android:pathData="M32.8132,19.6208H34.8249L35.2113,20.5911H36.0349L33.8555,15.2891H33.8118L31.6396,20.5911H32.4268L32.8132,19.6208ZM34.54,18.9037H33.0969L33.8257,17.0854L34.54,18.9037Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M37.0918,20.5896H37.8717V18.672H38.6809H38.7756L39.8835,20.5896H40.7363L39.5409,18.5268C40.1605,18.29 40.5031,17.7705 40.5031,17.0447C40.5031,16.0592 39.8398,15.3945 38.6809,15.3945H37.0918V20.5896ZM39.6934,17.0455C39.6934,17.6643 39.3872,17.9699 38.651,17.9699H37.8711V16.1211H38.651C39.38,16.1211 39.6934,16.419 39.6934,17.0455Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M42.6908,17.1768V20.5918H41.9619V15.3203H42.0203L45.1983,18.8117V15.3967H45.9271V20.6681H45.8689L42.6908,17.1768Z" - android:fillColor="#ffffff"/> - <path - android:pathData="M47.5049,17.8203H48.8461V18.5155H47.5049V17.8203Z" - android:fillColor="#ffffff"/> - <path - android:pathData="M50.8552,19.6208H52.8669L53.2533,20.5911H54.0769L51.8975,15.2891H51.8538L49.6816,20.5911H50.4688L50.8552,19.6208ZM52.5828,18.9037H51.1397L51.8685,17.0854L52.5828,18.9037Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M55.1338,20.5896H55.9137V18.756H56.7083C57.8599,18.756 58.5305,18.1066 58.5305,17.0753C58.5305,16.0668 57.8672,15.3945 56.7083,15.3945H55.1338V20.5896ZM57.7228,17.0761C57.7228,17.7102 57.4166,18.031 56.6804,18.031H55.915V16.1211H56.6804C57.4093,16.1211 57.7228,16.4343 57.7228,17.0761Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M59.7412,20.5896H60.5212V18.756H61.3157C62.4673,18.756 63.1379,18.1066 63.1379,17.0753C63.1379,16.0668 62.4746,15.3945 61.3157,15.3945H59.7412V20.5896ZM62.3302,17.0761C62.3302,17.7102 62.024,18.031 61.2878,18.031H60.5225V16.1211H61.2878C62.0167,16.1211 62.3302,16.4343 62.3302,17.0761Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M25.1113,7.8824C25.1113,5.4574 26.9226,3.6719 29.2191,3.6719C30.7107,3.6719 31.7406,4.263 32.439,5.2644L31.4683,5.9641C30.9356,5.2282 30.249,4.8422 29.1835,4.8422C27.5855,4.8422 26.4253,6.1451 26.4253,7.8824C26.4253,9.6559 27.6091,10.9227 29.2309,10.9227C30.2726,10.9227 31.0422,10.5246 31.6459,9.7283L32.6284,10.416C31.7998,11.538 30.7462,12.093 29.1835,12.093C26.8871,12.093 25.1113,10.3074 25.1113,7.8824Z" - android:fillColor="#ffffff"/> - <path - android:pathData="M37.909,3.6719C35.6006,3.6719 33.7539,5.4574 33.7539,7.8824C33.7539,10.3074 35.6006,12.093 37.909,12.093C40.2174,12.093 42.0641,10.3074 42.0641,7.8824C42.0641,5.4574 40.2174,3.6719 37.909,3.6719ZM37.9085,4.8438C39.5777,4.8438 40.7496,6.1467 40.7496,7.884C40.7496,9.6213 39.5777,10.9243 37.9085,10.9243C36.2394,10.9243 35.0674,9.6213 35.0674,7.884C35.0674,6.1467 36.2394,4.8438 37.9085,4.8438Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M43.8994,11.9852H45.1661V8.957H46.4801H46.634L48.4334,11.9852H49.8184L47.8769,8.7277C48.8831,8.3537 49.4396,7.5333 49.4396,6.3872C49.4396,4.8309 48.3623,3.7813 46.4801,3.7813H43.8994V11.9852ZM48.1244,6.3858C48.1244,7.363 47.6272,7.8456 46.4316,7.8456H45.165V4.9259H46.4316C47.6154,4.9259 48.1244,5.3964 48.1244,6.3858Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M55.2147,3.6719C52.9063,3.6719 51.0596,5.4574 51.0596,7.8824C51.0596,10.3074 52.9063,12.093 55.2147,12.093C57.5231,12.093 59.3698,10.3074 59.3698,7.8824C59.3698,5.4574 57.5231,3.6719 55.2147,3.6719ZM55.2161,4.8438C56.8853,4.8438 58.0573,6.1467 58.0573,7.884C58.0573,9.6213 56.8853,10.9243 55.2161,10.9243C53.547,10.9243 52.375,9.6213 52.375,7.884C52.375,6.1467 53.547,4.8438 55.2161,4.8438Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M62.3752,6.5919V11.9848H61.1914V3.6602H61.2861L66.4474,9.1737V3.7808H67.6312V12.1054H67.5365L62.3752,6.5919Z" - android:fillColor="#ffffff"/> - <path - android:pathData="M70.7672,10.45H74.0345L74.662,11.9822H75.9996L72.4601,3.6094H72.3891L68.8613,11.9822H70.1398L70.7672,10.45ZM73.5725,9.3128H71.2285L72.4123,6.4414L73.5725,9.3128Z" - android:fillColor="#ffffff" - android:fillType="evenOdd"/> - <path - android:pathData="M12.8401,16.6805V18.8725C13.2442,19.0159 13.5342,19.4012 13.5342,19.8554C13.5342,20.4317 13.0681,20.8989 12.4931,20.8989C11.9181,20.8989 11.452,20.4317 11.452,19.8554C11.452,19.4012 11.742,19.0159 12.1461,18.8725V16.6805C11.257,16.6069 10.4474,16.2539 9.8047,15.7086L8.2584,17.2584C8.4429,17.6462 8.3762,18.1242 8.0558,18.4453C7.6492,18.8529 6.99,18.8529 6.5834,18.4453C6.1769,18.0378 6.1769,17.3771 6.5834,16.9696C6.9038,16.6485 7.3807,16.5815 7.7676,16.7665L9.3139,15.2167C8.7698,14.5725 8.4177,13.761 8.3442,12.8698H6.1572C6.0142,13.2749 5.6298,13.5655 5.1767,13.5655C4.6017,13.5655 4.1356,13.0983 4.1356,12.522C4.1356,11.9457 4.6017,11.4785 5.1767,11.4785C5.6298,11.4785 6.0142,11.7692 6.1572,12.1742H8.3442C8.4177,11.283 8.7698,10.4716 9.3139,9.8274L7.7676,8.2775C7.3807,8.4625 6.9038,8.3955 6.5834,8.0744C6.1769,7.6669 6.1769,7.0062 6.5834,6.5987C6.99,6.1912 7.6492,6.1912 8.0558,6.5987C8.3762,6.9198 8.4429,7.3978 8.2584,7.7856L9.8047,9.3354C10.4474,8.7901 11.257,8.4371 12.1461,8.3636V6.1715C11.742,6.0281 11.452,5.6428 11.452,5.1887C11.452,4.6123 11.9181,4.1452 12.4931,4.1452C13.0681,4.1452 13.5342,4.6123 13.5342,5.1887C13.5342,5.6428 13.2442,6.0281 12.8401,6.1715V8.3636C13.8514,8.4473 14.76,8.8933 15.437,9.5713L21.327,3.6676C19.0662,1.4016 15.943,0 12.4931,0C5.5933,0 0,5.6063 0,12.522C0,19.4377 5.5933,25.044 12.4931,25.044C15.943,25.044 19.0662,23.6424 21.327,21.3764L15.437,15.4727C14.76,16.1508 13.8514,16.5968 12.8401,16.6805Z"> - <aapt:attr name="android:fillColor"> - <gradient - android:startY="25.044" - android:startX="21.327" - android:endY="0" - android:endX="21.327" - android:type="linear"> - <item android:offset="0" android:color="#FFFFFFFF"/> - <item android:offset="1" android:color="#FFFFFFFF"/> - </gradient> - </aapt:attr> - </path> -</vector> diff --git a/Corona-Warn-App/src/main/res/drawable/ic_cwa_logo_white.xml b/Corona-Warn-App/src/main/res/drawable/ic_cwa_logo_white.xml new file mode 100644 index 000000000..c3584e118 --- /dev/null +++ b/Corona-Warn-App/src/main/res/drawable/ic_cwa_logo_white.xml @@ -0,0 +1,60 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="76dp" + android:height="26dp" + android:viewportWidth="76" + android:viewportHeight="26"> + <path + android:fillColor="#ffffff" + android:pathData="M25.0703,15.396H25.8939L26.9581,18.7117L28.3576,15.2891H28.4014L29.8081,18.7117L30.8505,15.396H31.6231L29.8883,20.6598H29.8446L28.3795,17.0385L26.8779,20.6598H26.8415L25.0703,15.396Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M32.8132,19.6208H34.8249L35.2113,20.5911H36.0349L33.8555,15.2891H33.8118L31.6396,20.5911H32.4268L32.8132,19.6208ZM34.54,18.9037H33.0969L33.8257,17.0854L34.54,18.9037Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M37.0918,20.5896H37.8717V18.672H38.6809H38.7756L39.8835,20.5896H40.7363L39.5409,18.5268C40.1605,18.29 40.5031,17.7705 40.5031,17.0447C40.5031,16.0592 39.8398,15.3945 38.6809,15.3945H37.0918V20.5896ZM39.6934,17.0455C39.6934,17.6643 39.3872,17.9699 38.651,17.9699H37.8711V16.1211H38.651C39.38,16.1211 39.6934,16.419 39.6934,17.0455Z" /> + <path + android:fillColor="#ffffff" + android:pathData="M42.6908,17.1768V20.5918H41.9619V15.3203H42.0203L45.1983,18.8117V15.3967H45.9271V20.6681H45.8689L42.6908,17.1768Z" /> + <path + android:fillColor="#ffffff" + android:pathData="M47.5049,17.8203H48.8461V18.5155H47.5049V17.8203Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M50.8552,19.6208H52.8669L53.2533,20.5911H54.0769L51.8975,15.2891H51.8538L49.6816,20.5911H50.4688L50.8552,19.6208ZM52.5828,18.9037H51.1397L51.8685,17.0854L52.5828,18.9037Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M55.1338,20.5896H55.9137V18.756H56.7083C57.8599,18.756 58.5305,18.1066 58.5305,17.0753C58.5305,16.0668 57.8672,15.3945 56.7083,15.3945H55.1338V20.5896ZM57.7228,17.0761C57.7228,17.7102 57.4166,18.031 56.6804,18.031H55.915V16.1211H56.6804C57.4093,16.1211 57.7228,16.4343 57.7228,17.0761Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M59.7412,20.5896H60.5212V18.756H61.3157C62.4673,18.756 63.1379,18.1066 63.1379,17.0753C63.1379,16.0668 62.4746,15.3945 61.3157,15.3945H59.7412V20.5896ZM62.3302,17.0761C62.3302,17.7102 62.024,18.031 61.2878,18.031H60.5225V16.1211H61.2878C62.0167,16.1211 62.3302,16.4343 62.3302,17.0761Z" /> + <path + android:fillColor="#ffffff" + android:pathData="M25.1113,7.8824C25.1113,5.4574 26.9226,3.6719 29.2191,3.6719C30.7107,3.6719 31.7406,4.263 32.439,5.2644L31.4683,5.9641C30.9356,5.2282 30.249,4.8422 29.1835,4.8422C27.5855,4.8422 26.4253,6.1451 26.4253,7.8824C26.4253,9.6559 27.6091,10.9227 29.2309,10.9227C30.2726,10.9227 31.0422,10.5246 31.6459,9.7283L32.6284,10.416C31.7998,11.538 30.7462,12.093 29.1835,12.093C26.8871,12.093 25.1113,10.3074 25.1113,7.8824Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M37.909,3.6719C35.6006,3.6719 33.7539,5.4574 33.7539,7.8824C33.7539,10.3074 35.6006,12.093 37.909,12.093C40.2174,12.093 42.0641,10.3074 42.0641,7.8824C42.0641,5.4574 40.2174,3.6719 37.909,3.6719ZM37.9085,4.8438C39.5777,4.8438 40.7496,6.1467 40.7496,7.884C40.7496,9.6213 39.5777,10.9243 37.9085,10.9243C36.2394,10.9243 35.0674,9.6213 35.0674,7.884C35.0674,6.1467 36.2394,4.8438 37.9085,4.8438Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M43.8994,11.9852H45.1661V8.957H46.4801H46.634L48.4334,11.9852H49.8184L47.8769,8.7277C48.8831,8.3537 49.4396,7.5333 49.4396,6.3872C49.4396,4.8309 48.3623,3.7813 46.4801,3.7813H43.8994V11.9852ZM48.1244,6.3858C48.1244,7.363 47.6272,7.8456 46.4316,7.8456H45.165V4.9259H46.4316C47.6154,4.9259 48.1244,5.3964 48.1244,6.3858Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M55.2147,3.6719C52.9063,3.6719 51.0596,5.4574 51.0596,7.8824C51.0596,10.3074 52.9063,12.093 55.2147,12.093C57.5231,12.093 59.3698,10.3074 59.3698,7.8824C59.3698,5.4574 57.5231,3.6719 55.2147,3.6719ZM55.2161,4.8438C56.8853,4.8438 58.0573,6.1467 58.0573,7.884C58.0573,9.6213 56.8853,10.9243 55.2161,10.9243C53.547,10.9243 52.375,9.6213 52.375,7.884C52.375,6.1467 53.547,4.8438 55.2161,4.8438Z" /> + <path + android:fillColor="#ffffff" + android:pathData="M62.3752,6.5919V11.9848H61.1914V3.6602H61.2861L66.4474,9.1737V3.7808H67.6312V12.1054H67.5365L62.3752,6.5919Z" /> + <path + android:fillColor="#ffffff" + android:fillType="evenOdd" + android:pathData="M70.7672,10.45H74.0345L74.662,11.9822H75.9996L72.4601,3.6094H72.3891L68.8613,11.9822H70.1398L70.7672,10.45ZM73.5725,9.3128H71.2285L72.4123,6.4414L73.5725,9.3128Z" /> + <path + android:fillColor="#ffffff" + android:pathData="M12.8401,16.6805V18.8725C13.2442,19.0159 13.5342,19.4012 13.5342,19.8554C13.5342,20.4317 13.0681,20.8989 12.4931,20.8989C11.9181,20.8989 11.452,20.4317 11.452,19.8554C11.452,19.4012 11.742,19.0159 12.1461,18.8725V16.6805C11.257,16.6069 10.4474,16.2539 9.8047,15.7086L8.2584,17.2584C8.4429,17.6462 8.3762,18.1242 8.0558,18.4453C7.6492,18.8529 6.99,18.8529 6.5834,18.4453C6.1769,18.0378 6.1769,17.3771 6.5834,16.9696C6.9038,16.6485 7.3807,16.5815 7.7676,16.7665L9.3139,15.2167C8.7698,14.5725 8.4177,13.761 8.3442,12.8698H6.1572C6.0142,13.2749 5.6298,13.5655 5.1767,13.5655C4.6017,13.5655 4.1356,13.0983 4.1356,12.522C4.1356,11.9457 4.6017,11.4785 5.1767,11.4785C5.6298,11.4785 6.0142,11.7692 6.1572,12.1742H8.3442C8.4177,11.283 8.7698,10.4716 9.3139,9.8274L7.7676,8.2775C7.3807,8.4625 6.9038,8.3955 6.5834,8.0744C6.1769,7.6669 6.1769,7.0062 6.5834,6.5987C6.99,6.1912 7.6492,6.1912 8.0558,6.5987C8.3762,6.9198 8.4429,7.3978 8.2584,7.7856L9.8047,9.3354C10.4474,8.7901 11.257,8.4371 12.1461,8.3636V6.1715C11.742,6.0281 11.452,5.6428 11.452,5.1887C11.452,4.6123 11.9181,4.1452 12.4931,4.1452C13.0681,4.1452 13.5342,4.6123 13.5342,5.1887C13.5342,5.6428 13.2442,6.0281 12.8401,6.1715V8.3636C13.8514,8.4473 14.76,8.8933 15.437,9.5713L21.327,3.6676C19.0662,1.4016 15.943,0 12.4931,0C5.5933,0 0,5.6063 0,12.522C0,19.4377 5.5933,25.044 12.4931,25.044C15.943,25.044 19.0662,23.6424 21.327,21.3764L15.437,15.4727C14.76,16.1508 13.8514,16.5968 12.8401,16.6805Z" /> +</vector> diff --git a/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml b/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml index b5b111f19..09b1a0830 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_confirm_check_in.xml @@ -4,51 +4,262 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.eventregistration.attendee.confirm.ConfirmCheckInFragment"> + android:background="@drawable/trace_location_gradient_background"> - <androidx.appcompat.widget.Toolbar - android:id="@+id/toolbar" - style="@style/CWAToolbar.Close" + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/coordinator_layout" android:layout_width="0dp" - android:layout_height="wrap_content" + android:layout_height="0dp" + android:layout_marginBottom="@dimen/spacing_small" + android:nestedScrollingEnabled="true" + app:layout_constraintBottom_toTopOf="@id/confirm_checkin_confirm_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent"> - <!-- TODO implement actual UI --> - <LinearLayout - style="@style/Card" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:orientation="vertical" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/toolbar"> - <TextView - android:id="@+id/eventGuid" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - <TextView - android:id="@+id/startTime" + <com.google.android.material.appbar.AppBarLayout + android:id="@+id/appBarLayout" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content"> - <TextView - android:id="@+id/endTime" - 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:collapsedTitleTextAppearance="@style/headline5" + app:expandedTitleTextAppearance="@style/headline5" + app:layout_scrollFlags="scroll|exitUntilCollapsed"> - <TextView - android:id="@+id/description" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <ImageView + android:id="@+id/expandedImage" + android:layout_width="match_parent" + android:layout_height="270dp" + app:layout_collapseMode="parallax" + app:srcCompat="@drawable/trace_location_view_cardhighlight_gradient_all_corners" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_collapseMode="parallax"> + + <TextView + android:id="@+id/title" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="110dp" + android:layout_marginBottom="12dp" + android:gravity="start" + android:text="@string/confirm_checkin_title_text" + android:textColor="@color/colorStableLight" + android:textSize="20sp" + tools:text="Einchecken für:" /> + + </LinearLayout> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:fitsSystemWindows="true" + app:layout_collapseMode="pin" + app:layout_scrollFlags="scroll|enterAlways" + app:navigationIcon="@drawable/ic_close" + app:navigationIconTint="@color/colorStableLight" + app:titleTextColor="@color/colorAccentTintButton"> - <com.google.android.material.button.MaterialButton - android:id="@+id/confirmButton" + <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" + app:srcCompat="@drawable/ic_cwa_logo_white" /> + + <TextView + android:id="@+id/confirm_checkin_title" + style="@style/headline6" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_huge" + android:layout_marginBottom="@dimen/spacing_normal" + android:text="@string/confirm_checkin_title_text" + android:textColor="@color/colorStableLight" + tools:text="Hallo" /> + + </LinearLayout> + + </com.google.android.material.appbar.MaterialToolbar> + + </com.google.android.material.appbar.CollapsingToolbarLayout> + + </com.google.android.material.appbar.AppBarLayout> + + <androidx.core.widget.NestedScrollView + android:id="@+id/nested_scroll_view" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="Confirm" /> - </LinearLayout> + app:behavior_overlapTop="140dp" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/confirm_checkin_info_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="24dp" + android:layout_marginBottom="@dimen/spacing_tiny" + android:orientation="vertical"> + + <TextView + android:id="@+id/confirm_checkin_info_card_header" + style="@style/subtitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Vereinsaktivität" /> + + <TextView + android:id="@+id/confirm_checkin_info_card_title" + style="@style/headline5Bold" + android:layout_width="276dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + tools:text="Jahrestreffen der deutschen SAP Anwendergruppe" /> + + <TextView + android:id="@+id/confirm_checkin_info_card_address" + style="@style/subtitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + tools:text="Hauptstr 3, 69115 Heidelberg" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/confirm_checkin_event_in_future_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:visibility="gone"> + + <TextView + android:id="@+id/confirm_checkin_event_in_future_card_text" + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:text="@string/confirm_checkin_event_in_future_card_text" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/confirm_checkin_event_in_past_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:visibility="gone"> + + <TextView + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/confirm_checkin_event_in_past_card_text" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/confirm_checkin_settings_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_tiny" + android:layout_marginBottom="24dp" + android:orientation="vertical"> + + <com.google.android.material.switchmaterial.SwitchMaterial + android:id="@+id/confirm_checkin_settings_card_checkout_toggle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/confirm_checkin_settings_card_checkout_toggle_label" + android:textSize="14sp" + android:theme="@style/switchBase" /> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginVertical="@dimen/spacing_small" + android:background="?android:attr/listDivider" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + style="@style/body2" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_normal" + android:text="@string/confirm_checkin_settings_card_checkout_time_label" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toStartOf="@id/confirm_checkin_settings_card_checkout_time" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/confirm_checkin_settings_card_checkout_time" + style="@style/body2Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/spacing_mega_tiny" + app:layout_constraintEnd_toStartOf="@id/confirm_checkin_settings_card_checkout_time_tag" + app:layout_constraintTop_toTopOf="parent" + tools:text="03:00" /> + + <TextView + android:id="@+id/confirm_checkin_settings_card_checkout_time_tag" + style="@style/body2Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/confirm_checkin_settings_card_checkout_time_tag" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + </LinearLayout> + + </LinearLayout> + + </androidx.core.widget.NestedScrollView> + + </androidx.coordinatorlayout.widget.CoordinatorLayout> + + <Button + android:id="@+id/confirm_checkin_confirm_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="@dimen/spacing_small" + android:text="@string/confirm_checkin_confirm_button_text" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml b/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml new file mode 100644 index 000000000..15edd5621 --- /dev/null +++ b/Corona-Warn-App/src/main/res/layout/fragment_edit_check_in.xml @@ -0,0 +1,256 @@ +<?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: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="@dimen/spacing_small" + android:nestedScrollingEnabled="true" + app:layout_constraintBottom_toTopOf="@id/edit_checkin_confirm_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:collapsedTitleTextAppearance="@style/headline5" + app:expandedTitleTextAppearance="@style/headline5" + app:layout_scrollFlags="scroll|exitUntilCollapsed"> + + <ImageView + android:id="@+id/expandedImage" + android:layout_width="match_parent" + android:layout_height="270dp" + app:layout_collapseMode="parallax" + app:srcCompat="@drawable/trace_location_view_cardhighlight_gradient_all_corners" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_collapseMode="parallax"> + + <TextView + android:id="@+id/title" + style="@style/headline6" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="110dp" + android:layout_marginBottom="12dp" + android:gravity="start" + android:textSize="20sp" + android:text="@string/edit_checkin_title_text" + android:textColor="@color/colorStableLight" + tools:text="Aufenthaltsdauer anpassen für:" /> + + + </LinearLayout> + + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:fitsSystemWindows="true" + app:layout_collapseMode="pin" + app:layout_scrollFlags="scroll|enterAlways" + app:navigationIcon="@drawable/ic_close" + app:navigationIconTint="@color/colorStableLight" + 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" + 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.core.widget.NestedScrollView + android:layout_width="match_parent" + android:layout_height="match_parent" + app:behavior_overlapTop="140dp" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/edit_checkin_info_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="24dp" + android:layout_marginBottom="@dimen/spacing_tiny" + android:orientation="vertical"> + + <TextView + android:id="@+id/edit_checkin_info_card_header" + style="@style/subtitleMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Vereinsaktivität" /> + + <TextView + android:id="@+id/edit_checkin_info_card_title" + style="@style/headline5Bold" + android:layout_width="276dp" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + tools:text="Jahrestreffen der deutschen SAP Anwendergruppe" /> + + <TextView + android:id="@+id/edit_checkin_info_card_address" + style="@style/subtitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/spacing_small" + tools:text="Hauptstr 3, 69115 Heidelberg" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/edit_checkin_edit_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + style="@style/body2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/edit_checkin_edit_card_checkin_time_label" /> + + <Space + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1" /> + + <TextView + android:id="@+id/edit_checkin_edit_card_checkin_date" + style="@style/body2Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Do., 21.01.21" /> + + <TextView + android:id="@+id/edit_checkin_edit_card_checkin_time" + style="@style/body2Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_tiny" + tools:text="18:00" /> + </LinearLayout> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginVertical="@dimen/spacing_small" + android:background="?android:attr/listDivider" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + style="@style/body2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/edit_checkin_edit_card_checkout_time_label" /> + + <Space + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1" /> + + <TextView + android:id="@+id/edit_checkin_edit_card_checkout_date" + style="@style/body2Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="Do., 21.01.21" /> + + <TextView + android:id="@+id/edit_checkin_edit_card_checkout_time" + style="@style/body2Medium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/spacing_tiny" + tools:text="18:00" /> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:id="@+id/edit_checkin_duration_edit_hint_card" + style="@style/Card.NoElevation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="24dp" + android:layout_marginHorizontal="@dimen/spacing_normal" + android:layout_marginTop="@dimen/spacing_tiny"> + + <TextView + style="@style/body2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/edit_checkin_duration_edit_hint_card_text" /> + </LinearLayout> + + </LinearLayout> + + </androidx.core.widget.NestedScrollView> + + </androidx.coordinatorlayout.widget.CoordinatorLayout> + + <Button + android:id="@+id/edit_checkin_confirm_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="@dimen/spacing_small" + android:text="@string/edit_checkin_confirm_button_text" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_qr_code_detail_fragment.xml b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_qr_code_detail_fragment.xml index ee90c3a64..3d6748009 100644 --- a/Corona-Warn-App/src/main/res/layout/trace_location_organizer_qr_code_detail_fragment.xml +++ b/Corona-Warn-App/src/main/res/layout/trace_location_organizer_qr_code_detail_fragment.xml @@ -94,7 +94,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="72dp" - android:src="@drawable/ic_corona_warn_app_icon_white" /> + android:src="@drawable/ic_cwa_logo_white" /> </LinearLayout> 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 193d04ffb..bcfaeb488 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 @@ -11,8 +11,13 @@ tools:layout="@layout/fragment_confirm_check_in"> <argument android:name="verifiedTraceLocation" - app:argType="de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation" - app:nullable="true" /> + app:argType="de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation" /> + </fragment> + <fragment + android:id="@+id/editCheckInFragment" + android:name="de.rki.coronawarnapp.ui.eventregistration.attendee.edit.EditCheckInFragment" + android:label="EditCheckInFragment" + tools:layout="@layout/fragment_edit_check_in"> <argument android:name="editCheckInId" app:argType="long" /> @@ -40,6 +45,9 @@ android:defaultValue="@null" app:argType="string" app:nullable="true" /> + <action + android:id="@+id/action_checkInsFragment_to_editCheckInFragment" + app:destination="@id/editCheckInFragment" /> <action android:id="@+id/action_checkInsFragment_to_qrCodeDetailFragment" app:destination="@id/qrCodeDetailFragment" /> diff --git a/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml index f73789641..27140c9d9 100644 --- a/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/event_registration_strings.xml @@ -203,6 +203,34 @@ <!-- XBUT: Event organiser list item: menu: clear button --> <string name="trace_location_organizer_list_item_menu_clear_btn">"Löschen"</string> + <!-- Trace Location Checkin Confirmation --> + <!-- XHED: Checkin Confirm: title for screen --> + <string name="confirm_checkin_title_text">"Einchecken für:"</string> + <!-- XTXT: Checkin Confirm: text for event is in future info card --> + <string name="confirm_checkin_event_in_future_card_text">"Das Event beginnt erst am %1$s um %2$s Uhr. Wollen Sie jetzt bereits einchecken?"</string> + <!-- XTXT: Checkin Confirm: text for event is in past info card --> + <string name="confirm_checkin_event_in_past_card_text">"Das Event ist beendet. Wollen Sie nachträglich einchecken?"</string> + <!-- XTXT: Checkin Confirm: label for save to contact diary toggle --> + <string name="confirm_checkin_settings_card_checkout_toggle_label">"Nach dem Auschecken in mein Kontakt-Tagebuch eintragen?"</string> + <!-- XTXT: Checkin Confirm: label for checkout delay selection --> + <string name="confirm_checkin_settings_card_checkout_time_label">"Automatisch auschecken nach"</string> + <!-- XTXT: Checkin Confirm: time length label for checkout delay selection --> + <string name="confirm_checkin_settings_card_checkout_time_tag">"Std"</string> + <!-- XBUT: Checkin Confirm: Checkin Button --> + <string name="confirm_checkin_confirm_button_text">"Einchecken"</string> + + <!-- Trace Location Checkin Editing --> + <!-- XHED: Checkin Edit: title for screen --> + <string name="edit_checkin_title_text">"Aufenthaltsdauer anpassen für:"</string> + <!-- XTXT: Checkin Edit: label for checkout time --> + <string name="edit_checkin_edit_card_checkout_time_label">"Ausgecheckt"</string> + <!-- XTXT: Checkin Edit: label for checkin time --> + <string name="edit_checkin_edit_card_checkin_time_label">"Eingecheckt"</string> + <!-- XTXT: Checkin Edit: hint for unchanged contact diary checkin duration --> + <string name="edit_checkin_duration_edit_hint_card_text">"Die Aufenthaltsdauer wird nicht automatisch in Ihrem Kontakt-Tagebuch angepasst."</string> + <!-- XBUT: Checkin Edit: Save Button --> + <string name="edit_checkin_confirm_button_text">"Speichern"</string> + <!-- Organizer Flow: Event Detail Screen--> <!-- XTXT: Organizer Flow : Accessibility description for qr-code illustration --> <string name="trace_location_event_detail_qr_code_accessibility">"QR-Code"</string> diff --git a/Corona-Warn-App/src/main/res/values/dimens.xml b/Corona-Warn-App/src/main/res/values/dimens.xml index ca2c1a9e2..79e9dae77 100644 --- a/Corona-Warn-App/src/main/res/values/dimens.xml +++ b/Corona-Warn-App/src/main/res/values/dimens.xml @@ -31,6 +31,7 @@ <!-- elevation --> <dimen name="elevation_strong">10dp</dimen> <dimen name="elevation_weak">4dp</dimen> + <dimen name="elevation_none">0dp</dimen> <!-- default spacing for guidelines --> <dimen name="guideline_card">12dp</dimen> diff --git a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml index e2115b054..30ec57b3d 100644 --- a/Corona-Warn-App/src/main/res/values/event_registration_strings.xml +++ b/Corona-Warn-App/src/main/res/values/event_registration_strings.xml @@ -203,6 +203,35 @@ <!-- XBUT: Event organiser list item: menu: clear button --> <string name="trace_location_organizer_list_item_menu_clear_btn">"Delete"</string> + + <!-- Trace Location Checkin Confirmation --> + <!-- XHED: Checkin Confirm: title for screen --> + <string name="confirm_checkin_title_text">"Einchecken für:"</string> + <!-- XTXT: Checkin Confirm: text for event is in future info card --> + <string name="confirm_checkin_event_in_future_card_text">"Das Event beginnt erst am %1$s um %2$s Uhr. Wollen Sie jetzt bereits einchecken?"</string> + <!-- XTXT: Checkin Confirm: text for event is in past info card --> + <string name="confirm_checkin_event_in_past_card_text">"Das Event ist beendet. Wollen Sie nachträglich einchecken?"</string> + <!-- XTXT: Checkin Confirm: label for save to contact diary toggle --> + <string name="confirm_checkin_settings_card_checkout_toggle_label">"Nach dem Auschecken in mein Kontakt-Tagebuch eintragen?"</string> + <!-- XTXT: Checkin Confirm: label for checkout delay selection --> + <string name="confirm_checkin_settings_card_checkout_time_label">"Automatisch auschecken nach"</string> + <!-- XTXT: Checkin Confirm: time length label for checkout delay selection --> + <string name="confirm_checkin_settings_card_checkout_time_tag">"Std"</string> + <!-- XBUT: Checkin Confirm: Checkin Button --> + <string name="confirm_checkin_confirm_button_text">"Einchecken"</string> + + <!-- Trace Location Checkin Editing --> + <!-- XHED: Checkin Edit: title for screen --> + <string name="edit_checkin_title_text">"Aufenthaltsdauer anpassen für:"</string> + <!-- XTXT: Checkin Edit: label for checkout time --> + <string name="edit_checkin_edit_card_checkout_time_label">"Ausgecheckt"</string> + <!-- XTXT: Checkin Edit: label for checkin time --> + <string name="edit_checkin_edit_card_checkin_time_label">"Eingecheckt"</string> + <!-- XTXT: Checkin Edit: hint for unchanged contact diary checkin duration --> + <string name="edit_checkin_duration_edit_hint_card_text">"Die Aufenthaltsdauer wird nicht automatisch in Ihrem Kontakt-Tagebuch angepasst."</string> + <!-- XBUT: Checkin Edit: Save Button --> + <string name="edit_checkin_confirm_button_text">"Speichern"</string> + <!-- Organizer Flow: Event Detail Screen--> <!-- XTXT: Organizer Flow : Accessibility description for qr-code illustration --> <string name="trace_location_event_detail_qr_code_accessibility">"QR Code"</string> diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml index dfb4d908e..0c9467119 100644 --- a/Corona-Warn-App/src/main/res/values/styles.xml +++ b/Corona-Warn-App/src/main/res/values/styles.xml @@ -207,6 +207,11 @@ <item name="android:elevation">@dimen/elevation_strong</item> </style> + <style name="Card.NoElevation"> + <item name="android:elevation">@dimen/elevation_none</item> + </style> + + <style name="Card.NoPadding"> <item name="android:padding">@dimen/no_padding</item> </style> diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt index ad53c3742..054e7b947 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/eventregistration/attendee/confirm/ConfirmCheckInViewModelTest.kt @@ -1,11 +1,14 @@ package de.rki.coronawarnapp.eventregistration.attendee.confirm import de.rki.coronawarnapp.eventregistration.checkins.CheckInRepository +import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.eventregistration.checkins.qrcode.VerifiedTraceLocation import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInNavigation import de.rki.coronawarnapp.ui.eventregistration.attendee.confirm.ConfirmCheckInViewModel +import de.rki.coronawarnapp.util.TimeStamper import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations +import io.mockk.every import io.mockk.impl.annotations.MockK import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -17,18 +20,24 @@ import testhelpers.extensions.getOrAwaitValue @ExtendWith(InstantExecutorExtension::class) class ConfirmCheckInViewModelTest : BaseTest() { + @MockK lateinit var traceLocation: TraceLocation @MockK lateinit var verifiedTraceLocation: VerifiedTraceLocation @MockK lateinit var checkInRepository: CheckInRepository + @MockK lateinit var timeStamper: TimeStamper private lateinit var viewModel: ConfirmCheckInViewModel @BeforeEach fun setUp() { MockKAnnotations.init(this) + + every { verifiedTraceLocation.traceLocation } returns traceLocation + every { traceLocation.defaultCheckInLengthInMinutes } returns 10 + viewModel = ConfirmCheckInViewModel( verifiedTraceLocation = verifiedTraceLocation, checkInRepository = checkInRepository, - editCheckInId = null + timeStamper = timeStamper ) } -- GitLab