Redesign places result

This commit is contained in:
MM20 2024-05-05 22:35:57 +02:00
parent a382c40c20
commit 2cda2437f3
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
13 changed files with 507 additions and 199 deletions

View File

@ -2,72 +2,75 @@ package de.mm20.launcher2.ui.launcher.search.location
import android.content.Intent
import android.net.Uri
import android.widget.Toast
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.EaseOutBack
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateValueAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandIn
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkOut
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.ArrowUpward
import androidx.compose.material.icons.automirrored.rounded.NavigateNext
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.Map
import androidx.compose.material.icons.rounded.Navigation
import androidx.compose.material.icons.rounded.Phone
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material.icons.rounded.StarOutline
import androidx.compose.material.icons.rounded.TravelExplore
import androidx.compose.material.icons.twotone.CloudOff
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.AssistChip
import androidx.compose.material3.AssistChipDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect
import androidx.compose.ui.unit.times
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import de.mm20.launcher2.i18n.R
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.search.Location
import de.mm20.launcher2.ui.animation.animateHorizontalAlignmentAsState
import de.mm20.launcher2.ui.animation.animateTextStyleAsState
import de.mm20.launcher2.search.OpeningHours
import de.mm20.launcher2.search.OpeningSchedule
import de.mm20.launcher2.ui.component.DefaultToolbarAction
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
import de.mm20.launcher2.ui.component.Toolbar
import de.mm20.launcher2.ui.component.ToolbarAction
import de.mm20.launcher2.ui.ktx.DegreesConverter
import de.mm20.launcher2.ui.ktx.metersToLocalizedString
import de.mm20.launcher2.ui.ktx.toPixels
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
@ -76,14 +79,11 @@ import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
import de.mm20.launcher2.ui.locals.LocalGridSettings
import de.mm20.launcher2.ui.modifier.scale
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.launch
import java.time.DayOfWeek
import java.time.Duration
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.format.TextStyle
import java.util.Locale
import kotlin.math.pow
@Composable
@ -117,13 +117,442 @@ fun LocationItem(
} else emptyFlow()
}.collectAsStateWithLifecycle(null)
val icon by viewModel.icon.collectAsStateWithLifecycle()
val badge by viewModel.badge.collectAsStateWithLifecycle(null)
val imperialUnits by viewModel.imperialUnits.collectAsState()
val isUpToDate by viewModel.isUpToDate.collectAsState()
val distance = userLocation?.distanceTo(location.toAndroidLocation())
Row(modifier = modifier) {
SharedTransitionLayout(
modifier = modifier,
) {
AnimatedContent(showDetails) { showDetails ->
if (!showDetails) {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
ShapedLauncherIcon(
modifier = Modifier
.animateEnterExit(
enter = slideIn { IntOffset(-it.width, 0) } + fadeIn(),
exit = slideOut { IntOffset(-it.width, 0) } + fadeOut(),
)
.padding(8.dp),
size = 48.dp,
icon = { icon },
badge = { badge },
)
Column(
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp),
verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center,
) {
Text(
text = location.labelOverride ?: location.label,
style = MaterialTheme.typography.titleSmall,
modifier = Modifier
.sharedBounds(
rememberSharedContentState("label"),
this@AnimatedContent
)
)
val category = location.category
val formattedDistance = distance?.metersToLocalizedString(
context, imperialUnits
)
if (category != null || formattedDistance != null) {
Text(
when {
category != null && formattedDistance != null -> "${category}${formattedDistance}"
category != null -> category.toString()
formattedDistance != null -> formattedDistance
else -> ""
},
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier
.sharedElement(
rememberSharedContentState("sublabel"),
this@AnimatedContent
)
)
}
}
Box(
modifier = Modifier
.animateEnterExit(
enter = slideIn { IntOffset(it.width, 0) } + fadeIn(),
exit = slideOut { IntOffset(it.width, 0) } + fadeOut(),
)
.padding(end = 8.dp)
.size(48.dp)
.background(
MaterialTheme.colorScheme.secondaryContainer,
MaterialTheme.shapes.small
),
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 {
val showMap by viewModel.showMap.collectAsState()
Column {
if (showMap) {
val tileServerUrl by viewModel.mapTileServerUrl.collectAsState()
val shape = MaterialTheme.shapes.small
val applyTheming by viewModel.applyMapTheming.collectAsState()
val showPositionOnMap by viewModel.showPositionOnMap.collectAsState()
MapTiles(
modifier = Modifier
.animateEnterExit(
enter = expandVertically(),
exit = shrinkOut(),
)
.padding(12.dp)
.align(Alignment.CenterHorizontally)
.fillMaxWidth()
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, shape)
.clip(MaterialTheme.shapes.small)
.clickable {
viewModel.launch(context)
},
tileServerUrl = tileServerUrl,
location = location,
maxZoomLevel = 19,
tiles = IntSize(3, 2),
applyTheming = applyTheming,
userLocation = {
if (showPositionOnMap) userLocation?.let {
UserLocation(
it.latitude,
it.longitude,
heading = userHeading,
)
} else null
},
)
}
Row(
modifier = Modifier.padding(horizontal = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Column {
Text(
text = location.labelOverride ?: location.label,
style = MaterialTheme.typography.titleMedium,
modifier = Modifier
.sharedBounds(
rememberSharedContentState("label"),
this@AnimatedContent
)
)
val category = location.category
val formattedDistance = distance?.metersToLocalizedString(
context, imperialUnits
)
if (category != null || formattedDistance != null) {
Text(
when {
category != null && formattedDistance != null -> "${category}${formattedDistance}"
category != null -> category.toString()
formattedDistance != null -> formattedDistance
else -> ""
},
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier
.sharedElement(
rememberSharedContentState("sublabel"),
this@AnimatedContent
)
)
}
}
}
val openingSchedule = location.openingSchedule
if (openingSchedule != null && (openingSchedule.isTwentyFourSeven || openingSchedule.openingHours.isNotEmpty())) {
var showOpeningSchedule by remember(openingSchedule) {
mutableStateOf(false)
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(start = 12.dp, end = 12.dp, top = 12.dp),
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colorScheme.surfaceContainer,
onClick = {
if (!openingSchedule.isTwentyFourSeven) {
showOpeningSchedule = true
}
}
) {
AnimatedContent(showOpeningSchedule) { showSchedule ->
if (!showSchedule) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
if (openingSchedule.isTwentyFourSeven) {
Text(
text = stringResource(R.string.location_open_24_7),
style = MaterialTheme.typography.labelMedium,
)
} else {
val text = remember(openingSchedule) {
val currentOpeningTime =
openingSchedule.getCurrentOpeningHours()
val timeFormat =
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return@remember if (currentOpeningTime != null) {
val isSameDay =
currentOpeningTime.dayOfWeek == LocalDateTime.now().dayOfWeek
val formattedTime =
timeFormat.format(currentOpeningTime.startTime + currentOpeningTime.duration)
val closingTime = if (isSameDay) {
context.getString(
R.string.location_closes,
formattedTime
)
} else {
val dow = currentOpeningTime.dayOfWeek.getDisplayName(
TextStyle.SHORT,
Locale.getDefault()
)
context.getString(
R.string.location_closes_other_day,
dow,
formattedTime
)
}
"${context.getString(R.string.location_open)}$closingTime"
} else {
val nextOpeningTime =
openingSchedule.getNextOpeningHours()
val isSameDay = nextOpeningTime.dayOfWeek == LocalDateTime.now().dayOfWeek
val formattedTime = timeFormat.format(nextOpeningTime.startTime)
val openingTime = if (isSameDay) {
context.getString(
R.string.location_opens,
formattedTime
)
} else {
val dow = nextOpeningTime.dayOfWeek.getDisplayName(
TextStyle.SHORT,
Locale.getDefault()
)
context.getString(
R.string.location_opens_other_day,
dow,
formattedTime
)
}
"${context.getString(R.string.location_closed)}$openingTime"
}
}
Text(text = text, style = MaterialTheme.typography.labelMedium, modifier = Modifier.weight(1f))
Icon(Icons.AutoMirrored.Rounded.NavigateNext, null)
}
}
} else {
Column(
modifier = Modifier.padding(vertical = 6.dp)
) {
val groups = remember(openingSchedule) {
openingSchedule.openingHours
.groupBy { it.dayOfWeek }.entries
.sortedBy { it.key }
}
for (group in groups) {
Row(
modifier = Modifier.padding(
vertical = 2.dp,
horizontal = 12.dp
),
) {
Text(
modifier = Modifier.weight(1f),
text = group.key.getDisplayName(
TextStyle.FULL,
Locale.getDefault()
),
style = MaterialTheme.typography.bodySmall,
)
val times = remember(group.value) {
val dateFormatter =
DateTimeFormatter.ofLocalizedTime(
FormatStyle.SHORT
)
group.value.sortedBy { it.startTime }
.joinToString(separator = ", ") {
"${it.startTime.format(dateFormatter)}${
it.startTime.plus(
it.duration
).format(dateFormatter)
}"
}
}
Text(
text = times,
style = MaterialTheme.typography.labelMedium,
)
}
}
}
}
}
}
}
Row(
modifier = Modifier
.horizontalScroll(rememberScrollState())
.padding(start = 12.dp, top = 8.dp)
) {
AssistChip(
modifier = Modifier.padding(end = 12.dp),
onClick = {
context.tryStartActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("google.navigation:q=${location.latitude},${location.longitude}")
),
)
},
label = { Text(stringResource(R.string.menu_navigation)) },
leadingIcon = {
Icon(
Icons.Rounded.Navigation, null,
modifier = Modifier.size(AssistChipDefaults.IconSize)
)
}
)
location.phoneNumber?.let {
AssistChip(
modifier = Modifier.padding(end = 12.dp),
onClick = {
context.tryStartActivity(
Intent(
Intent.ACTION_DIAL, Uri.parse("tel:$it")
)
)
},
label = { Text(stringResource(R.string.menu_dial)) },
leadingIcon = {
Icon(
Icons.Rounded.Phone, null,
modifier = Modifier.size(AssistChipDefaults.IconSize)
)
}
)
}
location.websiteUrl?.let {
AssistChip(
modifier = Modifier.padding(end = 12.dp),
onClick = {
context.tryStartActivity(
Intent(
Intent.ACTION_VIEW, Uri.parse(it)
)
)
},
label = { Text(stringResource(R.string.menu_website)) },
leadingIcon = {
Icon(
Icons.Rounded.Language, null,
modifier = Modifier.size(AssistChipDefaults.IconSize)
)
}
)
}
}
val toolbarActions = mutableListOf<ToolbarAction>()
if (LocalFavoritesEnabled.current) {
val isPinned by viewModel.isPinned.collectAsState(false)
val favAction = if (isPinned) {
DefaultToolbarAction(
label = stringResource(R.string.menu_favorites_unpin),
icon = Icons.Rounded.Star,
action = {
viewModel.unpin()
}
)
} else {
DefaultToolbarAction(
label = stringResource(R.string.menu_favorites_pin),
icon = Icons.Rounded.StarOutline,
action = {
viewModel.pin()
})
}
toolbarActions.add(favAction)
}
if (!showMap) {
toolbarActions += DefaultToolbarAction(
label = stringResource(id = R.string.menu_map),
icon = Icons.Rounded.Map
) {
viewModel.launch(context)
}
}
location.fixMeUrl?.let {
toolbarActions += DefaultToolbarAction(
label = stringResource(id = R.string.menu_bugreport),
icon = Icons.Rounded.BugReport,
) {
context.tryStartActivity(
Intent(
Intent.ACTION_VIEW, Uri.parse(location.fixMeUrl)
)
)
}
}
Toolbar(
modifier = Modifier.fillMaxWidth(),
leftActions = listOf(DefaultToolbarAction(
label = stringResource(id = R.string.menu_back),
icon = Icons.AutoMirrored.Rounded.ArrowBack
) {
onBack()
}),
rightActions = toolbarActions,
)
}
}
}
}
/*Row(modifier = modifier) {
Column {
Row(
modifier = Modifier
@ -136,8 +565,6 @@ fun LocationItem(
modifier = Modifier.padding(start = 8.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
val icon by viewModel.icon.collectAsStateWithLifecycle()
val badge by viewModel.badge.collectAsState(null)
Box(
modifier = Modifier
.size(52.dp)
@ -283,56 +710,20 @@ fun LocationItem(
}
}
val showMap by viewModel.showMap.collectAsState()
if (showMap) {
val zoomLevel = 19
val nTiles = 4
val tileServerUrl by viewModel.mapTileServerUrl.collectAsState()
val shape = MaterialTheme.shapes.small
HorizontalDivider()
val applyTheming by viewModel.applyMapTheming.collectAsState()
val showPositionOnMap by viewModel.showPositionOnMap.collectAsState()
HorizontalDivider()
MapTiles(
val address = buildAddress(location.street, location.houseNumber)
if (address != null) {
Text(
modifier = Modifier
.padding(top = 16.dp, bottom = 8.dp)
.align(Alignment.CenterHorizontally)
.fillMaxWidth(.9125f)
.border(1.dp, MaterialTheme.colorScheme.outline, shape)
.clip(shape)
.clickable {
viewModel.launch(context)
},
tileServerUrl = tileServerUrl,
location = location,
maxZoomLevel = zoomLevel,
tiles = IntSize(3, 2),
applyTheming = applyTheming,
userLocation = {
if (showPositionOnMap) userLocation?.let {
UserLocation(
it.latitude,
it.longitude,
heading = userHeading,
)
} else null
},
.padding(bottom = 8.dp),
text = address,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.secondary
)
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))
@ -378,97 +769,10 @@ fun LocationItem(
style = MaterialTheme.typography.labelMedium,
)
}
val toolbarActions = mutableListOf<ToolbarAction>()
if (LocalFavoritesEnabled.current) {
val isPinned by viewModel.isPinned.collectAsState(false)
val favAction = if (isPinned) {
DefaultToolbarAction(
label = stringResource(R.string.menu_favorites_unpin),
icon = Icons.Rounded.Star,
action = {
viewModel.unpin()
}
)
} else {
DefaultToolbarAction(
label = stringResource(R.string.menu_favorites_pin),
icon = Icons.Rounded.StarOutline,
action = {
viewModel.pin()
})
}
toolbarActions.add(favAction)
}
if (!showMap) {
toolbarActions += DefaultToolbarAction(
label = stringResource(id = R.string.menu_map),
icon = Icons.Rounded.Map
) {
viewModel.launch(context)
}
}
location.phoneNumber?.let {
toolbarActions += DefaultToolbarAction(
label = stringResource(id = R.string.menu_dial),
icon = Icons.Rounded.Phone
) {
viewModel.viewModelScope.launch {
context.tryStartActivity(
Intent(
Intent.ACTION_DIAL, Uri.parse("tel:$it")
)
)
}
}
}
location.websiteUrl?.let {
toolbarActions += DefaultToolbarAction(
label = stringResource(id = R.string.menu_website),
icon = Icons.Rounded.TravelExplore
) {
viewModel.viewModelScope.launch {
context.tryStartActivity(
Intent(
Intent.ACTION_VIEW, Uri.parse(it)
)
)
}
}
}
location.fixMeUrl?.let {
toolbarActions += DefaultToolbarAction(
label = stringResource(id = R.string.menu_bugreport),
icon = Icons.Rounded.BugReport,
) {
context.tryStartActivity(
Intent(
Intent.ACTION_VIEW, Uri.parse(location.fixMeUrl)
)
)
}
}
Toolbar(
modifier = Modifier.fillMaxWidth(),
leftActions = listOf(DefaultToolbarAction(
label = stringResource(id = R.string.menu_back),
icon = Icons.AutoMirrored.Rounded.ArrowBack
) {
onBack()
}),
rightActions = toolbarActions,
)
}
}
}
}
}*/
}
@Composable
@ -521,3 +825,25 @@ private fun buildAddress(
}
return if (summary.isEmpty()) null else summary.toString()
}
private fun OpeningSchedule.getCurrentOpeningHours(): OpeningHours? {
return openingHours.find { it.isOpen }
}
private fun OpeningSchedule.getNextOpeningHours(): OpeningHours {
val now = LocalDateTime.now()
val sortedSchedule = this
.openingHours
.sortedWith { a, b ->
if (a.dayOfWeek == b.dayOfWeek) {
a.startTime.compareTo(b.startTime)
} else {
a.dayOfWeek.compareTo(b.dayOfWeek)
}
}
return sortedSchedule
.find {
now.dayOfWeek < it.dayOfWeek || now.dayOfWeek == it.dayOfWeek && now.toLocalTime() < it.startTime
} ?: sortedSchedule.first()
}

