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 2e48fa57cc1300a63e91ee60e13ffef5ed702266..ae8bc05a04a7b86873b458a0f3e4d93d240ed7ed 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 09f3e8853f12012f282c8836aea66f817d8e89e8..4155d9059992f459dce2ab89167997d1dc11db11 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 2e37fe3685317abaa60534e99c88a003ab2bca96..6bf054474f391288abd994c529f42874a76bef10 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 a22c989af6286798d22c7d1ab5ec9a0a8ac8ae6b..a411d1b2ea41b78288cff2c99248ab6113d8c069 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 e0f8e2d8b0a09132b1a0143a1868d29df236660b..ba77ca1bc358fe2fcec52924c0a7b06d2e228160 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 0000000000000000000000000000000000000000..0e822c842aca62574fad8ef7c5078b89262a2f97 --- /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 0000000000000000000000000000000000000000..6a7862e259435a50b7624c3dc28decd6003f4644 --- /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 0000000000000000000000000000000000000000..05b11d1ad1c7509567aa471835f684734c526fa5 --- /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 0000000000000000000000000000000000000000..a266e7e6d8ab74f5f64edcefa1e50e96e7963c4b --- /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 9d9bc2ac3563fc669f9ec1b94c3aae0450ebfb78..31f49804d9db7fed35bad84e2e5799f301b78d1d 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 4e4ddebd4d49744d2be3964bef71a1d26cd953ad..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..c3584e118a37056c5490948d022bee10212266d5 --- /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 b5b111f19b1de861eafe5a4e015ef7416d026c45..09b1a08305859ef5c3bd2a69132f8d7cf56911e2 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 0000000000000000000000000000000000000000..15edd5621dd232084da2e2a6bb9302796dea86d0 --- /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 ee90c3a64c7e22fee55e4327c7e3d6f757b2b90b..3d67480093e2f75751b8a0ee35c49f4ac29332ba 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 193d04ffbc59c2be1a28e945d1279bc91f7dc8f8..bcfaeb48890a3b524e7563844ae0280757b5e04b 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 f7378964180663a2d7d401a2efbfa76c0504b473..27140c9d97f10cc47fe28a3486665332d44b9897 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 ca2c1a9e262b9f18b7312321e48d5c07f924ca68..79e9dae773d6b9c36433d66e9ca90ca824b522d7 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 e2115b054f028f9d8375a958e94145f6372e709b..30ec57b3dc25246ac452c6d20efa7003556a3b4a 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 dfb4d908eef3d8446e62b04dcd1f3d37d3b27789..0c94671196cdb387ebe89320c1e148377757b725 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 ad53c37420874c9275500b8f56e7ff34e64b0e25..054e7b9473651d136d6f07c03b5a4c5f5f244652 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 ) }