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:
vrubelroman 2026-07-09 22:12:35 +00:00
parent 37edc96d50
commit 28f310b56f
3 changed files with 46 additions and 2 deletions

View file

@ -3,12 +3,14 @@ package com.guidecity.app.ui.map
import android.Manifest
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.material.icons.Icons
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.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
@ -40,6 +45,12 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.guidecity.app.R
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
fun MapScreen(
@ -53,6 +64,7 @@ fun MapScreen(
val resolvedLocation by viewModel.resolvedLocation.collectAsState()
val nearbyPlaces by viewModel.nearbyPlaces.collectAsState()
var query by remember { mutableStateOf("") }
var showList by remember { mutableStateOf(false) }
val permissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestMultiplePermissions(),
@ -69,6 +81,16 @@ fun MapScreen(
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
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) {
Icon(Icons.Filled.Favorite, contentDescription = stringResource(R.string.favorites_title))
}
@ -151,7 +173,7 @@ fun MapScreen(
CircularProgressIndicator()
if (state == MapUiState.CheckingNearby) {
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,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(stringResource(R.string.map_no_places_nearby))
Text(stringResource(R.string.map_no_places_nearby), color = MapOverlayTextColor)
}
}
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(
modifier = Modifier
.fillMaxSize()
@ -178,6 +217,7 @@ fun MapScreen(
) {
Text(
text = stringResource(R.string.map_places_found, state.placesFound, state.radiusM),
color = MapOverlayTextColor,
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = onLocationResolved) {

View file

@ -19,6 +19,8 @@
<string name="map_places_found">Найдено мест поблизости: %1$d (в радиусе %2$d м)</string>
<string name="map_start">Начать</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_places_count">Мест поблизости: %1$d</string>

View file

@ -19,6 +19,8 @@
<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_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_places_count">%1$d place(s) nearby</string>