View File

@ -23,9 +23,11 @@ import androidx.compose.foundation.layout.absoluteOffset
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Navigation
import androidx.compose.material.icons.rounded.Place
@ -185,31 +187,6 @@ fun MapTiles(
),
label = "poiLocAnimation"
)
val textMeasurer = rememberTextMeasurer()
val osmAttributionTextStyle = MaterialTheme.typography.labelSmall
val osmAttributionTextColor = MaterialTheme.colorScheme.onSurface
val osmAttributionSurface =
MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = .5f)
val (yLocation, xLocation) = remember(location, zoom) {
getTileCoordinates(
latitude = location.latitude,
longitude = location.longitude,
zoom
)
}
val userOffset = remember(userLocation, zoom) {
if (userLocation != null) {
getTileCoordinates(
latitude = userLocation.lat,
longitude = userLocation.lon,
zoom
)
} else {
Offset.Unspecified
}
}
val tileSize = minWidth / tiles.width.toFloat()
val locationTileCoordinates =
getTileCoordinates(location.latitude, location.longitude, zoom)
@ -275,6 +252,18 @@ fun MapTiles(
.border(2.dp, MaterialTheme.colorScheme.onTertiary, CircleShape)
.shadow(1.dp, CircleShape)
)
if (osmAttribution != null) {
Text(
text = osmAttribution,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier
.align(Alignment.BottomEnd)
.background(MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = .5f))
.padding(top = 2.dp, bottom = 2.dp, start = 4.dp, end = 4.dp)
)
}
}
}
}

