Add map/list toggle on the start screen; fix text contrast over map
The "found N places" overlay text (and the checking/no-places states) used the theme's default light text color, which washed out against the now-real, mostly light-colored OSM map tiles. Fixed with a fixed dark color (Mocha.Crust) for text overlaid on the map. Added a toggle button (top bar, visible once places are found) that switches the start screen between the map and a plain list preview of the found places (reusing PlaceCard in its neutral/UPCOMING state) — lets the user see what's "ready to read" before committing to Start. Verified: testDebugUnitTest passes, assembleDebug produces a working APK, sent to Telegram. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
37edc96d50
commit
28f310b56f
3 changed files with 46 additions and 2 deletions
|
|
@ -3,12 +3,14 @@ package com.guidecity.app.ui.map
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -16,12 +18,15 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Favorite
|
import androidx.compose.material.icons.filled.Favorite
|
||||||
|
import androidx.compose.material.icons.filled.List
|
||||||
|
import androidx.compose.material.icons.filled.Map
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
|
@ -40,6 +45,12 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import com.guidecity.app.R
|
import com.guidecity.app.R
|
||||||
import com.guidecity.app.map.CityMapView
|
import com.guidecity.app.map.CityMapView
|
||||||
|
import com.guidecity.app.theme.Mocha
|
||||||
|
import com.guidecity.app.ui.guide.CardState
|
||||||
|
import com.guidecity.app.ui.guide.PlaceCard
|
||||||
|
|
||||||
|
/** Overlay text sits on top of the (now real, often light-colored) map tiles, so it needs a fixed dark color rather than the theme's default light-on-dark text. */
|
||||||
|
private val MapOverlayTextColor = Mocha.Crust
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MapScreen(
|
fun MapScreen(
|
||||||
|
|
@ -53,6 +64,7 @@ fun MapScreen(
|
||||||
val resolvedLocation by viewModel.resolvedLocation.collectAsState()
|
val resolvedLocation by viewModel.resolvedLocation.collectAsState()
|
||||||
val nearbyPlaces by viewModel.nearbyPlaces.collectAsState()
|
val nearbyPlaces by viewModel.nearbyPlaces.collectAsState()
|
||||||
var query by remember { mutableStateOf("") }
|
var query by remember { mutableStateOf("") }
|
||||||
|
var showList by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val permissionLauncher = rememberLauncherForActivityResult(
|
val permissionLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.RequestMultiplePermissions(),
|
contract = ActivityResultContracts.RequestMultiplePermissions(),
|
||||||
|
|
@ -69,6 +81,16 @@ fun MapScreen(
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(stringResource(R.string.app_name)) },
|
title = { Text(stringResource(R.string.app_name)) },
|
||||||
actions = {
|
actions = {
|
||||||
|
if (uiState is MapUiState.ReadyToStart) {
|
||||||
|
IconButton(onClick = { showList = !showList }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (showList) Icons.Filled.Map else Icons.Filled.List,
|
||||||
|
contentDescription = stringResource(
|
||||||
|
if (showList) R.string.map_show_map else R.string.map_show_list,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
IconButton(onClick = onOpenFavorites) {
|
IconButton(onClick = onOpenFavorites) {
|
||||||
Icon(Icons.Filled.Favorite, contentDescription = stringResource(R.string.favorites_title))
|
Icon(Icons.Filled.Favorite, contentDescription = stringResource(R.string.favorites_title))
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +173,7 @@ fun MapScreen(
|
||||||
CircularProgressIndicator()
|
CircularProgressIndicator()
|
||||||
if (state == MapUiState.CheckingNearby) {
|
if (state == MapUiState.CheckingNearby) {
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
Text(stringResource(R.string.map_checking_nearby))
|
Text(stringResource(R.string.map_checking_nearby), color = MapOverlayTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -164,11 +186,28 @@ fun MapScreen(
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.map_no_places_nearby))
|
Text(stringResource(R.string.map_no_places_nearby), color = MapOverlayTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is MapUiState.ReadyToStart -> {
|
is MapUiState.ReadyToStart -> {
|
||||||
|
if (showList) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(MaterialTheme.colorScheme.background),
|
||||||
|
contentPadding = PaddingValues(bottom = 140.dp),
|
||||||
|
) {
|
||||||
|
items(nearbyPlaces, key = { it.id }) { place ->
|
||||||
|
PlaceCard(
|
||||||
|
place = place,
|
||||||
|
state = CardState.UPCOMING,
|
||||||
|
modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|
@ -178,6 +217,7 @@ fun MapScreen(
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.map_places_found, state.placesFound, state.radiusM),
|
text = stringResource(R.string.map_places_found, state.placesFound, state.radiusM),
|
||||||
|
color = MapOverlayTextColor,
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Button(onClick = onLocationResolved) {
|
Button(onClick = onLocationResolved) {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
<string name="map_places_found">Найдено мест поблизости: %1$d (в радиусе %2$d м)</string>
|
<string name="map_places_found">Найдено мест поблизости: %1$d (в радиусе %2$d м)</string>
|
||||||
<string name="map_start">Начать</string>
|
<string name="map_start">Начать</string>
|
||||||
<string name="map_no_places_nearby">В радиусе 10 км ничего не нашлось.</string>
|
<string name="map_no_places_nearby">В радиусе 10 км ничего не нашлось.</string>
|
||||||
|
<string name="map_show_list">Показать список</string>
|
||||||
|
<string name="map_show_map">Показать карту</string>
|
||||||
|
|
||||||
<string name="guide_no_places_nearby">Поблизости пока не найдено интересных мест.</string>
|
<string name="guide_no_places_nearby">Поблизости пока не найдено интересных мест.</string>
|
||||||
<string name="guide_places_count">Мест поблизости: %1$d</string>
|
<string name="guide_places_count">Мест поблизости: %1$d</string>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
<string name="map_places_found">Found %1$d place(s) nearby (within %2$d m)</string>
|
<string name="map_places_found">Found %1$d place(s) nearby (within %2$d m)</string>
|
||||||
<string name="map_start">Start</string>
|
<string name="map_start">Start</string>
|
||||||
<string name="map_no_places_nearby">Nothing found within 10 km of here.</string>
|
<string name="map_no_places_nearby">Nothing found within 10 km of here.</string>
|
||||||
|
<string name="map_show_list">Show list</string>
|
||||||
|
<string name="map_show_map">Show map</string>
|
||||||
|
|
||||||
<string name="guide_no_places_nearby">No places found nearby yet.</string>
|
<string name="guide_no_places_nearby">No places found nearby yet.</string>
|
||||||
<string name="guide_places_count">%1$d place(s) nearby</string>
|
<string name="guide_places_count">%1$d place(s) nearby</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue