Location item design
This commit is contained in:
parent
53ca2b525d
commit
787f64b85f
@ -0,0 +1,69 @@
|
|||||||
|
package de.mm20.launcher2.ui.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.rounded.StarHalf
|
||||||
|
import androidx.compose.material.icons.rounded.Star
|
||||||
|
import androidx.compose.material.icons.rounded.StarOutline
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.round
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A star rating bar that displays a rating from 0 to 5 stars.
|
||||||
|
* @param rating in the range of 0..1
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun RatingBar(
|
||||||
|
rating: Float,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
tint: Color = MaterialTheme.colorScheme.primary,
|
||||||
|
starSize: Dp = 16.dp
|
||||||
|
) {
|
||||||
|
val starRating = round(rating * 10f).toInt()
|
||||||
|
val fullStars = starRating / 2
|
||||||
|
val halfStar = starRating % 2 == 1
|
||||||
|
val emptyStars = 5 - fullStars - if (halfStar) 1 else 0
|
||||||
|
val iconModifier = Modifier.size(starSize)
|
||||||
|
Row(
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
|
for (i in 0 until fullStars) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Rounded.Star,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = tint,
|
||||||
|
modifier = iconModifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (halfStar) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Rounded.StarHalf,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = tint,
|
||||||
|
modifier = iconModifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (i in 0 until emptyStars) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Rounded.StarOutline,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = tint,
|
||||||
|
modifier = iconModifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun RatingBarPreview() {
|
||||||
|
RatingBar(0.67f)
|
||||||
|
}
|
||||||
@ -30,7 +30,6 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||||
import androidx.compose.material.icons.automirrored.rounded.NavigateNext
|
import androidx.compose.material.icons.automirrored.rounded.NavigateNext
|
||||||
import androidx.compose.material.icons.rounded.BugReport
|
import androidx.compose.material.icons.rounded.BugReport
|
||||||
import androidx.compose.material.icons.rounded.FiberManualRecord
|
|
||||||
import androidx.compose.material.icons.rounded.Language
|
import androidx.compose.material.icons.rounded.Language
|
||||||
import androidx.compose.material.icons.rounded.Map
|
import androidx.compose.material.icons.rounded.Map
|
||||||
import androidx.compose.material.icons.rounded.Navigation
|
import androidx.compose.material.icons.rounded.Navigation
|
||||||
@ -41,7 +40,7 @@ import androidx.compose.material3.AssistChip
|
|||||||
import androidx.compose.material3.AssistChipDefaults
|
import androidx.compose.material3.AssistChipDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.OutlinedCard
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
@ -57,10 +56,12 @@ import androidx.compose.ui.geometry.Rect
|
|||||||
import androidx.compose.ui.graphics.TransformOrigin
|
import androidx.compose.ui.graphics.TransformOrigin
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.roundToIntRect
|
import androidx.compose.ui.unit.roundToIntRect
|
||||||
|
import androidx.compose.ui.unit.times
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import de.mm20.launcher2.i18n.R
|
import de.mm20.launcher2.i18n.R
|
||||||
import de.mm20.launcher2.ktx.tryStartActivity
|
import de.mm20.launcher2.ktx.tryStartActivity
|
||||||
@ -68,6 +69,7 @@ import de.mm20.launcher2.search.Location
|
|||||||
import de.mm20.launcher2.search.OpeningHours
|
import de.mm20.launcher2.search.OpeningHours
|
||||||
import de.mm20.launcher2.search.OpeningSchedule
|
import de.mm20.launcher2.search.OpeningSchedule
|
||||||
import de.mm20.launcher2.ui.component.DefaultToolbarAction
|
import de.mm20.launcher2.ui.component.DefaultToolbarAction
|
||||||
|
import de.mm20.launcher2.ui.component.RatingBar
|
||||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||||
import de.mm20.launcher2.ui.component.Toolbar
|
import de.mm20.launcher2.ui.component.Toolbar
|
||||||
import de.mm20.launcher2.ui.component.ToolbarAction
|
import de.mm20.launcher2.ui.component.ToolbarAction
|
||||||
@ -122,6 +124,7 @@ fun LocationItem(
|
|||||||
|
|
||||||
val imperialUnits by viewModel.imperialUnits.collectAsState()
|
val imperialUnits by viewModel.imperialUnits.collectAsState()
|
||||||
|
|
||||||
|
val showMap by viewModel.showMap.collectAsState()
|
||||||
val isUpToDate by viewModel.isUpToDate.collectAsState()
|
val isUpToDate by viewModel.isUpToDate.collectAsState()
|
||||||
|
|
||||||
val distance = userLocation?.distanceTo(location.toAndroidLocation())
|
val distance = userLocation?.distanceTo(location.toAndroidLocation())
|
||||||
@ -175,6 +178,7 @@ fun LocationItem(
|
|||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.padding(top = 2.dp)
|
||||||
.sharedElement(
|
.sharedElement(
|
||||||
rememberSharedContentState("sublabel"),
|
rememberSharedContentState("sublabel"),
|
||||||
this@AnimatedContent
|
this@AnimatedContent
|
||||||
@ -182,46 +186,36 @@ fun LocationItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box(
|
Compass(
|
||||||
modifier = Modifier
|
targetHeading = targetHeading,
|
||||||
.animateEnterExit(
|
modifier = Modifier.padding(end = 8.dp) then
|
||||||
enter = slideIn { IntOffset(it.width, 0) } + fadeIn(),
|
if (!showMap) {
|
||||||
exit = slideOut { IntOffset(it.width, 0) } + fadeOut(),
|
Modifier.sharedBounds(
|
||||||
)
|
rememberSharedContentState("compass"),
|
||||||
.padding(end = 8.dp)
|
this@AnimatedContent
|
||||||
.size(48.dp)
|
)
|
||||||
.background(
|
} else {
|
||||||
MaterialTheme.colorScheme.secondaryContainer,
|
Modifier.animateEnterExit(
|
||||||
MaterialTheme.shapes.small
|
enter = slideIn { IntOffset(it.width, 0) } + fadeIn(),
|
||||||
),
|
exit = slideOut { IntOffset(it.width, 0) } + fadeOut(),
|
||||||
contentAlignment = Alignment.Center
|
)
|
||||||
) {
|
}
|
||||||
Icon(
|
)
|
||||||
if (targetHeading != null) Icons.Rounded.Navigation else Icons.Rounded.FiberManualRecord,
|
|
||||||
null,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(20.dp)
|
|
||||||
.rotate(targetHeading ?: 0f),
|
|
||||||
tint = MaterialTheme.colorScheme.onSecondaryContainer,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val showMap by viewModel.showMap.collectAsState()
|
|
||||||
Column {
|
Column {
|
||||||
if (showMap) {
|
if (showMap) {
|
||||||
val tileServerUrl by viewModel.mapTileServerUrl.collectAsState()
|
val tileServerUrl by viewModel.mapTileServerUrl.collectAsState()
|
||||||
val shape = MaterialTheme.shapes.small
|
val shape = MaterialTheme.shapes.small
|
||||||
|
|
||||||
val applyTheming by viewModel.applyMapTheming.collectAsState()
|
val applyTheming by viewModel.applyMapTheming.collectAsState()
|
||||||
val showPositionOnMap by viewModel.showPositionOnMap.collectAsState()
|
|
||||||
MapTiles(
|
MapTiles(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.animateEnterExit(
|
.animateEnterExit(
|
||||||
enter = expandVertically(),
|
enter = expandVertically(),
|
||||||
exit = shrinkOut(),
|
exit = shrinkOut(),
|
||||||
)
|
)
|
||||||
.padding(12.dp)
|
.padding(top = 12.dp, start = 12.dp, end = 12.dp)
|
||||||
.align(Alignment.CenterHorizontally)
|
.align(Alignment.CenterHorizontally)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, shape)
|
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, shape)
|
||||||
@ -235,22 +229,29 @@ fun LocationItem(
|
|||||||
tiles = IntSize(3, 2),
|
tiles = IntSize(3, 2),
|
||||||
applyTheming = applyTheming,
|
applyTheming = applyTheming,
|
||||||
userLocation = {
|
userLocation = {
|
||||||
if (showPositionOnMap) userLocation?.let {
|
userLocation?.let {
|
||||||
UserLocation(
|
UserLocation(
|
||||||
it.latitude,
|
it.latitude,
|
||||||
it.longitude,
|
it.longitude,
|
||||||
heading = userHeading,
|
heading = userHeading,
|
||||||
)
|
)
|
||||||
} else null
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(horizontal = 12.dp),
|
modifier = Modifier.padding(
|
||||||
|
top = 12.dp,
|
||||||
|
start = 12.dp,
|
||||||
|
end = 12.dp,
|
||||||
|
bottom = 4.dp
|
||||||
|
),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Column {
|
Column(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = location.labelOverride ?: location.label,
|
text = location.labelOverride ?: location.label,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
@ -275,12 +276,32 @@ fun LocationItem(
|
|||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.padding(top = 2.dp)
|
||||||
.sharedElement(
|
.sharedElement(
|
||||||
rememberSharedContentState("sublabel"),
|
rememberSharedContentState("sublabel"),
|
||||||
this@AnimatedContent
|
this@AnimatedContent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// TODO: add rating to location
|
||||||
|
if (!showMap && false) {
|
||||||
|
RatingBar(0.66f, modifier = Modifier.padding(top = 4.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: add rating to location
|
||||||
|
if (showMap && false) {
|
||||||
|
RatingBar(0.66f)
|
||||||
|
} else {
|
||||||
|
Compass(
|
||||||
|
targetHeading = targetHeading,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.Top)
|
||||||
|
.sharedBounds(
|
||||||
|
rememberSharedContentState("compass"),
|
||||||
|
this@AnimatedContent
|
||||||
|
),
|
||||||
|
size = 56.dp,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,12 +310,11 @@ fun LocationItem(
|
|||||||
var showOpeningSchedule by remember(openingSchedule) {
|
var showOpeningSchedule by remember(openingSchedule) {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
Surface(
|
OutlinedCard(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 12.dp, end = 12.dp, top = 12.dp),
|
.padding(start = 12.dp, end = 12.dp, top = 12.dp),
|
||||||
shape = MaterialTheme.shapes.medium,
|
shape = MaterialTheme.shapes.small,
|
||||||
color = MaterialTheme.colorScheme.surfaceContainer,
|
|
||||||
onClick = {
|
onClick = {
|
||||||
if (!openingSchedule.isTwentyFourSeven) {
|
if (!openingSchedule.isTwentyFourSeven) {
|
||||||
showOpeningSchedule = true
|
showOpeningSchedule = true
|
||||||
@ -331,10 +351,11 @@ fun LocationItem(
|
|||||||
formattedTime
|
formattedTime
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val dow = currentOpeningTime.dayOfWeek.getDisplayName(
|
val dow =
|
||||||
TextStyle.SHORT,
|
currentOpeningTime.dayOfWeek.getDisplayName(
|
||||||
Locale.getDefault()
|
TextStyle.SHORT,
|
||||||
)
|
Locale.getDefault()
|
||||||
|
)
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.location_closes_other_day,
|
R.string.location_closes_other_day,
|
||||||
dow,
|
dow,
|
||||||
@ -345,18 +366,21 @@ fun LocationItem(
|
|||||||
} else {
|
} else {
|
||||||
val nextOpeningTime =
|
val nextOpeningTime =
|
||||||
openingSchedule.getNextOpeningHours()
|
openingSchedule.getNextOpeningHours()
|
||||||
val isSameDay = nextOpeningTime.dayOfWeek == LocalDateTime.now().dayOfWeek
|
val isSameDay =
|
||||||
val formattedTime = timeFormat.format(nextOpeningTime.startTime)
|
nextOpeningTime.dayOfWeek == LocalDateTime.now().dayOfWeek
|
||||||
|
val formattedTime =
|
||||||
|
timeFormat.format(nextOpeningTime.startTime)
|
||||||
val openingTime = if (isSameDay) {
|
val openingTime = if (isSameDay) {
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.location_opens,
|
R.string.location_opens,
|
||||||
formattedTime
|
formattedTime
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val dow = nextOpeningTime.dayOfWeek.getDisplayName(
|
val dow =
|
||||||
TextStyle.SHORT,
|
nextOpeningTime.dayOfWeek.getDisplayName(
|
||||||
Locale.getDefault()
|
TextStyle.SHORT,
|
||||||
)
|
Locale.getDefault()
|
||||||
|
)
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.location_opens_other_day,
|
R.string.location_opens_other_day,
|
||||||
dow,
|
dow,
|
||||||
@ -367,7 +391,11 @@ fun LocationItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(text = text, style = MaterialTheme.typography.labelMedium, modifier = Modifier.weight(1f))
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
|
||||||
Icon(Icons.AutoMirrored.Rounded.NavigateNext, null)
|
Icon(Icons.AutoMirrored.Rounded.NavigateNext, null)
|
||||||
}
|
}
|
||||||
@ -551,228 +579,35 @@ fun LocationItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*Row(modifier = modifier) {
|
@Composable
|
||||||
Column {
|
fun Compass(
|
||||||
Row(
|
targetHeading: Float?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
size: Dp = 48.dp
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.size(size)
|
||||||
|
.background(
|
||||||
|
MaterialTheme.colorScheme.secondaryContainer,
|
||||||
|
MaterialTheme.shapes.small
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
if (targetHeading != null) {
|
||||||
|
Icon(
|
||||||
|
Icons.Rounded.Navigation,
|
||||||
|
null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.size(20f / 48f * size)
|
||||||
.padding(top = 8.dp, bottom = 8.dp),
|
.rotate(targetHeading)
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
.offset(y = -1f / 48f * size),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
tint = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||||
) {
|
)
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(start = 8.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(52.dp)
|
|
||||||
.aspectRatio(1f)
|
|
||||||
) {
|
|
||||||
ShapedLauncherIcon(
|
|
||||||
size = 48.dp,
|
|
||||||
icon = { icon },
|
|
||||||
badge = { badge },
|
|
||||||
)
|
|
||||||
val targetIconAnimationValue = if (isUpToDate) 0f else 1f
|
|
||||||
val animatedIconAlpha by animateFloatAsState(
|
|
||||||
targetValue = targetIconAnimationValue,
|
|
||||||
animationSpec = tween(delayMillis = 275)
|
|
||||||
)
|
|
||||||
val animatedIconSize by animateDpAsState(
|
|
||||||
targetValue = targetIconAnimationValue * 20.dp,
|
|
||||||
animationSpec = tween(delayMillis = 275, easing = EaseOutBack)
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.size(22.dp)
|
|
||||||
.align(Alignment.BottomEnd)
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(animatedIconSize)
|
|
||||||
.alpha(animatedIconAlpha)
|
|
||||||
.align(Alignment.Center)
|
|
||||||
.clickable(!isUpToDate) {
|
|
||||||
Toast
|
|
||||||
.makeText(
|
|
||||||
context,
|
|
||||||
R.string.cached_searchable,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
)
|
|
||||||
.show()
|
|
||||||
},
|
|
||||||
imageVector = Icons.TwoTone.CloudOff,
|
|
||||||
contentDescription = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(.75f),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
val textStyle by animateTextStyleAsState(
|
|
||||||
if (showDetails) MaterialTheme.typography.titleMedium
|
|
||||||
else MaterialTheme.typography.titleSmall
|
|
||||||
)
|
|
||||||
val titleAlignment by animateHorizontalAlignmentAsState(
|
|
||||||
targetAlignment = if (showDetails) Alignment.CenterHorizontally else Alignment.Start
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = location.labelOverride ?: location.label,
|
|
||||||
modifier = Modifier.align(titleAlignment),
|
|
||||||
style = textStyle,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
softWrap = true,
|
|
||||||
)
|
|
||||||
if (!location.openingSchedule?.openingHours.isNullOrEmpty()) {
|
|
||||||
val isOpen = location.openingSchedule!!.isOpen
|
|
||||||
AnimatedVisibility(!showDetails) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = 4.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
text = context.getString(if (isOpen) R.string.location_open else R.string.location_closed),
|
|
||||||
style = MaterialTheme.typography.labelSmall,
|
|
||||||
color = if (isOpen) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.secondary,
|
|
||||||
textAlign = TextAlign.Start,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(end = 12.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.SpaceAround,
|
|
||||||
) {
|
|
||||||
|
|
||||||
if (targetHeading != null) {
|
|
||||||
val directionArrowAngle by animateValueAsState(
|
|
||||||
targetValue = targetHeading!!,
|
|
||||||
typeConverter = Float.DegreesConverter
|
|
||||||
)
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.rotate(directionArrowAngle),
|
|
||||||
imageVector = Icons.Rounded.ArrowUpward,
|
|
||||||
contentDescription = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (distance != null) {
|
|
||||||
Text(
|
|
||||||
text = distance.metersToLocalizedString(
|
|
||||||
context, imperialUnits
|
|
||||||
), style = MaterialTheme.typography.labelSmall
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnimatedVisibility(showDetails) {
|
|
||||||
Column {
|
|
||||||
val isTwentyFourSeven = location.openingSchedule?.isTwentyFourSeven ?: false
|
|
||||||
val hasOpeningHours = !location.openingSchedule?.openingHours.isNullOrEmpty()
|
|
||||||
val daysOfWeek = enumValues<DayOfWeek>()
|
|
||||||
|
|
||||||
val javaLocale = java.util.Locale.forLanguageTag(Locale.current.toLanguageTag())
|
|
||||||
val timeFormatter = DateTimeFormatter
|
|
||||||
.ofLocalizedTime(FormatStyle.SHORT)
|
|
||||||
.withLocale(javaLocale)
|
|
||||||
|
|
||||||
if (isTwentyFourSeven) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterHorizontally)
|
|
||||||
.padding(bottom = 8.dp),
|
|
||||||
text = stringResource(id = R.string.location_open_24_7),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
color = MaterialTheme.colorScheme.tertiary,
|
|
||||||
)
|
|
||||||
} else if (hasOpeningHours) {
|
|
||||||
val oh = location.openingSchedule!!.openingHours
|
|
||||||
val openIndex = oh.indexOfFirst { it.isOpen }
|
|
||||||
if (openIndex != -1) {
|
|
||||||
val todaySchedule = oh[openIndex]
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterHorizontally)
|
|
||||||
.padding(bottom = 8.dp),
|
|
||||||
text = stringResource(
|
|
||||||
R.string.location_open_until,
|
|
||||||
(todaySchedule.startTime + todaySchedule.duration).format(
|
|
||||||
timeFormatter
|
|
||||||
)
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
color = MaterialTheme.colorScheme.tertiary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HorizontalDivider()
|
|
||||||
|
|
||||||
|
|
||||||
val address = buildAddress(location.street, location.houseNumber)
|
|
||||||
if (address != null) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterHorizontally)
|
|
||||||
.padding(bottom = 8.dp),
|
|
||||||
text = address,
|
|
||||||
style = MaterialTheme.typography.labelSmall,
|
|
||||||
color = MaterialTheme.colorScheme.secondary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalDivider(Modifier.padding(top = 8.dp))
|
|
||||||
|
|
||||||
if (!isTwentyFourSeven && hasOpeningHours) {
|
|
||||||
val today = LocalDateTime.now().dayOfWeek
|
|
||||||
val oh = location.openingSchedule!!.openingHours
|
|
||||||
val nextOpeningTime =
|
|
||||||
(0..DayOfWeek.SUNDAY.ordinal)
|
|
||||||
.firstNotNullOfOrNull {
|
|
||||||
val dow =
|
|
||||||
daysOfWeek[(today.ordinal + it) % (DayOfWeek.SUNDAY.ordinal + 1)]
|
|
||||||
oh.filter {
|
|
||||||
it.dayOfWeek == dow
|
|
||||||
}.firstOrNull {
|
|
||||||
it.dayOfWeek != today || it.startTime.isAfter(LocalTime.now())
|
|
||||||
}
|
|
||||||
} ?: oh.first()
|
|
||||||
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterHorizontally)
|
|
||||||
.padding(top = 8.dp),
|
|
||||||
text = stringResource(
|
|
||||||
if (nextOpeningTime.dayOfWeek == today) R.string.location_open_next
|
|
||||||
else R.string.location_open_next_day,
|
|
||||||
if (nextOpeningTime.dayOfWeek == today) {
|
|
||||||
val untilOpenToday = Duration.between(
|
|
||||||
LocalTime.now(),
|
|
||||||
nextOpeningTime.startTime,
|
|
||||||
)
|
|
||||||
val hours = untilOpenToday.toHours()
|
|
||||||
val minutes = untilOpenToday.toMinutes() % 60L
|
|
||||||
if (hours > 0L) "${hours}h ${minutes}m"
|
|
||||||
else "${minutes}m"
|
|
||||||
} else "${
|
|
||||||
nextOpeningTime.dayOfWeek.getDisplayName(
|
|
||||||
TextStyle.FULL_STANDALONE,
|
|
||||||
javaLocale
|
|
||||||
)
|
|
||||||
} ${nextOpeningTime.startTime.format(timeFormatter)}"
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.labelMedium,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@ -118,15 +118,6 @@ fun LocationsSettingsScreen() {
|
|||||||
viewModel.setThemeMap(it)
|
viewModel.setThemeMap(it)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
SwitchPreference(
|
|
||||||
title = stringResource(R.string.preference_search_locations_show_position_on_map),
|
|
||||||
summary = stringResource(R.string.preference_search_locations_show_position_on_map_summary),
|
|
||||||
value = showPositionOnMap == true,
|
|
||||||
enabled = locations == true && showMap == true,
|
|
||||||
onValueChanged = {
|
|
||||||
viewModel.setShowPositionOnMap(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user