View File

@ -666,7 +666,6 @@
<string name="missing_permission_plugins">Es requereix permís de connector per utilitzar connectors.</string>
<string name="preference_plugin_badges_summary">Indiqueu amb quin connector s\'ha creat un resultat de cerca</string>
<string name="preference_mdy_color_source_wallpaper">Colors del Fons de Pantalla</string>
<string name="location_open_next_day">Estarà disponible %1$s</string>
<string name="missing_permission_location_search">Doneu permís a la ubicació per cercar ubicacions properes.</string>
<string name="preference_mdy_color_source">Font de Colors dinàmics</string>
<string name="preference_mdy_color_source_system">Colors del Sistema</string>

View File

@ -688,7 +688,6 @@
<string name="preference_search_locations_radius">Vzdálenost vyhledávání</string>
<string name="preference_search_locations_summary">Vyhledat v místní oblasti obchody a další místa</string>
<string name="preference_search_locations_show_position_on_map_summary">Zobrazit vlastní lokaci na mapě</string>
<string name="location_open_next_day">Otevírá v %1$s</string>
<string name="preference_search_locations_show_map_summary">Zobrazit náhled mapy pro místa</string>
<string name="preference_search_locations_theme_map">Téma mapy</string>
<string name="preference_search_locations_theme_map_summary">Použít barevné schéma launcheru jako téma mapy</string>

