Skip to content
Snippets Groups Projects
Unverified Commit 5c6dfba8 authored by Matthias Urhahn's avatar Matthias Urhahn Committed by GitHub
Browse files

CheckIn cards & interaction (EXPOSUREAPP-5410) (#2644)


* Fix duplicate fragment on navstack.

* Active checkin card, first draft.

* CheckIn cards, second pass.

* CheckIn cards, third pass.

* CheckIn cards, fourth pass.

* Fix textcolor on gradient in nightmode.

Co-authored-by: default avatarRalf Gehrer <ralfgehrer@users.noreply.github.com>
parent 3a449caf
No related branches found
No related tags found
No related merge requests found
Showing
with 612 additions and 21 deletions
package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.viewbinding.ViewBinding
import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.ActiveCheckInVH
import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.CheckInsItem
import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.PastCheckInVH
import de.rki.coronawarnapp.util.lists.BindableVH
import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffUtilAdapter
import de.rki.coronawarnapp.util.lists.diffutil.AsyncDiffer
import de.rki.coronawarnapp.util.lists.modular.ModularAdapter
import de.rki.coronawarnapp.util.lists.modular.mods.DataBinderMod
import de.rki.coronawarnapp.util.lists.modular.mods.StableIdMod
import de.rki.coronawarnapp.util.lists.modular.mods.TypedVHCreatorMod
class CheckInsAdapter :
ModularAdapter<CheckInsAdapter.ItemVH<CheckInsItem, ViewBinding>>(),
AsyncDiffUtilAdapter<CheckInsItem> {
override val asyncDiffer: AsyncDiffer<CheckInsItem> = AsyncDiffer(adapter = this)
init {
modules.addAll(
listOf(
StableIdMod(data),
DataBinderMod<CheckInsItem, ItemVH<CheckInsItem, ViewBinding>>(data),
TypedVHCreatorMod({ data[it] is ActiveCheckInVH.Item }) { ActiveCheckInVH(it) },
TypedVHCreatorMod({ data[it] is PastCheckInVH.Item }) { PastCheckInVH(it) },
)
)
}
override fun getItemCount(): Int = data.size
abstract class ItemVH<Item : CheckInsItem, VB : ViewBinding>(
@LayoutRes layoutRes: Int,
parent: ViewGroup
) : ModularAdapter.VH(layoutRes, parent), BindableVH<Item, VB>
}
......@@ -6,15 +6,20 @@ import android.view.View
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.core.net.toUri
import androidx.core.view.isGone
import androidx.fragment.app.Fragment
import androidx.navigation.NavOptions
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator
import com.google.android.material.transition.Hold
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsFragmentBinding
import de.rki.coronawarnapp.util.CWADebug
import de.rki.coronawarnapp.util.di.AutoInject
import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator
import de.rki.coronawarnapp.util.lists.diffutil.update
import de.rki.coronawarnapp.util.ui.doNavigate
import de.rki.coronawarnapp.util.ui.observe2
import de.rki.coronawarnapp.util.ui.viewBindingLazy
......@@ -35,6 +40,7 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
}
)
private val binding: TraceLocationAttendeeCheckinsFragmentBinding by viewBindingLazy()
private val checkInsAdapter = CheckInsAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -45,6 +51,20 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
super.onViewCreated(view, savedInstanceState)
setupMenu(binding.toolbar)
binding.checkInsList.apply {
adapter = checkInsAdapter
addItemDecoration(TopBottomPaddingDecorator(topPadding = R.dimen.spacing_tiny))
itemAnimator = DefaultItemAnimator()
}
viewModel.checkins.observe2(this) {
checkInsAdapter.update(it)
binding.apply {
checkInsList.isGone = it.isEmpty()
emptyListInfoContainer.isGone = it.isNotEmpty()
}
}
binding.scanCheckinQrcodeFab.apply {
setOnClickListener {
findNavController().navigate(
......@@ -56,22 +76,26 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
}
if (CWADebug.isDeviceForTestersBuild) {
setOnLongClickListener {
findNavController().navigate(createCheckInUri(DEBUG_CHECKINS.random()))
findNavController().navigate(
createCheckInUri(DEBUG_CHECKINS.random()),
NavOptions.Builder().apply {
setLaunchSingleTop(true)
}.build()
)
true
}
}
}
viewModel.verifyResult.observe2(this) {
viewModel.confirmationEvent.observe2(this) {
doNavigate(
CheckInsFragmentDirections
.actionCheckInsFragmentToConfirmCheckInFragment(it.verifiedTraceLocation)
CheckInsFragmentDirections.actionCheckInsFragmentToConfirmCheckInFragment(it.verifiedTraceLocation)
)
}
}
private fun setupMenu(toolbar: Toolbar) = toolbar.apply {
inflateMenu(R.menu.menu_trace_location_my_check_ins)
inflateMenu(R.menu.menu_trace_location_attendee_checkins)
setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_information -> {
......
package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
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.qrcode.QRCodeUriParser
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocationQRCodeVerifier
import de.rki.coronawarnapp.eventregistration.checkins.qrcode.TraceLocationVerifyResult
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.ActiveCheckInVH
import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items.PastCheckInVH
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import org.joda.time.Duration
import org.joda.time.Instant
import timber.log.Timber
class CheckInsViewModel @AssistedInject constructor(
......@@ -24,8 +31,28 @@ class CheckInsViewModel @AssistedInject constructor(
private val qrCodeUriParser: QRCodeUriParser
) : CWAViewModel(dispatcherProvider) {
private val verifyResultData = MutableLiveData<TraceLocationVerifyResult>()
val verifyResult: LiveData<TraceLocationVerifyResult> = verifyResultData
val confirmationEvent = SingleLiveEvent<TraceLocationVerifyResult>()
val checkins = FAKE_CHECKIN_SOURCE
.map { checkins -> checkins.sortedBy { it.checkInEnd } }
.map { checkins ->
checkins.map { checkin ->
when {
checkin.checkInEnd == null -> ActiveCheckInVH.Item(
checkin = checkin,
onCardClicked = { /* TODO */ },
onRemoveItem = { /* TODO */ },
onCheckout = { /* TODO */ }
)
else -> PastCheckInVH.Item(
checkin = checkin,
onCardClicked = { /* TODO */ },
onRemoveItem = { /* TODO */ }
)
}
}
}
.asLiveData(context = dispatcherProvider.Default)
init {
deepLink?.let {
......@@ -47,7 +74,7 @@ class CheckInsViewModel @AssistedInject constructor(
val verifyResult = traceLocationQRCodeVerifier.verify(signedTraceLocation.toByteArray())
Timber.i("verifyResult: $verifyResult")
verifyResultData.postValue(verifyResult)
confirmationEvent.postValue(verifyResult)
} catch (e: Exception) {
Timber.d(e, "TraceLocation verification failed")
e.report(ExceptionCategory.INTERNAL)
......@@ -66,3 +93,42 @@ class CheckInsViewModel @AssistedInject constructor(
): CheckInsViewModel
}
}
private val FAKE_CHECKINS = listOf(
CheckIn(
id = 1,
guid = "testGuid2",
version = 1,
type = 1,
description = "Jahrestreffen der deutschen SAP Anwendergruppe",
address = "Hauptstr. 3, 69115 Heidelberg",
traceLocationStart = null,
traceLocationEnd = null,
defaultCheckInLengthInMinutes = 3 * 60,
signature = "Signature",
checkInStart = Instant.now().minus(Duration.standardHours(2)),
checkInEnd = null,
targetCheckInEnd = Instant.now().plus(Duration.standardHours(1)),
createJournalEntry = true
),
CheckIn(
id = 2,
guid = "testGuid1",
version = 1,
type = 2,
description = "CWA Launch Party",
address = "At home! Do you want the 'rona?",
traceLocationStart = Instant.parse("2021-01-01T12:00:00.000Z"),
traceLocationEnd = Instant.parse("2021-01-01T15:00:00.000Z"),
defaultCheckInLengthInMinutes = 15,
signature = "Signature",
checkInStart = Instant.parse("2021-01-01T12:30:00.000Z"),
checkInEnd = Instant.parse("2021-01-01T14:00:00.000Z"),
targetCheckInEnd = Instant.parse("2021-01-01T12:45:00.000Z"),
createJournalEntry = true
)
)
private val FAKE_CHECKIN_SOURCE = flow {
emit(FAKE_CHECKINS)
}
package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items
import android.view.ViewGroup
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.contactdiary.util.getLocale
import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsItemActiveBinding
import de.rki.coronawarnapp.eventregistration.checkins.CheckIn
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone
import org.joda.time.Duration
import org.joda.time.Instant
import org.joda.time.PeriodType
import org.joda.time.format.DateTimeFormat
import org.joda.time.format.PeriodFormat
import org.joda.time.format.PeriodFormatterBuilder
class ActiveCheckInVH(parent: ViewGroup) :
BaseCheckInVH<ActiveCheckInVH.Item, TraceLocationAttendeeCheckinsItemActiveBinding>(
layoutRes = R.layout.trace_location_attendee_checkins_item_active,
parent = parent
) {
override val viewBinding: Lazy<TraceLocationAttendeeCheckinsItemActiveBinding> = lazy {
TraceLocationAttendeeCheckinsItemActiveBinding.bind(itemView)
}
private val hourPeriodFormatter by lazy {
PeriodFormat.wordBased(context.getLocale())
}
override val onBindData: TraceLocationAttendeeCheckinsItemActiveBinding.(
item: Item,
payloads: List<Any>
) -> Unit = { item, _ ->
val checkInStartUserTZ = item.checkin.checkInStart.toUserTimeZone()
val checkinDuration = Duration(checkInStartUserTZ, Instant.now())
highlightDuration.text = highlightDurationForamtter.print(checkinDuration.toPeriod())
description.text = item.checkin.description
address.text = item.checkin.address
val startDate = checkInStartUserTZ.toLocalDate()
traceLocationCardHighlightView.setCaption(startDate.toString(DateTimeFormat.mediumDate()))
val autoCheckoutText = item.checkin.defaultCheckInLengthInMinutes?.let { checkoutLength ->
val checkoutAt = checkInStartUserTZ.plus(Duration.standardMinutes(checkoutLength.toLong()))
val checkoutIn = Duration(Instant.now(), checkoutAt).let {
val periodType = when {
it.isLongerThan(Duration.standardHours(1)) -> PeriodType.hours()
it.isLongerThan(Duration.standardDays(1)) -> PeriodType.days()
else -> PeriodType.minutes()
}
it.toPeriod(periodType)
}
context.getString(
R.string.trace_location_checkins_card_automatic_checkout_info,
checkInStartUserTZ.toLocalTime().toString("HH:mm"),
hourPeriodFormatter.print(checkoutIn)
)
}
checkoutInfo.text = autoCheckoutText ?: checkInStartUserTZ.toLocalTime().toString("HH:mm")
menuAction.setupMenu(R.menu.menu_trace_location_attendee_checkin_item) {
when (it.itemId) {
R.id.menu_remove_item -> item.onRemoveItem(item.checkin).let { true }
else -> false
}
}
}
data class Item(
val checkin: CheckIn,
val onCardClicked: (CheckIn) -> Unit,
val onRemoveItem: (CheckIn) -> Unit,
val onCheckout: (CheckIn) -> Unit,
) : CheckInsItem {
override val stableId: Long = checkin.id
}
companion object {
private val highlightDurationForamtter = PeriodFormatterBuilder().apply {
printZeroAlways()
minimumPrintedDigits(2)
appendHours()
appendSuffix(":")
appendMinutes()
}.toFormatter()
}
}
package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items
import android.view.Gravity
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.annotation.MenuRes
import androidx.appcompat.widget.PopupMenu
import androidx.viewbinding.ViewBinding
import de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.CheckInsAdapter
abstract class BaseCheckInVH<ItemT : CheckInsItem, BindingT : ViewBinding>(
parent: ViewGroup,
@LayoutRes layoutRes: Int
) : CheckInsAdapter.ItemVH<ItemT, BindingT>(
layoutRes = layoutRes,
parent = parent
) {
companion object {
fun View.setupMenu(@MenuRes menuRes: Int, onMenuAction: (MenuItem) -> Boolean) {
val menu = PopupMenu(context, this, Gravity.TOP or Gravity.END).apply {
inflate(menuRes)
setOnMenuItemClickListener { onMenuAction(it) }
}
setOnClickListener { menu.show() }
}
}
}
package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items
import de.rki.coronawarnapp.util.lists.HasStableId
interface CheckInsItem : HasStableId
package de.rki.coronawarnapp.ui.eventregistration.attendee.checkins.items
import android.view.ViewGroup
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.TraceLocationAttendeeCheckinsItemPastBinding
import de.rki.coronawarnapp.eventregistration.checkins.CheckIn
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone
import org.joda.time.Instant
import org.joda.time.format.DateTimeFormat
class PastCheckInVH(parent: ViewGroup) :
BaseCheckInVH<PastCheckInVH.Item, TraceLocationAttendeeCheckinsItemPastBinding>(
layoutRes = R.layout.trace_location_attendee_checkins_item_past,
parent = parent
) {
override val viewBinding: Lazy<TraceLocationAttendeeCheckinsItemPastBinding> = lazy {
TraceLocationAttendeeCheckinsItemPastBinding.bind(itemView)
}
override val onBindData: TraceLocationAttendeeCheckinsItemPastBinding.(
item: Item,
payloads: List<Any>
) -> Unit = { item, _ ->
val checkInStartUserTZ = item.checkin.checkInStart.toUserTimeZone()
val checkInEndUserTZ = (item.checkin.checkInEnd ?: Instant.EPOCH).toUserTimeZone()
description.text = item.checkin.description
address.text = item.checkin.address
checkoutInfo.text = run {
val dayFormatted = checkInStartUserTZ.toLocalDate().toString(DateTimeFormat.mediumDate())
val startTimeFormatted = checkInStartUserTZ.toLocalTime().toString(DateTimeFormat.shortTime())
val endTimeFormatted = checkInEndUserTZ.toLocalTime().toString(DateTimeFormat.shortTime())
"$dayFormatted, $startTimeFormatted - $endTimeFormatted"
}
menuAction.setupMenu(R.menu.menu_trace_location_attendee_checkin_item) {
when (it.itemId) {
R.id.menu_remove_item -> item.onRemoveItem(item.checkin).let { true }
else -> false
}
}
}
data class Item(
val checkin: CheckIn,
val onCardClicked: (CheckIn) -> Unit,
val onRemoveItem: (CheckIn) -> Unit
) : CheckInsItem {
override val stableId: Long = checkin.id
}
}
......@@ -3,12 +3,15 @@ package de.rki.coronawarnapp.ui.eventregistration.common
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.content.withStyledAttributes
import androidx.core.view.children
import androidx.core.view.isGone
import de.rki.coronawarnapp.R
import timber.log.Timber
class TraceLocationCardHighlightView @JvmOverloads constructor(
context: Context,
......@@ -17,7 +20,7 @@ class TraceLocationCardHighlightView @JvmOverloads constructor(
) : ConstraintLayout(context, attrs, defStyleAttr) {
private val captionView: TextView by lazy { findViewById(R.id.caption) }
private val containerView: ConstraintLayout by lazy { findViewById(R.id.container) }
private val containerView: ViewGroup by lazy { findViewById(R.id.container) }
init {
LayoutInflater.from(context).inflate(R.layout.trace_location_view_cardhighlight, this, true)
......@@ -26,13 +29,18 @@ class TraceLocationCardHighlightView @JvmOverloads constructor(
context.withStyledAttributes(attrs, R.styleable.TraceLocationHighlightView) {
val captionText = getText(R.styleable.TraceLocationHighlightView_android_text) ?: ""
captionView.text = captionText
setCaption(captionText.toString())
}
}
override fun onFinishInflate() {
children
.filter { it != captionView && it != containerView }
.toList()
.filter {
val filtered = it != captionView && it != containerView
Timber.v("filtered($filtered): %s", it)
filtered
}
.forEach {
removeView(it)
containerView.addView(it)
......@@ -40,7 +48,15 @@ class TraceLocationCardHighlightView @JvmOverloads constructor(
super.onFinishInflate()
}
fun setCaption(caption: String) {
fun setCaption(caption: String?) {
captionView.text = caption
captionView.isGone = caption.isNullOrBlank()
containerView.background = ContextCompat.getDrawable(
context,
if (captionView.isGone) R.drawable.trace_location_view_cardhighlight_gradient_all_corners
else R.drawable.trace_location_view_cardhighlight_gradient_top_corners
)
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#434445"
android:pathData="M16,16m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0" />
<path
android:fillColor="#007FAD"
android:pathData="M20.4444,16.9H16V21.4H20.4444V16.9ZM19.5556,7V8.8H12.4444V7H10.6667V8.8H9.7778C8.7911,8.8 8.0089,9.61 8.0089,10.6L8,23.2C8,24.19 8.7911,25 9.7778,25H22.2222C23.2,25 24,24.19 24,23.2V10.6C24,9.61 23.2,8.8 22.2222,8.8H21.3333V7H19.5556ZM22.2222,23.2H9.7778V13.3H22.2222V23.2Z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#ffffff"
android:pathData="M16,16m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0" />
<path
android:fillColor="#007FAD"
android:pathData="M20.4444,16.9H16V21.4H20.4444V16.9ZM19.5556,7V8.8H12.4444V7H10.6667V8.8H9.7778C8.7911,8.8 8.0089,9.61 8.0089,10.6L8,23.2C8,24.19 8.7911,25 9.7778,25H22.2222C23.2,25 24,24.19 24,23.2V10.6C24,9.61 23.2,8.8 22.2222,8.8H21.3333V7H19.5556ZM22.2222,23.2H9.7778V13.3H22.2222V23.2Z" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="@dimen/radius_card"
android:bottomRightRadius="@dimen/radius_card"
android:radius="0dp"
android:topLeftRadius="@dimen/radius_card"
android:topRightRadius="@dimen/radius_card" />
<gradient
android:angle="135"
android:centerColor="#6C648C"
android:endColor="#3C8CBB"
android:startColor="#A93F45" />
</shape>
<?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:id="@+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
......@@ -19,21 +20,27 @@
android:id="@+id/check_ins_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
app:layout_constraintTop_toBottomOf="@id/toolbar"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/empty_list_info_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="48dp"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
app:layout_constraintTop_toBottomOf="@id/toolbar"
tools:visibility="visible">
<ImageView
android:layout_width="wrap_content"
......@@ -42,14 +49,15 @@
android:src="@drawable/trace_location_my_check_ins_empty_illustration" />
<TextView
style="@style/headline6"
style="@style/subtitleMedium"
android:layout_width="wrap_content"
android:textStyle="bold"
android:layout_height="wrap_content"
android:layout_marginTop="36dp"
android:layout_gravity="center"
android:layout_marginTop="36dp"
android:text="@string/trace_location_checkins_empty_label" />
<TextView
style="@style/subtitleMedium"
style="@style/body2Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
......
<?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"
style="@style/contactDiaryCardRipple"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_marginHorizontal="16dp"
android:focusable="true">
<de.rki.coronawarnapp.ui.eventregistration.common.TraceLocationCardHighlightView
android:id="@+id/traceLocationCardHighlightView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/checkout_action"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="21.01.2021">
<TextView
android:id="@+id/highlight_duration_label"
style="@style/body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="@string/trace_location_checkins_card_highlight_duration_label"
android:textColor="@color/colorTextPrimary1InvertedStable"
android:textSize="13sp"
app:layout_constraintBottom_toTopOf="@+id/highlight_duration"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/highlight_duration"
style="@style/headline5Bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorTextPrimary1InvertedStable"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/highlight_duration_label"
tools:text="00:25" />
</de.rki.coronawarnapp.ui.eventregistration.common.TraceLocationCardHighlightView>
<TextView
android:id="@+id/description"
style="@style/subtitleBoldSixteen"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toStartOf="@+id/menu_action"
app:layout_constraintStart_toEndOf="@+id/traceLocationCardHighlightView"
app:layout_constraintTop_toTopOf="parent"
tools:text="Jahrestreffen der deutschen SAP Anwendergruppe" />
<TextView
android:id="@+id/address"
style="@style/body2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:textColor="@color/colorTextPrimary2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/traceLocationCardHighlightView"
app:layout_constraintTop_toBottomOf="@id/description"
tools:text="Hauptstr. 3, 69115 Heidelberg" />
<TextView
android:id="@+id/checkout_info"
style="@style/body2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toTopOf="@+id/checkout_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/traceLocationCardHighlightView"
app:layout_constraintTop_toBottomOf="@id/address"
app:layout_constraintVertical_bias="0.0"
tools:text="18:00 - Automatisch auschecken nach 3 Std." />
<ImageButton
android:id="@+id/menu_action"
style="@style/CardOverFlowButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/checkout_action"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:text="@string/trace_location_checkins_card_action_checkout"
android:textColor="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:strokeColor="@color/colorAccent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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"
style="@style/contactDiaryCardRipple"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp"
android:focusable="true">
<ImageView
android:id="@+id/traceLocationCardHighlightView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:orientation="vertical"
android:src="@drawable/ic_old_checkin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
tools:text="21.01.2021" />
<TextView
android:id="@+id/description"
style="@style/subtitleBoldSixteen"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@+id/menu_action"
app:layout_constraintStart_toEndOf="@+id/traceLocationCardHighlightView"
app:layout_constraintTop_toTopOf="parent"
tools:text="Jahrestreffen der deutschen SAP Anwendergruppe" />
<TextView
android:id="@+id/address"
style="@style/body2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:textColor="@color/colorTextPrimary2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/traceLocationCardHighlightView"
app:layout_constraintTop_toBottomOf="@id/description"
tools:text="Hauptstr. 3, 69115 Heidelberg" />
<TextView
android:id="@+id/checkout_info"
style="@style/body2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/traceLocationCardHighlightView"
app:layout_constraintTop_toBottomOf="@id/address"
tools:text="18:00 - Automatisch auschecken nach 3 Std." />
<ImageButton
android:id="@+id/menu_action"
style="@style/CardOverFlowButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -11,8 +11,8 @@
android:id="@+id/container"
android:layout_width="88dp"
android:layout_height="96dp"
android:background="@drawable/trace_location_view_cardhighlight_gradient"
android:padding="16dp"
android:background="@drawable/trace_location_view_cardhighlight_gradient_top_corners"
android:padding="8dp"
app:layout_constraintBottom_toTopOf="@+id/caption"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
......
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_remove_item"
android:title="@string/trace_location_checkins_menu_remove_item" />
</menu>
......@@ -35,6 +35,15 @@
<!-- XTXT: My checkin-ins: Confirmation dialog description when removing all/single items -->
<string name="trace_location_checkins_remove_message">Sie können dann Personen, die zur selben Zeit für diesen Ort oder Event eingecheckt waren, bei Bedarf nicht mehr warnen oder von ihnen gewarnt werden.</string>
<!-- XBUT: My check-ins card: Menu, remove item -->
<string name="trace_location_checkins_menu_remove_item">Entfernen</string>
<!-- XBUT: My check-ins card: Active event, checkout button -->
<string name="trace_location_checkins_card_action_checkout">Jetzt auschecken</string>
<!-- XTXT: My check-ins card: Active event, duration label in highlight view -->
<string name="trace_location_checkins_card_highlight_duration_label">Dauer</string>
<!-- XTXT: My check-ins card: Active event, checkin information, automatic checkout info -->
<string name="trace_location_checkins_card_automatic_checkout_info">"%1$s - Automatisch auschecken nach %2$s."</string>
<!-- XHED: Title of the category list screen of the event creation -->
<string name="tracelocation_organizer_category_title">QR-Code erstellen</string>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment