From ccaacee2c1b1097cbe2864301e18d32b35bd7730 Mon Sep 17 00:00:00 2001 From: James Rich Date: Thu, 7 May 2026 19:53:12 -0500 Subject: [PATCH] feat(discovery): replace hardcoded UI strings with string resources (D047) --- .skills/compose-ui/strings-index.txt | 15 +++++++++++ .../composeResources/values/strings.xml | 15 +++++++++++ .../ui/DiscoveryHistoryDetailScreen.kt | 16 ++++++++--- .../discovery/ui/DiscoveryHistoryScreen.kt | 26 +++++++++++++----- .../discovery/ui/DiscoveryMapScreen.kt | 10 +++++-- .../discovery/ui/DiscoveryScanScreen.kt | 23 ++++++++++++---- .../discovery/ui/DiscoverySummaryScreen.kt | 27 +++++++++++++++---- .../tasks.md | 2 +- 8 files changed, 112 insertions(+), 22 deletions(-) diff --git a/.skills/compose-ui/strings-index.txt b/.skills/compose-ui/strings-index.txt index 71c89ac96..b7ad7e8b2 100644 --- a/.skills/compose-ui/strings-index.txt +++ b/.skills/compose-ui/strings-index.txt @@ -288,6 +288,21 @@ discard_changes disconnect disconnected discovered_network_devices +### DISCOVERY ### +discovery_delete_session +discovery_delete_session_confirm +discovery_dwell_minutes +discovery_export_report +discovery_history +discovery_local_mesh +discovery_map +discovery_rerun_analysis +discovery_scan_history +discovery_scan_summary +discovery_session_detail +discovery_start_scan +discovery_stop_scan +discovery_view_map disk_free_indexed ### DISPLAY ### display diff --git a/core/resources/src/commonMain/composeResources/values/strings.xml b/core/resources/src/commonMain/composeResources/values/strings.xml index ff6c6333b..4b8d6f54b 100644 --- a/core/resources/src/commonMain/composeResources/values/strings.xml +++ b/core/resources/src/commonMain/composeResources/values/strings.xml @@ -312,6 +312,21 @@ Disconnect Disconnected Discovered Network Devices + + Delete Session + Are you sure you want to delete this discovery session? This action cannot be undone. + %1$d min + Export report + Discovery History + Local Mesh Discovery + Discovery Map + Re-run analysis + Scan History + Scan Summary + Session Detail + Start Scan + Stop Scan + View map Disk Free %1$d Display diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryDetailScreen.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryDetailScreen.kt index f06c35435..e2682077e 100644 --- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryDetailScreen.kt +++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryDetailScreen.kt @@ -42,7 +42,12 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.jetbrains.compose.resources.stringResource import org.meshtastic.core.database.entity.DiscoverySessionEntity +import org.meshtastic.core.resources.Res +import org.meshtastic.core.resources.back +import org.meshtastic.core.resources.discovery_session_detail +import org.meshtastic.core.resources.discovery_view_map import org.meshtastic.core.ui.icon.ArrowBack import org.meshtastic.core.ui.icon.Map import org.meshtastic.core.ui.icon.MeshtasticIcons @@ -63,9 +68,11 @@ fun DiscoveryHistoryDetailScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Session Detail") }, + title = { Text(stringResource(Res.string.discovery_session_detail)) }, navigationIcon = { - IconButton(onClick = onNavigateUp) { Icon(MeshtasticIcons.ArrowBack, contentDescription = "Back") } + IconButton(onClick = onNavigateUp) { + Icon(MeshtasticIcons.ArrowBack, contentDescription = stringResource(Res.string.back)) + } }, actions = { val s = session @@ -75,7 +82,10 @@ fun DiscoveryHistoryDetailScreen( } if (s != null && (s.userLatitude != 0.0 || hasAnyMappableNodes)) { IconButton(onClick = { onNavigateToMap(s.id) }) { - Icon(MeshtasticIcons.Map, contentDescription = "View map") + Icon( + MeshtasticIcons.Map, + contentDescription = stringResource(Res.string.discovery_view_map), + ) } } }, diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryScreen.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryScreen.kt index 7728b0d3a..4adedb392 100644 --- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryScreen.kt +++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryHistoryScreen.kt @@ -51,8 +51,16 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime +import org.jetbrains.compose.resources.stringResource import org.meshtastic.core.common.util.toInstant import org.meshtastic.core.database.entity.DiscoverySessionEntity +import org.meshtastic.core.resources.Res +import org.meshtastic.core.resources.back +import org.meshtastic.core.resources.cancel +import org.meshtastic.core.resources.delete +import org.meshtastic.core.resources.discovery_delete_session +import org.meshtastic.core.resources.discovery_delete_session_confirm +import org.meshtastic.core.resources.discovery_history import org.meshtastic.core.ui.icon.ArrowBack import org.meshtastic.core.ui.icon.CheckCircle import org.meshtastic.core.ui.icon.Delete @@ -73,9 +81,11 @@ fun DiscoveryHistoryScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Discovery History") }, + title = { Text(stringResource(Res.string.discovery_history)) }, navigationIcon = { - IconButton(onClick = onNavigateUp) { Icon(MeshtasticIcons.ArrowBack, contentDescription = "Back") } + IconButton(onClick = onNavigateUp) { + Icon(MeshtasticIcons.ArrowBack, contentDescription = stringResource(Res.string.back)) + } }, ) }, @@ -187,10 +197,14 @@ private fun CompletionStatusIcon(status: String) { private fun DeleteConfirmationDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) { AlertDialog( onDismissRequest = onDismiss, - title = { Text("Delete Session") }, - text = { Text("Are you sure you want to delete this discovery session? This action cannot be undone.") }, - confirmButton = { TextButton(onClick = onConfirm) { Text("Delete", color = MaterialTheme.colorScheme.error) } }, - dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } }, + title = { Text(stringResource(Res.string.discovery_delete_session)) }, + text = { Text(stringResource(Res.string.discovery_delete_session_confirm)) }, + confirmButton = { + TextButton(onClick = onConfirm) { + Text(stringResource(Res.string.delete), color = MaterialTheme.colorScheme.error) + } + }, + dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(Res.string.cancel)) } }, ) } diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryMapScreen.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryMapScreen.kt index 83db549d3..e4134f604 100644 --- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryMapScreen.kt +++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryMapScreen.kt @@ -31,6 +31,10 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.jetbrains.compose.resources.stringResource +import org.meshtastic.core.resources.Res +import org.meshtastic.core.resources.back +import org.meshtastic.core.resources.discovery_map import org.meshtastic.core.ui.icon.ArrowBack import org.meshtastic.core.ui.icon.MeshtasticIcons import org.meshtastic.core.ui.util.DiscoveryMapNode @@ -52,9 +56,11 @@ fun DiscoveryMapScreen(viewModel: DiscoveryMapViewModel, onNavigateUp: () -> Uni Scaffold( topBar = { TopAppBar( - title = { Text("Discovery Map") }, + title = { Text(stringResource(Res.string.discovery_map)) }, navigationIcon = { - IconButton(onClick = onNavigateUp) { Icon(MeshtasticIcons.ArrowBack, contentDescription = "Back") } + IconButton(onClick = onNavigateUp) { + Icon(MeshtasticIcons.ArrowBack, contentDescription = stringResource(Res.string.back)) + } }, ) }, diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt index 2be9c80f1..cea159bb6 100644 --- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt +++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoveryScanScreen.kt @@ -54,6 +54,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.jetbrains.compose.resources.stringResource +import org.meshtastic.core.resources.Res +import org.meshtastic.core.resources.back +import org.meshtastic.core.resources.discovery_local_mesh +import org.meshtastic.core.resources.discovery_scan_history +import org.meshtastic.core.resources.discovery_start_scan +import org.meshtastic.core.resources.discovery_stop_scan import org.meshtastic.core.ui.component.SwitchPreference import org.meshtastic.core.ui.icon.ArrowBack import org.meshtastic.core.ui.icon.Close @@ -108,15 +115,21 @@ fun DiscoveryScanScreen( Scaffold( topBar = { CenterAlignedTopAppBar( - title = { Text("Local Mesh Discovery") }, + title = { Text(stringResource(Res.string.discovery_local_mesh)) }, navigationIcon = { IconButton(onClick = onNavigateUp) { - Icon(imageVector = MeshtasticIcons.ArrowBack, contentDescription = "Back") + Icon( + imageVector = MeshtasticIcons.ArrowBack, + contentDescription = stringResource(Res.string.back), + ) } }, actions = { IconButton(onClick = onNavigateToHistory) { - Icon(imageVector = MeshtasticIcons.History, contentDescription = "Scan History") + Icon( + imageVector = MeshtasticIcons.History, + contentDescription = stringResource(Res.string.discovery_scan_history), + ) } }, ) @@ -291,12 +304,12 @@ private fun ScanButton( modifier = modifier.fillMaxWidth(), ) { Icon(imageVector = MeshtasticIcons.Close, contentDescription = null) - Text("Stop Scan", modifier = Modifier.padding(start = 8.dp)) + Text(stringResource(Res.string.discovery_stop_scan), modifier = Modifier.padding(start = 8.dp)) } } else { Button(onClick = onStart, enabled = isConnected && hasPresetsSelected, modifier = modifier.fillMaxWidth()) { Icon(imageVector = MeshtasticIcons.PlayArrow, contentDescription = null) - Text("Start Scan", modifier = Modifier.padding(start = 8.dp)) + Text(stringResource(Res.string.discovery_start_scan), modifier = Modifier.padding(start = 8.dp)) } } } diff --git a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoverySummaryScreen.kt b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoverySummaryScreen.kt index 7e9c1e2b4..4dc9f413c 100644 --- a/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoverySummaryScreen.kt +++ b/feature/discovery/src/commonMain/kotlin/org/meshtastic/feature/discovery/ui/DiscoverySummaryScreen.kt @@ -46,11 +46,18 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.jetbrains.compose.resources.stringResource import org.meshtastic.core.common.util.DateFormatter import org.meshtastic.core.common.util.NumberFormatter import org.meshtastic.core.database.entity.DiscoveredNodeEntity import org.meshtastic.core.database.entity.DiscoveryPresetResultEntity import org.meshtastic.core.database.entity.DiscoverySessionEntity +import org.meshtastic.core.resources.Res +import org.meshtastic.core.resources.back +import org.meshtastic.core.resources.discovery_export_report +import org.meshtastic.core.resources.discovery_rerun_analysis +import org.meshtastic.core.resources.discovery_scan_summary +import org.meshtastic.core.resources.discovery_view_map import org.meshtastic.core.ui.icon.ArrowBack import org.meshtastic.core.ui.icon.Map import org.meshtastic.core.ui.icon.MeshtasticIcons @@ -131,17 +138,27 @@ private fun DiscoverySummaryContent( Scaffold( topBar = { TopAppBar( - title = { Text("Scan Summary") }, + title = { Text(stringResource(Res.string.discovery_scan_summary)) }, navigationIcon = { - IconButton(onClick = onNavigateUp) { Icon(MeshtasticIcons.ArrowBack, contentDescription = "Back") } + IconButton(onClick = onNavigateUp) { + Icon(MeshtasticIcons.ArrowBack, contentDescription = stringResource(Res.string.back)) + } }, actions = { if (session != null) { IconButton(onClick = { onNavigateToMap(session.id) }) { - Icon(MeshtasticIcons.Map, contentDescription = "View map") + Icon( + MeshtasticIcons.Map, + contentDescription = stringResource(Res.string.discovery_view_map), + ) } } - IconButton(onClick = onExport) { Icon(MeshtasticIcons.Share, contentDescription = "Export report") } + IconButton(onClick = onExport) { + Icon( + MeshtasticIcons.Share, + contentDescription = stringResource(Res.string.discovery_export_report), + ) + } }, ) }, @@ -230,7 +247,7 @@ private fun AiSummaryCard( IconButton(onClick = onRerunAnalysis) { Icon( MeshtasticIcons.Refresh, - contentDescription = "Re-run analysis", + contentDescription = stringResource(Res.string.discovery_rerun_analysis), tint = MaterialTheme.colorScheme.onTertiaryContainer, ) } diff --git a/specs/20260507-161658-local-mesh-discovery/tasks.md b/specs/20260507-161658-local-mesh-discovery/tasks.md index 91c8a7761..9a45475ca 100644 --- a/specs/20260507-161658-local-mesh-discovery/tasks.md +++ b/specs/20260507-161658-local-mesh-discovery/tasks.md @@ -110,7 +110,7 @@ - [ ] **D044** [P] Add accessibility polish: semantics, progress announcements, disabled-preset explanations, and large-screen layout checks. - [X] **D045** [P] Finalize 2.4 GHz hardware gating using `DeviceHardwareRepository` + current radio metadata. - [X] **D046** [P] Add logging / diagnostics and make sure the feature is debuggable through existing app logging tools. -- [ ] **D047** [P] Add strings, icons, and docs updates (`core/resources`, deep-link docs, quickstart references). +- [X] **D047** [P] Add strings, icons, and docs updates (`core/resources`, deep-link docs, quickstart references). - [ ] **D048** Run targeted and full verification commands. **Depends on**: all previous phases