View File

@ -678,7 +678,6 @@
<string name="default_websearch_3_url">https://play.google.com/store/search?q=${1}</string>
<string name="shortcut_unavailable_description">Denne genvej er utilgængelig, fordi %1$s ikke er din standard launcher</string>
<string name="default_websearch_2_url">https://www.youtube.com/results?search_query=${1}</string>
<string name="location_open_next_day">Åbner på %1$s</string>
<string name="location_open">Åben</string>
<string name="location_closed">Lukket</string>
<string name="location_open_until">Åben indtil %1$s</string>

View File

@ -681,7 +681,6 @@
<string name="preference_mdy_color_source">Quelle für dynamische Farben</string>
<string name="preference_search_locations_show_position_on_map_summary">Den eigenen Standort auf der Karte zeigen</string>
<string name="location_closed">Geschlossen</string>
<string name="location_open_next_day">Öffnet am %1$s</string>
<string name="preference_search_location_custom_overpass_url">Overpass-URL</string>
<string name="preference_search_locations">Orte</string>
<string name="location_open">Geöffnet</string>

View File

@ -703,7 +703,6 @@
<string name="clock_style_analog">Manecillas</string>
<string name="clock_style_empty">Sin reloj</string>
<string name="clock_variant_standard">Estándar</string>
<string name="location_open_next_day">Abre el %1$s</string>
<string name="preference_search_locations_show_map">Mapa</string>
<string name="preference_search_locations_show_map_summary">Mostrar una vista previa de mapa para los lugares</string>
<string name="preference_search_locations_theme_map">Tema del mapa</string>

View File

@ -688,7 +688,6 @@
<string name="preference_search_locations_hide_uncategorized">Kategorizálatlan helyek elrejtése</string>
<string name="preference_search_locations_hide_uncategorized_summary">Csak jól meghatározott kategóriák, például kávézók, vagy éttermek eredményeit jeleníti meg</string>
<string name="preference_search_locations_show_map">Térkép</string>
<string name="location_open_next_day">Kinyit ekkor: %1$s</string>
<string name="preference_search_locations_theme_map">Térkép színséma</string>
<string name="preference_search_locations_theme_map_summary">Az indító színsémájának alkalmazása a térképre</string>
<string name="preference_search_locations_show_position_on_map">Saját helyszín megjelenítése</string>

View File

@ -687,7 +687,6 @@
<string name="preference_search_location_custom_overpass_url">URL Overpass</string>
<string name="preference_search_bar_separate_work_profile">App per profili di lavoro separate</string>
<string name="preference_search_bar_separate_work_profile_summary">Mostra app del profilo di lavoro in una scheda separata</string>
<string name="location_open_next_day">Apertura %1$s</string>
<string name="preference_search_locations_hide_uncategorized">Nascondi luoghi senza categoria</string>
<string name="preference_clock_widget_show_seconds">Mostra secondi</string>
<string name="widget_use_theme_colors">Usa colore del tema</string>

View File

@ -347,7 +347,6 @@
<string name="location_closed">Fechado</string>
<string name="location_open_until">Aberto até %1$s</string>
<string name="location_open_next">Abre em %1$s</string>
<string name="location_open_next_day">Abre no/na %1$s</string>
<string name="menu_map">Ver no mapa</string>
<string name="menu_website">Abrir página web</string>
</resources>

View File

@ -691,7 +691,6 @@
<string name="missing_permission_location_search">Для поиска мест поблизости требуется разрешение на доступ к местоположению.</string>
<string name="location_open_until">Закроется в %1$s</string>
<string name="location_open_next">Откроется в %1$s</string>
<string name="location_open_next_day">Откроется в %1$s</string>
<string name="menu_map">Показать на карте</string>
<string name="preference_search_locations">Места</string>
<string name="preference_search_locations_radius">Радиус поиска</string>

View File

@ -195,7 +195,6 @@
<string name="location_closed">Kapalı</string>
<string name="location_open_until">Saat %1$s\'e kadar açık</string>
<string name="location_open_next">%1$s Sonra açılacaktır</string>
<string name="location_open_next_day">%1$s Günü açılacaktır</string>
<string name="menu_map">Haritada göster</string>
<string name="menu_website">Websiteyi aç</string>
<string name="calendar_widget_pinned_events">Yakında</string>

View File

@ -2,12 +2,14 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
<string name="location_open">Open</string>
<string name="location_closed">Closed</string>
<!-- Shown when a location search result is open until TIMESTAMP (hours:minutes) of the same day -->
<string name="location_open_until">Open until %1$s</string>
<!-- Shown when a location search result opens in TIMESPAN on the same day -->
<string name="location_open_next">Opens in %1$s</string>
<!-- Shown when a location search result opens next DAY-OF-WEEK -->
<string name="location_open_next_day">Opens on %1$s</string>
<!-- Time when a place next closes (on the same day). $1%s: time (hh:mm) -->
<string name="location_closes">closes at %1$s</string>
<!-- Time when a place next closes (on a different day). $1%s: day of week, %2$s: time (hh:mm) -->
<string name="location_closes_other_day">closes %1$s, %2$s</string>
<!-- Time when a place next opens (on the same day). $1%s: time (hh:mm) -->
<string name="location_opens">opens at %1$s</string>
<!-- Time when a place next opens (on a different day). $1%s: day of week, %2$s: time (hh:mm) -->
<string name="location_opens_other_day">opens %1$s, %2$s</string>
<!-- Name of the app -->
<!-- Share something. Can be anything, an app, a website, a file, … -->
<string name="menu_share">Share</string>
@ -893,6 +895,7 @@
<string name="preference_search_locations_show_position_on_map">Show own position</string>
<string name="preference_search_location_custom_tile_server_url">Tileserver URL</string>
<string name="menu_dial">Call</string>
<string name="menu_navigation">Navigation</string>
<string name="menu_bugreport">Bug Report</string>
<string name="location_open_24_7">Open 24/7</string>
<string name="plugin_state_error">This plugin isn\'t working correctly</string>