From 2cdcde950ef32e87d44a15fc4b136a4ee7e0c312 Mon Sep 17 00:00:00 2001 From: Dave Craig Date: Mon, 28 Sep 2026 16:49:09 +0100 Subject: [PATCH 1/3] Stop failed extract downloads leaving .geojson sidecars behind AndroidOfflineMapsManager wrote an extract's metadata sidecar before the download started, under a new timestamped name each time, and a download that failed or was cancelled only cleaned up its .downloading file. The sidecars stayed on the phone forever with no extract next to them - one test phone had six (two for Helsinki) and no extracts at all. The downloader now writes the sidecar itself, only once the extract is published, as the shared OfflineMapManager already does. Sidecars left by earlier versions are deleted when the downloaded list is refreshed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01THRgoVbh1G3pVacd7csDqJ --- .../utils/AndroidOfflineMapsManager.kt | 21 +++--- .../soundscape/utils/OfflineDownloader.kt | 11 +++ .../soundscape/utils/StorageUtils.kt | 13 ++++ .../soundscape/OfflineDownloaderTest.kt | 72 +++++++++++++++++-- 4 files changed, 100 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/scottishtecharmy/soundscape/utils/AndroidOfflineMapsManager.kt b/app/src/main/java/org/scottishtecharmy/soundscape/utils/AndroidOfflineMapsManager.kt index 5d2d559eb..696ad8f2c 100644 --- a/app/src/main/java/org/scottishtecharmy/soundscape/utils/AndroidOfflineMapsManager.kt +++ b/app/src/main/java/org/scottishtecharmy/soundscape/utils/AndroidOfflineMapsManager.kt @@ -27,7 +27,6 @@ import org.scottishtecharmy.soundscape.i18n.ComposeLocalizedStrings import org.scottishtecharmy.soundscape.network.DownloadStateCommon import org.scottishtecharmy.soundscape.screens.home.offlinemaps.NearbyExtractsState import java.io.File -import java.io.FileOutputStream private fun DownloadState.toCommon(): DownloadStateCommon = when (this) { is DownloadState.Idle -> DownloadStateCommon.Idle @@ -109,6 +108,7 @@ class AndroidOfflineMapsManager( private fun refreshDownloaded() { val dir = extractsDir() + deleteOrphanedSidecars(dir) _downloadedExtractsFc.value = findExtracts(dir.path) ?: FeatureCollection() } @@ -153,16 +153,16 @@ class AndroidOfflineMapsManager( // version's files once this one is published (see logicalBaseName below). val versionedFilename = "$logicalBase.v${System.currentTimeMillis()}.pmtiles" val path = "${extractsDir().path}/$versionedFilename" - try { - val moshi = GeoMoshi.registerAdapters(Moshi.Builder()).build() - val adapter = moshi.adapter(Feature::class.java) - FileOutputStream("$path.geojson").use { - it.write( - adapter.toJson(current).toByteArray() - ) - } + // The metadata sidecar is written by the downloader once the extract is saved, not here + // before it starts: a download that failed or was cancelled used to leave its sidecar + // behind, for an extract that was never there. + val metadataJson = try { + GeoMoshi.registerAdapters(Moshi.Builder()).build() + .adapter(Feature::class.java) + .toJson(current) } catch (e: Exception) { - Log.e(TAG, "Failed to write extract metadata", e) + Log.e(TAG, "Failed to encode extract metadata", e) + null } val extractSize = (current.properties?.get("extract-size") as? Number)?.toDouble() downloader.startDownload( @@ -170,6 +170,7 @@ class AndroidOfflineMapsManager( path, extractSize, logicalBaseName = logicalBase, + metadataJson = metadataJson, ) } diff --git a/app/src/main/java/org/scottishtecharmy/soundscape/utils/OfflineDownloader.kt b/app/src/main/java/org/scottishtecharmy/soundscape/utils/OfflineDownloader.kt index e7eba242b..64dc4d116 100644 --- a/app/src/main/java/org/scottishtecharmy/soundscape/utils/OfflineDownloader.kt +++ b/app/src/main/java/org/scottishtecharmy/soundscape/utils/OfflineDownloader.kt @@ -86,12 +86,16 @@ class OfflineDownloader(injectedFileDownloader: FileDownloader? = null) { * directory whose name starts with "." is deleted - this is what actually * retires a previous version of the same extract (see the comment above the rename below for * why in-place replacement isn't safe for pmtiles extracts that MapLibre may have opened). + * @param metadataJson If set, written to the ".geojson" sidecar once the + * download is published - and only then, so that a download which fails or is cancelled + * doesn't leave a sidecar behind for an extract that was never saved. */ fun startDownload( fileUrl: String, outputFilePath: String, extractSize: Double?, logicalBaseName: String? = null, + metadataJson: String? = null, ) { if (downloadJob?.isActive == true) { Log.w(TAG, "Download is already in progress.") @@ -162,6 +166,13 @@ class OfflineDownloader(injectedFileDownloader: FileDownloader? = null) { // are always in the same directory. if (tempFile.renameTo(finalFile)) { Log.i(TAG, "Download successful. File saved to: ${finalFile.path}") + if (metadataJson != null) { + try { + File("$outputFilePath.geojson").writeText(metadataJson) + } catch (e: Exception) { + Log.e(TAG, "Failed to write extract metadata", e) + } + } // Clean up old versions before publishing Success - an observer // reacting to Success (e.g. refreshing the extract list) should // never see a superseded version still on disk. diff --git a/app/src/main/java/org/scottishtecharmy/soundscape/utils/StorageUtils.kt b/app/src/main/java/org/scottishtecharmy/soundscape/utils/StorageUtils.kt index 356583168..ba0f7adca 100644 --- a/app/src/main/java/org/scottishtecharmy/soundscape/utils/StorageUtils.kt +++ b/app/src/main/java/org/scottishtecharmy/soundscape/utils/StorageUtils.kt @@ -155,6 +155,19 @@ fun getMetadata(pmtilesPath: String): Feature? { return null } +/** + * Delete the .geojson metadata sidecars in [dir] which have no extract next to them. Downloads + * used to write the sidecar before they started, and left it behind when they failed or were + * cancelled; those orphans are never listed, but they stay on the phone forever. + */ +fun deleteOrphanedSidecars(dir: File) { + dir.listFiles { file -> file.name.endsWith(".pmtiles.geojson") }?.forEach { sidecar -> + if (!File(dir, sidecar.name.removeSuffix(".geojson")).exists()) { + sidecar.delete() + } + } +} + fun findExtracts(path: String): FeatureCollection? { // Find any extracts that we have downloaded val extractsDir = File(path) diff --git a/app/src/test/java/org/scottishtecharmy/soundscape/OfflineDownloaderTest.kt b/app/src/test/java/org/scottishtecharmy/soundscape/OfflineDownloaderTest.kt index a7fbade0b..a336dc29c 100644 --- a/app/src/test/java/org/scottishtecharmy/soundscape/OfflineDownloaderTest.kt +++ b/app/src/test/java/org/scottishtecharmy/soundscape/OfflineDownloaderTest.kt @@ -16,6 +16,7 @@ import org.junit.Test import org.scottishtecharmy.soundscape.network.createFileDownloader import org.scottishtecharmy.soundscape.utils.DownloadState import org.scottishtecharmy.soundscape.utils.OfflineDownloader +import org.scottishtecharmy.soundscape.utils.deleteOrphanedSidecars import java.io.File /** @@ -114,12 +115,11 @@ class OfflineDownloaderTest { val unrelatedExtract = File(tempDir, "glasgow-gbx.bin").apply { writeText("unrelated") } val newOutputFile = File(tempDir, "glasgow-gb.v2000.bin") - // AndroidOfflineMapsManager.startDownload() writes this sidecar *before* calling - // startDownload - it must survive the post-publish cleanup, which previously deleted - // it (it starts with the logical prefix and its name isn't *exactly* - // newOutputFile.name), silently hiding every freshly downloaded extract from the - // offline-maps UI. - val newSidecar = File(tempDir, "glasgow-gb.v2000.bin.geojson").apply { writeText("{}") } + // The download writes its own sidecar once published, and it must survive the + // post-publish cleanup, which once deleted it (it starts with the logical prefix and + // its name isn't *exactly* newOutputFile.name), silently hiding every freshly + // downloaded extract from the offline-maps UI. + val newSidecar = File(tempDir, "glasgow-gb.v2000.bin.geojson") val fake = FakeResponses(listOf({ body(1000) })) val downloader = OfflineDownloader(fakeFileDownloader(fake)) @@ -128,6 +128,7 @@ class OfflineDownloaderTest { newOutputFile.path, extractSize = 1000.0, logicalBaseName = "glasgow-gb", + metadataJson = "{}", ) val state = runBlocking { @@ -164,7 +165,7 @@ class OfflineDownloaderTest { val unrelatedExtract = File(tempDir, "glasgow-gbx.bin").apply { writeText("unrelated") } val newOutputFile = File(tempDir, "glasgow-gb.v2000.bin") - val newSidecar = File(tempDir, "glasgow-gb.v2000.bin.geojson").apply { writeText("{}") } + val newSidecar = File(tempDir, "glasgow-gb.v2000.bin.geojson") val fake = FakeResponses(listOf({ body(1000) })) val downloader = OfflineDownloader(fakeFileDownloader(fake)) downloader.startDownload( @@ -172,6 +173,7 @@ class OfflineDownloaderTest { newOutputFile.path, extractSize = 1000.0, logicalBaseName = "glasgow-gb", + metadataJson = "{}", ) val state = runBlocking { @@ -256,4 +258,60 @@ class OfflineDownloaderTest { file.parentFile?.deleteRecursively() } } + + /** + * A download that fails must leave nothing behind - its metadata sidecar used to be written + * before the download started, and stayed on the phone forever with no extract next to it. + */ + @Test + fun failedDownloadLeavesNoSidecar() { + val tempDir = File(System.getProperty("java.io.tmpdir"), "offline-dl-${System.nanoTime()}") + tempDir.mkdirs() + try { + val outputFile = File(tempDir, "helsinki-fi.v2000.bin") + val fake = FakeResponses(listOf({ truncatedBody(advertised = 1000L, actual = 500) })) + val downloader = OfflineDownloader(fakeFileDownloader(fake)) + downloader.startDownload( + "https://example.test/extract", + outputFile.path, + extractSize = 1000.0, + logicalBaseName = "helsinki-fi", + metadataJson = "{}", + ) + + val state = runBlocking { + withTimeout(10_000) { + downloader.downloadState.first { + it is DownloadState.Success || it is DownloadState.Error + } + } + } + + assertTrue("expected Error but was $state", state is DownloadState.Error) + assertTrue("no sidecar for a failed download", tempDir.listFiles().isNullOrEmpty()) + } finally { + tempDir.deleteRecursively() + } + } + + @Test + fun orphanedSidecarsAreDeleted() { + val tempDir = File(System.getProperty("java.io.tmpdir"), "offline-dl-${System.nanoTime()}") + tempDir.mkdirs() + try { + val extract = File(tempDir, "glasgow-gb.v1000.pmtiles").apply { writeText("x") } + val sidecar = File(tempDir, "glasgow-gb.v1000.pmtiles.geojson").apply { writeText("{}") } + val orphan = File(tempDir, "helsinki-fi.v2000.pmtiles.geojson").apply { writeText("{}") } + val download = File(tempDir, "budapest-hu.v3000.pmtiles.downloading").apply { writeText("x") } + + deleteOrphanedSidecars(tempDir) + + assertTrue(extract.exists()) + assertTrue("an extract's own sidecar must survive", sidecar.exists()) + assertTrue("a sidecar with no extract should be deleted", !orphan.exists()) + assertTrue("a download in progress isn't touched", download.exists()) + } finally { + tempDir.deleteRecursively() + } + } } From 52001f34ba5e170cfe805d2e52b8b4bb3c068cdc Mon Sep 17 00:00:00 2001 From: Dave Craig Date: Mon, 28 Sep 2026 16:52:04 +0100 Subject: [PATCH 2/3] Say where the unnamed toilets in the category search test really are They're off Craigmillar Avenue near the James Gale Memorial, about 1km from Milngavie station - not by the station, as the comment (and the commit message of fff466c20) wrongly said. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01THRgoVbh1G3pVacd7csDqJ --- .../java/org/scottishtecharmy/soundscape/SearchTest.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/test/java/org/scottishtecharmy/soundscape/SearchTest.kt b/app/src/test/java/org/scottishtecharmy/soundscape/SearchTest.kt index caa62dcf3..d26a3a407 100644 --- a/app/src/test/java/org/scottishtecharmy/soundscape/SearchTest.kt +++ b/app/src/test/java/org/scottishtecharmy/soundscape/SearchTest.kt @@ -649,9 +649,10 @@ class SearchTest { @Test fun categorySearchNamesAnUnnamedPlaceByItsType() { runBlocking { - // The toilets by Milngavie station (OSM way 218224201) are an unnamed building. They - // used to be listed as "Milngavie" - their address - with nothing to say they were - // toilets, and twice, because the building crosses a tile boundary. + // The toilets near the James Gale Memorial in Milngavie (OSM way 218224201) are an + // unnamed building. They used to be listed as "Milngavie" - their address - with + // nothing to say they were toilets, and twice, because the building crosses a tile + // boundary. val currentLocation = LngLatAlt(-4.3092376, 55.9497288) val gridState = getGridStateForLocation(currentLocation, MAX_ZOOM_LEVEL, GRID_SIZE) val settlementState = getGridStateForLocation(currentLocation, 12, 3) From 73b616337abb3b63acd34d163f34cb7ad745f4d4 Mon Sep 17 00:00:00 2001 From: Dave Craig Date: Mon, 28 Sep 2026 17:21:43 +0100 Subject: [PATCH 3/3] Reinstate moving a marker's location from the Edit Marker screen Moving a marker by panning the full-screen map was lost in the move to the shared screen: MapContainerLibre's editBeaconLocation flag was no longer passed through PlatformMapContainer, and the screen always saved the original location. The map now takes an onBeaconLocationEdited callback which pins the marker to the camera centre and reports each new position, instead of mutating the caller's LngLatAlt during composition. Editing the location is a distinct mode with its own title, instructions and Cancel/Done (and system back cancels); the FAB and Delete Marker button are hidden while in it, and the FAB uses an edit-location icon. The now unused location_detail_exit_full_screen_for_edit_hint string is removed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01THRgoVbh1G3pVacd7csDqJ --- .../screens/home/home/PlatformMapContainer.kt | 2 + .../composeResources/values-ar/strings.xml | 1 - .../composeResources/values-bg/strings.xml | 1 - .../composeResources/values-bn/strings.xml | 1 - .../composeResources/values-ca/strings.xml | 1 - .../composeResources/values-cs/strings.xml | 1 - .../composeResources/values-da/strings.xml | 1 - .../composeResources/values-de/strings.xml | 1 - .../composeResources/values-el/strings.xml | 1 - .../values-en-rGB/strings.xml | 1 - .../composeResources/values-es/strings.xml | 1 - .../composeResources/values-et/strings.xml | 1 - .../composeResources/values-fa/strings.xml | 1 - .../composeResources/values-fi/strings.xml | 1 - .../values-fr-rCA/strings.xml | 1 - .../composeResources/values-fr/strings.xml | 1 - .../composeResources/values-ha/strings.xml | 1 - .../composeResources/values-hi/strings.xml | 1 - .../composeResources/values-hr/strings.xml | 1 - .../composeResources/values-hu/strings.xml | 1 - .../composeResources/values-in/strings.xml | 1 - .../composeResources/values-is/strings.xml | 1 - .../composeResources/values-it/strings.xml | 1 - .../composeResources/values-ja/strings.xml | 1 - .../composeResources/values-ko/strings.xml | 1 - .../composeResources/values-mr/strings.xml | 1 - .../composeResources/values-nb/strings.xml | 1 - .../composeResources/values-nl/strings.xml | 1 - .../composeResources/values-pl/strings.xml | 1 - .../values-pt-rBR/strings.xml | 1 - .../composeResources/values-pt/strings.xml | 1 - .../composeResources/values-ro/strings.xml | 1 - .../composeResources/values-ru/strings.xml | 1 - .../composeResources/values-sk/strings.xml | 1 - .../composeResources/values-sl/strings.xml | 1 - .../composeResources/values-sr/strings.xml | 1 - .../composeResources/values-sv/strings.xml | 1 - .../composeResources/values-sw/strings.xml | 1 - .../composeResources/values-ta/strings.xml | 1 - .../composeResources/values-te/strings.xml | 1 - .../composeResources/values-th/strings.xml | 1 - .../composeResources/values-tr/strings.xml | 1 - .../composeResources/values-uk/strings.xml | 1 - .../composeResources/values-ur/strings.xml | 1 - .../composeResources/values-vi/strings.xml | 1 - .../values-zh-rCN/strings.xml | 1 - .../composeResources/values/strings.xml | 6 +- .../screens/home/home/MapContainerLibre.kt | 31 +++- .../screens/home/home/PlatformMapContainer.kt | 1 + .../SharedSaveAndEditMarkerScreen.kt | 148 +++++++++++++----- .../screens/home/home/IosMapContainer.kt | 2 + .../screens/home/home/PlatformMapContainer.kt | 2 + 52 files changed, 144 insertions(+), 93 deletions(-) diff --git a/shared/src/androidMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt b/shared/src/androidMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt index afb09244f..d22992e49 100644 --- a/shared/src/androidMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt +++ b/shared/src/androidMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt @@ -28,6 +28,7 @@ actual fun PlatformMapContainer( extractGeometry: Geometry?, forceOnlineTiles: Boolean, onInteractionChanged: (Boolean) -> Unit, + onBeaconLocationEdited: ((LngLatAlt) -> Unit)?, ) { val context = LocalContext.current @@ -109,5 +110,6 @@ actual fun PlatformMapContainer( baseStyle = baseStyle, extractGeometry = extractGeometry, onInteractionChanged = onInteractionChanged, + onBeaconLocationEdited = onBeaconLocationEdited, ) } diff --git a/shared/src/commonMain/composeResources/values-ar/strings.xml b/shared/src/commonMain/composeResources/values-ar/strings.xml index 3193c2e40..676113db1 100644 --- a/shared/src/commonMain/composeResources/values-ar/strings.xml +++ b/shared/src/commonMain/composeResources/values-ar/strings.xml @@ -560,7 +560,6 @@ عرض الخريطة بملء الشاشة الخروج من الخريطة بملء الشاشة عرض الخريطة بملء الشاشة وتعديل موقع العلامة - الخروج من وضع تعديل موقع العلامة بدء المسار إيقاف المسار تعديل المسار diff --git a/shared/src/commonMain/composeResources/values-bg/strings.xml b/shared/src/commonMain/composeResources/values-bg/strings.xml index 6362a3a7d..f1f71051a 100644 --- a/shared/src/commonMain/composeResources/values-bg/strings.xml +++ b/shared/src/commonMain/composeResources/values-bg/strings.xml @@ -80,7 +80,6 @@ Показване на картата на цял екран излезете от картата на цял екран Показване на картата на цял екран за редактиране на местоположението на маркера - Изход от режима за редактиране на местоположението на маркера Стартирай маршрута Спри маршрута Редактирай маршрута diff --git a/shared/src/commonMain/composeResources/values-bn/strings.xml b/shared/src/commonMain/composeResources/values-bn/strings.xml index 54f1797ab..59f202f67 100644 --- a/shared/src/commonMain/composeResources/values-bn/strings.xml +++ b/shared/src/commonMain/composeResources/values-bn/strings.xml @@ -1015,7 +1015,6 @@ মানচিত্রটি পূর্ণ পর্দা করুন পূর্ণ পর্দার মানচিত্র থেকে বের হতে মানচিত্রটি পূর্ণ পর্দা করুন এবং মার্কারের অবস্থান সম্পাদনা করুন - মার্কার অবস্থান সম্পাদনা মোড থেকে প্রস্থান করুন রুট শুরু করুন রুট বন্ধ করুন রুট সম্পাদনা করুন diff --git a/shared/src/commonMain/composeResources/values-ca/strings.xml b/shared/src/commonMain/composeResources/values-ca/strings.xml index d7ecea287..79c363afa 100644 --- a/shared/src/commonMain/composeResources/values-ca/strings.xml +++ b/shared/src/commonMain/composeResources/values-ca/strings.xml @@ -80,7 +80,6 @@ Mostra el mapa a pantalla completa sortir del mapa a pantalla completa Mostra el mapa a pantalla completa i edita la ubicació del marcador - Surt del mode d'edició de la ubicació del marcador Inicia la ruta Atura la ruta Edita la ruta diff --git a/shared/src/commonMain/composeResources/values-cs/strings.xml b/shared/src/commonMain/composeResources/values-cs/strings.xml index cc6addcb3..968b0c6d9 100644 --- a/shared/src/commonMain/composeResources/values-cs/strings.xml +++ b/shared/src/commonMain/composeResources/values-cs/strings.xml @@ -792,7 +792,6 @@ Zobrazit mapu na celou obrazovku ukončit zobrazení mapy na celou obrazovku Zobrazit mapu na celou obrazovku a upravit polohu značky - Ukončit režim úpravy polohy značky Spustit trasu Zastavit trasu Upravit trasu diff --git a/shared/src/commonMain/composeResources/values-da/strings.xml b/shared/src/commonMain/composeResources/values-da/strings.xml index 337e236eb..f473995bd 100644 --- a/shared/src/commonMain/composeResources/values-da/strings.xml +++ b/shared/src/commonMain/composeResources/values-da/strings.xml @@ -1257,7 +1257,6 @@ lukke popuppen og fortsætte tutorialen Start lydfyr ved dette mærke Vis kortet i fuld skærm, og rediger mærkets placering - Afslut redigering af mærkets placering På %1$s lige før %2$s På %1$s lige efter %2$s Nær krydset ved %1$s diff --git a/shared/src/commonMain/composeResources/values-de/strings.xml b/shared/src/commonMain/composeResources/values-de/strings.xml index 641a4762d..137e9553d 100644 --- a/shared/src/commonMain/composeResources/values-de/strings.xml +++ b/shared/src/commonMain/composeResources/values-de/strings.xml @@ -1257,7 +1257,6 @@ das Popup schließen und das Tutorial fortsetzen Audiobeacon an dieser Markierung starten Karte im Vollbild anzeigen und den Markierungsstandort bearbeiten - Bearbeitungsmodus für Markierungsstandort beenden Auf %1$s, kurz vor %2$s Auf %1$s, kurz nach %2$s In der Nähe der Kreuzung von %1$s diff --git a/shared/src/commonMain/composeResources/values-el/strings.xml b/shared/src/commonMain/composeResources/values-el/strings.xml index 068034ea1..7b7e34fd3 100644 --- a/shared/src/commonMain/composeResources/values-el/strings.xml +++ b/shared/src/commonMain/composeResources/values-el/strings.xml @@ -1257,7 +1257,6 @@ κλείσετε το αναδυόμενο παράθυρο και να συνεχίσετε τον οδηγό Έναρξη ηχητικού σήματος σε αυτόν τον δείκτη Μεγιστοποίηση του χάρτη σε πλήρη οθόνη και επεξεργασία της θέσης του δείκτη - Έξοδος από τη λειτουργία επεξεργασίας της θέσης του δείκτη Στην %1$s, λίγο πριν από %2$s Στην %1$s, λίγο μετά από %2$s Κοντά στη διασταύρωση %1$s diff --git a/shared/src/commonMain/composeResources/values-en-rGB/strings.xml b/shared/src/commonMain/composeResources/values-en-rGB/strings.xml index ffae1de79..4edb018d4 100644 --- a/shared/src/commonMain/composeResources/values-en-rGB/strings.xml +++ b/shared/src/commonMain/composeResources/values-en-rGB/strings.xml @@ -1257,7 +1257,6 @@ close the popup and continue the tutorial Start audio beacon at this marker Make the map full screen and edit the marker location - Exit marker location editing mode On %1$s, just before %2$s On %1$s, just after %2$s Near the intersection of %1$s diff --git a/shared/src/commonMain/composeResources/values-es/strings.xml b/shared/src/commonMain/composeResources/values-es/strings.xml index 299289e8e..4d96c70b6 100644 --- a/shared/src/commonMain/composeResources/values-es/strings.xml +++ b/shared/src/commonMain/composeResources/values-es/strings.xml @@ -1261,7 +1261,6 @@ cerrar la ventana emergente y continuar el tutorial Iniciar la señal de audio en este marcador Poner el mapa en pantalla completa y editar la ubicación del marcador - Salir del modo de edición de la ubicación del marcador {es:En %1$s}, justo antes {es:de %2$s} {es:En %1$s}, justo después {es:de %2$s} Cerca de la intersección de %1$s diff --git a/shared/src/commonMain/composeResources/values-et/strings.xml b/shared/src/commonMain/composeResources/values-et/strings.xml index 28e2494fc..f74d29c1f 100644 --- a/shared/src/commonMain/composeResources/values-et/strings.xml +++ b/shared/src/commonMain/composeResources/values-et/strings.xml @@ -79,7 +79,6 @@ Kuva kaart täisekraanil väljuda kaardi täisekraanvaatest Kuva kaart täisekraanil ja muuda markeri asukohta - Välju markeri asukoha muutmise režiimist Alusta marsruuti Peata marsruut Muuda marsruuti diff --git a/shared/src/commonMain/composeResources/values-fa/strings.xml b/shared/src/commonMain/composeResources/values-fa/strings.xml index f8e284cb3..cf7759b9d 100644 --- a/shared/src/commonMain/composeResources/values-fa/strings.xml +++ b/shared/src/commonMain/composeResources/values-fa/strings.xml @@ -1258,7 +1258,6 @@ پنجره‌ی پاپ‌آپ را ببندید و آموزش را ادامه دهید فعال‌سازی جهت‌نمای صوتی روی این نشانه نقشه را در حالت تمام‌صفحه قرار دهید و مکان نشانه را ویرایش کنید - از حالت ویرایش مکان نشانه خارج شوید در %1$s درست قبل از %2$s در %1$s درست بعد از %2$s نزدیک تقاطع %1$s diff --git a/shared/src/commonMain/composeResources/values-fi/strings.xml b/shared/src/commonMain/composeResources/values-fi/strings.xml index a3c638782..436774b85 100644 --- a/shared/src/commonMain/composeResources/values-fi/strings.xml +++ b/shared/src/commonMain/composeResources/values-fi/strings.xml @@ -1257,7 +1257,6 @@ sulje ponnahdusikkuna ja jatka tutoriaalia Käynnistä äänimajakka tälle merkitsimelle Näytä kartta koko näytöllä ja muokkaa merkitsimen sijaintia - Poistu merkitsimen sijainnin muokkaustilasta {Kadulla %1$s} juuri ennen kohdetta %2$s {Kadulla %1$s} juuri kohteen %2$s jälkeen Lähellä risteystä %1$s diff --git a/shared/src/commonMain/composeResources/values-fr-rCA/strings.xml b/shared/src/commonMain/composeResources/values-fr-rCA/strings.xml index ae0094778..b74224bfc 100644 --- a/shared/src/commonMain/composeResources/values-fr-rCA/strings.xml +++ b/shared/src/commonMain/composeResources/values-fr-rCA/strings.xml @@ -1261,7 +1261,6 @@ fermer la fenêtre contextuelle et continuer le tutoriel Démarrer la balise sonore sur ce marqueur Afficher la carte en plein écran et modifier l’emplacement du marqueur - Quitter le mode d’édition de l’emplacement du marqueur {fr:Sur %1$s} juste {fr:avant %2$s} {fr:Sur %1$s} juste {fr:après %2$s} Près de l’intersection de %1$s diff --git a/shared/src/commonMain/composeResources/values-fr/strings.xml b/shared/src/commonMain/composeResources/values-fr/strings.xml index e7f8c0a04..541573674 100644 --- a/shared/src/commonMain/composeResources/values-fr/strings.xml +++ b/shared/src/commonMain/composeResources/values-fr/strings.xml @@ -1261,7 +1261,6 @@ fermer la fenêtre contextuelle et continuer le tutoriel Démarrer la balise sonore sur ce marqueur Afficher la carte en plein écran et modifier l’emplacement du marqueur - Quitter le mode d’édition de l’emplacement du marqueur {fr:Sur %1$s} juste {fr:avant %2$s} {fr:Sur %1$s} juste {fr:après %2$s} Près de l’intersection de %1$s diff --git a/shared/src/commonMain/composeResources/values-ha/strings.xml b/shared/src/commonMain/composeResources/values-ha/strings.xml index ae7526441..69ab7174d 100644 --- a/shared/src/commonMain/composeResources/values-ha/strings.xml +++ b/shared/src/commonMain/composeResources/values-ha/strings.xml @@ -258,7 +258,6 @@ Faɗaɗa taswira zuwa cikakken allo fita daga taswirar cikakken allo Faɗaɗa taswira zuwa cikakken allo don gyara wurin alama - Fita daga yanayin gyara wurin alama Fara Tafarki Tsayar da Tafarki Gyara Tafarki diff --git a/shared/src/commonMain/composeResources/values-hi/strings.xml b/shared/src/commonMain/composeResources/values-hi/strings.xml index 3d25446b0..7f3506647 100644 --- a/shared/src/commonMain/composeResources/values-hi/strings.xml +++ b/shared/src/commonMain/composeResources/values-hi/strings.xml @@ -64,7 +64,6 @@ मानचित्र को पूर्ण स्क्रीन बनाएँ पूर्ण स्क्रीन मानचित्र से बाहर निकलें मानचित्र को पूर्ण स्क्रीन बनाएँ और मार्कर का स्थान संपादित करें - मार्कर स्थान संपादन मोड से बाहर निकलें मार्ग शुरू करें मार्ग रोकें मार्ग संपादित करें diff --git a/shared/src/commonMain/composeResources/values-hr/strings.xml b/shared/src/commonMain/composeResources/values-hr/strings.xml index 268074af0..9ce368c71 100644 --- a/shared/src/commonMain/composeResources/values-hr/strings.xml +++ b/shared/src/commonMain/composeResources/values-hr/strings.xml @@ -792,7 +792,6 @@ Prikaži kartu preko cijelog zaslona izašli iz karte preko cijelog zaslona Prikaži kartu preko cijelog zaslona i uredi lokaciju oznake - Izađi iz načina uređivanja lokacije oznake Pokreni rutu Zaustavi rutu Uredi rutu diff --git a/shared/src/commonMain/composeResources/values-hu/strings.xml b/shared/src/commonMain/composeResources/values-hu/strings.xml index 2a8090b93..f75b95cbf 100644 --- a/shared/src/commonMain/composeResources/values-hu/strings.xml +++ b/shared/src/commonMain/composeResources/values-hu/strings.xml @@ -792,7 +792,6 @@ Térkép teljes képernyőre állítása kilépj a teljes képernyős térképből Térkép teljes képernyőre állítása és a jelölő helyzetének szerkesztése - Kilépés a jelölő helyzetének szerkesztési módjából Útvonal indítása Útvonal leállítása Útvonal szerkesztése diff --git a/shared/src/commonMain/composeResources/values-in/strings.xml b/shared/src/commonMain/composeResources/values-in/strings.xml index ecd51a9e1..7a34fc05f 100644 --- a/shared/src/commonMain/composeResources/values-in/strings.xml +++ b/shared/src/commonMain/composeResources/values-in/strings.xml @@ -792,7 +792,6 @@ Menampilkan peta dalam layar penuh keluar dari peta layar penuh Menampilkan peta dalam layar penuh dan mengedit lokasi penanda - Keluar dari mode pengeditan lokasi penanda Mulai Rute Hentikan Rute Edit Rute diff --git a/shared/src/commonMain/composeResources/values-is/strings.xml b/shared/src/commonMain/composeResources/values-is/strings.xml index 693b7c39f..cce7a538f 100644 --- a/shared/src/commonMain/composeResources/values-is/strings.xml +++ b/shared/src/commonMain/composeResources/values-is/strings.xml @@ -1257,7 +1257,6 @@ loka sprettiglugga og halda áfram með leiðsögunámskeiðið Kveikja á hljóðvita á þessu merki Gera kortið fullskjá og breyta staðsetningu merkisins - Hætta að breyta staðsetningu merkisins Á %1$s rétt fyrir %2$s Á %1$s rétt eftir %2$s Nálægt gatnamótum %1$s diff --git a/shared/src/commonMain/composeResources/values-it/strings.xml b/shared/src/commonMain/composeResources/values-it/strings.xml index 7f5f6acde..c9cf03888 100644 --- a/shared/src/commonMain/composeResources/values-it/strings.xml +++ b/shared/src/commonMain/composeResources/values-it/strings.xml @@ -1261,7 +1261,6 @@ chiudi il popup e continua il tutorial Avviare l'audiofaro su questo indicatore Mettere la mappa a schermo intero e modificare la posizione dell'indicatore - Uscire dalla modalità di modifica della posizione dell'indicatore {it:Su %1$s} appena prima {it:di %2$s} {it:Su %1$s} appena dopo %2$s Nei pressi dell'incrocio tra %1$s diff --git a/shared/src/commonMain/composeResources/values-ja/strings.xml b/shared/src/commonMain/composeResources/values-ja/strings.xml index 7cd854029..8e3d6f77e 100644 --- a/shared/src/commonMain/composeResources/values-ja/strings.xml +++ b/shared/src/commonMain/composeResources/values-ja/strings.xml @@ -1253,7 +1253,6 @@ ポップアップを閉じてチュートリアルを続行します このマーカーで音声ビーコンを開始する 地図を全画面表示にしてマーカーの位置を編集する - マーカーの位置編集モードを終了する %1$s(%2$s の手前) %1$s(%2$s の直後) %1$s の交差点付近 diff --git a/shared/src/commonMain/composeResources/values-ko/strings.xml b/shared/src/commonMain/composeResources/values-ko/strings.xml index 63f4fdad0..f5cbd9ff9 100644 --- a/shared/src/commonMain/composeResources/values-ko/strings.xml +++ b/shared/src/commonMain/composeResources/values-ko/strings.xml @@ -80,7 +80,6 @@ 지도를 전체 화면으로 표시 전체 화면 지도 종료 지도를 전체 화면으로 표시하고 마커 위치 편집 - 마커 위치 편집 모드 종료 경로 시작 경로 중지 경로 편집 diff --git a/shared/src/commonMain/composeResources/values-mr/strings.xml b/shared/src/commonMain/composeResources/values-mr/strings.xml index 1354459e9..ec95762a6 100644 --- a/shared/src/commonMain/composeResources/values-mr/strings.xml +++ b/shared/src/commonMain/composeResources/values-mr/strings.xml @@ -1028,7 +1028,6 @@ नकाशा पूर्णस्क्रीन करा पूर्णस्क्रीन नकाशामधून बाहेर पडा नकाशा पूर्णस्क्रीन करा आणि मार्करचे स्थान संपादित करा - मार्कर स्थान संपादन मोडमधून बाहेर पडा मार्ग सुरू करा मार्ग थांबवा मार्ग संपादित करा diff --git a/shared/src/commonMain/composeResources/values-nb/strings.xml b/shared/src/commonMain/composeResources/values-nb/strings.xml index fbb2d3dff..2f7e5b34e 100644 --- a/shared/src/commonMain/composeResources/values-nb/strings.xml +++ b/shared/src/commonMain/composeResources/values-nb/strings.xml @@ -1257,7 +1257,6 @@ lukk popupen og fortsett gjennomgangen Start lydsignal på denne markøren Vis kartet i fullskjerm og rediger markørens plassering - Avslutt redigering av markørens plassering På %1$s rett før %2$s På %1$s rett etter %2$s Nær veikrysset %1$s diff --git a/shared/src/commonMain/composeResources/values-nl/strings.xml b/shared/src/commonMain/composeResources/values-nl/strings.xml index 7bfbae06f..a72ee5f35 100644 --- a/shared/src/commonMain/composeResources/values-nl/strings.xml +++ b/shared/src/commonMain/composeResources/values-nl/strings.xml @@ -1257,7 +1257,6 @@ de pop-up sluiten en doorgaan met de tutorial Audiobaken starten op deze markering De kaart op volledig scherm weergeven en de locatie van de markering bewerken - Bewerking van de markeringslocatie afsluiten Op %1$s net voor %2$s Op %1$s net na %2$s Bij het kruispunt van %1$s diff --git a/shared/src/commonMain/composeResources/values-pl/strings.xml b/shared/src/commonMain/composeResources/values-pl/strings.xml index fec17f5c8..9aeb9787c 100644 --- a/shared/src/commonMain/composeResources/values-pl/strings.xml +++ b/shared/src/commonMain/composeResources/values-pl/strings.xml @@ -1265,7 +1265,6 @@ zamknąć okienko i kontynuować samouczek Uruchom dźwięk naprowadzający na tym znaczniku wyświetlić mapę w trybie pełnoekranowym i edytować lokalizację znacznika - zakończ tryb edycji lokalizacji znacznika Na %1$s tuż przed %2$s Na %1$s tuż po %2$s W pobliżu skrzyżowania %1$s diff --git a/shared/src/commonMain/composeResources/values-pt-rBR/strings.xml b/shared/src/commonMain/composeResources/values-pt-rBR/strings.xml index aab01823e..60d931b96 100644 --- a/shared/src/commonMain/composeResources/values-pt-rBR/strings.xml +++ b/shared/src/commonMain/composeResources/values-pt-rBR/strings.xml @@ -1261,7 +1261,6 @@ fechar o pop‑up e continuar o tutorial Iniciar Sinalizador Sonoro neste Favorito Exibir o mapa em tela cheia e editar a localização do favorito - Sair do modo de edição da localização do favorito {pt:Em %1$s}, logo antes {pt:de %2$s} {pt:Em %1$s}, logo {pt:após %2$s} Perto do cruzamento de %1$s diff --git a/shared/src/commonMain/composeResources/values-pt/strings.xml b/shared/src/commonMain/composeResources/values-pt/strings.xml index eb1395576..141f4b9b2 100644 --- a/shared/src/commonMain/composeResources/values-pt/strings.xml +++ b/shared/src/commonMain/composeResources/values-pt/strings.xml @@ -1261,7 +1261,6 @@ fechar o pop‑up e continuar o tutorial Iniciar Sinal de Áudio neste Marco colocar o mapa em ecrã inteiro e editar a localização do marco - sair do modo de edição da localização do marco {pt:Em %1$s}, pouco antes {pt:de %2$s} {pt:Em %1$s}, pouco depois {pt:de %2$s} Perto do cruzamento de %1$s diff --git a/shared/src/commonMain/composeResources/values-ro/strings.xml b/shared/src/commonMain/composeResources/values-ro/strings.xml index 2abf83fbb..96ed049f4 100644 --- a/shared/src/commonMain/composeResources/values-ro/strings.xml +++ b/shared/src/commonMain/composeResources/values-ro/strings.xml @@ -64,7 +64,6 @@ Afișează harta pe tot ecranul ieși din harta pe tot ecranul Afișează harta pe tot ecranul și editează locația marcajului - Ieși din modul de editare a locației marcajului Pornește ruta Oprește ruta Editează ruta diff --git a/shared/src/commonMain/composeResources/values-ru/strings.xml b/shared/src/commonMain/composeResources/values-ru/strings.xml index 2d8722554..39ec7ede5 100644 --- a/shared/src/commonMain/composeResources/values-ru/strings.xml +++ b/shared/src/commonMain/composeResources/values-ru/strings.xml @@ -1265,7 +1265,6 @@ закрыть всплывающее окно и продолжить руководство Включить звуковой маяк на этой отметке Развернуть карту на весь экран и отредактировать местоположение отметки - Выйти из режима редактирования местоположения отметки На %1$s, прямо перед %2$s На %1$s, сразу после %2$s Рядом с перекрёстком %1$s diff --git a/shared/src/commonMain/composeResources/values-sk/strings.xml b/shared/src/commonMain/composeResources/values-sk/strings.xml index 83d47db8c..3f2e34a08 100644 --- a/shared/src/commonMain/composeResources/values-sk/strings.xml +++ b/shared/src/commonMain/composeResources/values-sk/strings.xml @@ -792,7 +792,6 @@ Zobraziť mapu na celú obrazovku ukončiť zobrazenie mapy na celú obrazovku Zobraziť mapu na celú obrazovku a upraviť polohu značky - Ukončiť režim úpravy polohy značky Spustiť trasu Zastaviť trasu Upraviť trasu diff --git a/shared/src/commonMain/composeResources/values-sl/strings.xml b/shared/src/commonMain/composeResources/values-sl/strings.xml index 486e929bc..935669764 100644 --- a/shared/src/commonMain/composeResources/values-sl/strings.xml +++ b/shared/src/commonMain/composeResources/values-sl/strings.xml @@ -80,7 +80,6 @@ Preklopi zemljevid v celozaslonski način zaprete celozaslonski zemljevid Preklopi zemljevid v celozaslonski način in uredi lokacijo oznake - Zapri način urejanja lokacije oznake Zaženi pot Zaustavi pot Uredi pot diff --git a/shared/src/commonMain/composeResources/values-sr/strings.xml b/shared/src/commonMain/composeResources/values-sr/strings.xml index ba3b8087a..4d1436034 100644 --- a/shared/src/commonMain/composeResources/values-sr/strings.xml +++ b/shared/src/commonMain/composeResources/values-sr/strings.xml @@ -436,7 +436,6 @@ Прикажи мапу преко целог екрана изађете из мапе преко целог екрана Прикажи мапу преко целог екрана и уреди локацију маркера - Изађи из режима уређивања локације маркера Покрени руту Заустави руту Уреди руту diff --git a/shared/src/commonMain/composeResources/values-sv/strings.xml b/shared/src/commonMain/composeResources/values-sv/strings.xml index 6079e8b37..efc38686c 100644 --- a/shared/src/commonMain/composeResources/values-sv/strings.xml +++ b/shared/src/commonMain/composeResources/values-sv/strings.xml @@ -1257,7 +1257,6 @@ stänga popupen och fortsätta självstudien Starta ljudfyr på den här platsmarkören Gör kartan till helskärm och redigera platsmarkörens läge - Avsluta redigering av platsmarkörens läge På %1$s precis innan %2$s På %1$s precis efter %2$s Nära korsningen vid %1$s diff --git a/shared/src/commonMain/composeResources/values-sw/strings.xml b/shared/src/commonMain/composeResources/values-sw/strings.xml index 6e97129ac..58e5e653b 100644 --- a/shared/src/commonMain/composeResources/values-sw/strings.xml +++ b/shared/src/commonMain/composeResources/values-sw/strings.xml @@ -837,7 +837,6 @@ Fanya ramani ionekane kwenye skrini nzima kutoka kwenye ramani ya skrini nzima Fanya ramani ionekane kwenye skrini nzima na uhariri mahali pa alama - Toka kwenye hali ya kuhariri mahali pa alama Anzisha Njia Simamisha Njia Hariri Njia diff --git a/shared/src/commonMain/composeResources/values-ta/strings.xml b/shared/src/commonMain/composeResources/values-ta/strings.xml index d7b8433e0..7cfc50792 100644 --- a/shared/src/commonMain/composeResources/values-ta/strings.xml +++ b/shared/src/commonMain/composeResources/values-ta/strings.xml @@ -80,7 +80,6 @@ வரைபடத்தை முழுத்திரையாக்கு முழுத்திரை வரைபடத்திலிருந்து வெளியேற வரைபடத்தை முழுத்திரையாக்கி குறிப்பானின் இருப்பிடத்தைத் திருத்து - குறிப்பான் இருப்பிடத் திருத்த முறையிலிருந்து வெளியேறு பாதையைத் தொடங்கு பாதையை நிறுத்து பாதையைத் திருத்து diff --git a/shared/src/commonMain/composeResources/values-te/strings.xml b/shared/src/commonMain/composeResources/values-te/strings.xml index b78d54bfd..8010bc0c4 100644 --- a/shared/src/commonMain/composeResources/values-te/strings.xml +++ b/shared/src/commonMain/composeResources/values-te/strings.xml @@ -80,7 +80,6 @@ మ్యాప్‌ను పూర్తి తెరగా చేయడానికి పూర్తి తెర మ్యాప్ నుండి నిష్క్రమించడానికి మ్యాప్‌ను పూర్తి తెరగా చేసి మార్కర్ స్థానాన్ని సవరించడానికి - మార్కర్ స్థాన సవరణ మోడ్ నుండి నిష్క్రమించడానికి రూట్‌ను ప్రారంభించు రూట్‌ను ఆపివేయి రూట్‌ను సవరించు diff --git a/shared/src/commonMain/composeResources/values-th/strings.xml b/shared/src/commonMain/composeResources/values-th/strings.xml index 7484e0e3a..34ea359b9 100644 --- a/shared/src/commonMain/composeResources/values-th/strings.xml +++ b/shared/src/commonMain/composeResources/values-th/strings.xml @@ -258,7 +258,6 @@ แสดงแผนที่แบบเต็มหน้าจอ ออกจากแผนที่แบบเต็มหน้าจอ แสดงแผนที่แบบเต็มหน้าจอและแก้ไขตำแหน่งหมุด - ออกจากโหมดแก้ไขตำแหน่งหมุด เริ่มเส้นทาง หยุดเส้นทาง แก้ไขเส้นทาง diff --git a/shared/src/commonMain/composeResources/values-tr/strings.xml b/shared/src/commonMain/composeResources/values-tr/strings.xml index ad943f216..637cd40f8 100644 --- a/shared/src/commonMain/composeResources/values-tr/strings.xml +++ b/shared/src/commonMain/composeResources/values-tr/strings.xml @@ -86,7 +86,6 @@ Haritayı tam ekran yapın Tam ekran haritadan çıkın Haritayı tam ekran yapın ve kayıtlı nokta konumunu düzenleyin - Kayıtlı nokta konumu düzenleme modundan çıkın Rotayı Başlat Rotayı Durdur Rotayı Düzenle diff --git a/shared/src/commonMain/composeResources/values-uk/strings.xml b/shared/src/commonMain/composeResources/values-uk/strings.xml index d894a0b54..414c4f2bc 100644 --- a/shared/src/commonMain/composeResources/values-uk/strings.xml +++ b/shared/src/commonMain/composeResources/values-uk/strings.xml @@ -1265,7 +1265,6 @@ закрити спливаюче вікно і продовжити інтерактивний тур Запустити звуковий маячок на цій мітці Розгорнути карту на весь екран та відредагувати місцезнаходження мітки - Вийти з режиму редагування місцезнаходження мітки На %1$s, одразу перед %2$s На %1$s, одразу після %2$s Поблизу перехрестя %1$s diff --git a/shared/src/commonMain/composeResources/values-ur/strings.xml b/shared/src/commonMain/composeResources/values-ur/strings.xml index 392d6d649..9509a7e50 100644 --- a/shared/src/commonMain/composeResources/values-ur/strings.xml +++ b/shared/src/commonMain/composeResources/values-ur/strings.xml @@ -614,7 +614,6 @@ نقشے کو مکمل اسکرین بنائیں مکمل اسکرین نقشے سے باہر نکلیں نقشے کو مکمل اسکرین بنائیں اور مارکر کا مقام ترمیم کریں - مارکر مقام ترمیمی موڈ سے باہر نکلیں روٹ شروع کریں روٹ روکیں روٹ میں ترمیم کریں diff --git a/shared/src/commonMain/composeResources/values-vi/strings.xml b/shared/src/commonMain/composeResources/values-vi/strings.xml index 0418b71c2..1f2566860 100644 --- a/shared/src/commonMain/composeResources/values-vi/strings.xml +++ b/shared/src/commonMain/composeResources/values-vi/strings.xml @@ -614,7 +614,6 @@ Xem bản đồ toàn màn hình Thoát bản đồ toàn màn hình Xem bản đồ toàn màn hình và chỉnh sửa vị trí điểm đánh dấu - Thoát chế độ chỉnh sửa vị trí điểm đánh dấu Bắt đầu lộ trình Dừng lộ trình Chỉnh sửa lộ trình diff --git a/shared/src/commonMain/composeResources/values-zh-rCN/strings.xml b/shared/src/commonMain/composeResources/values-zh-rCN/strings.xml index c0de04088..3f13110cd 100644 --- a/shared/src/commonMain/composeResources/values-zh-rCN/strings.xml +++ b/shared/src/commonMain/composeResources/values-zh-rCN/strings.xml @@ -64,7 +64,6 @@ 将地图全屏显示 退出全屏地图 将地图全屏显示并编辑标记点位置 - 退出标记点位置编辑模式 开始路线 停止路线 编辑路线 diff --git a/shared/src/commonMain/composeResources/values/strings.xml b/shared/src/commonMain/composeResources/values/strings.xml index 41a6f1420..2b46f504f 100644 --- a/shared/src/commonMain/composeResources/values/strings.xml +++ b/shared/src/commonMain/composeResources/values/strings.xml @@ -186,8 +186,10 @@ Exit the full-screen map Make the map full screen and edit the marker location - - Exit marker location editing mode + + Edit location + + Drag the map to move the marker's location. Tap on Done to keep the new location, or Cancel to leave it unchanged. Start Route diff --git a/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/MapContainerLibre.kt b/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/MapContainerLibre.kt index fd3898457..548c79603 100644 --- a/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/MapContainerLibre.kt +++ b/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/MapContainerLibre.kt @@ -11,7 +11,10 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap @@ -91,7 +94,8 @@ fun FullScreenMapFab( * @param beaconLocation An optional location to show a beacon marker * @param routeData Optional route data to display route waypoint markers * @param modifier Modifier for the map container - * @param editBeaconLocation If true, the beacon location tracks the camera center + * @param onBeaconLocationEdited If non-null, the beacon marker is pinned to the camera center so + * that panning the map moves it, and each new location is reported through this callback * @param currentBeaconWaypointIndex The waypoint index the beacon marker currently represents * (0-based); shown as a 1-based number label on the beacon marker, matching route waypoint markers * @param onMapLongClick Callback when the map is long-pressed, receives the location @@ -119,7 +123,7 @@ fun MapContainerLibre( beaconLocation: LngLatAlt?, routeData: RouteWithMarkers?, modifier: Modifier = Modifier, - editBeaconLocation: Boolean = false, + onBeaconLocationEdited: ((LngLatAlt) -> Unit)? = null, currentBeaconWaypointIndex: Int = 0, onMapLongClick: ((LngLatAlt) -> Boolean)? = null, baseStyle: BaseStyle, @@ -154,9 +158,20 @@ fun MapContainerLibre( } val styleState = rememberStyleState() - if (editBeaconLocation && (beaconLocation != null)) { - beaconLocation.longitude = cameraState.position.target.longitude - beaconLocation.latitude = cameraState.position.target.latitude + val editingBeacon = onBeaconLocationEdited != null + val currentOnBeaconLocationEdited by rememberUpdatedState(onBeaconLocationEdited) + if (editingBeacon) { + LaunchedEffect(cameraState) { + snapshotFlow { cameraState.position.target }.collect { target -> + currentOnBeaconLocationEdited?.invoke(LngLatAlt(target.longitude, target.latitude)) + } + } + } + val drawnBeaconLocation = if (editingBeacon) { + val target = cameraState.position.target + LngLatAlt(target.longitude, target.latitude) + } else { + beaconLocation } val navigationMarker = painterResource(Res.drawable.navigation) @@ -285,10 +300,10 @@ fun MapContainerLibre( } // Draw beacon location marker last to prevent waypoint marker being drawn on top. - if (beaconLocation != null) { + if (drawnBeaconLocation != null) { val position = Position( - latitude = beaconLocation.latitude, - longitude = beaconLocation.longitude + latitude = drawnBeaconLocation.latitude, + longitude = drawnBeaconLocation.longitude ) val beaconLocationGeoJson = rememberGeoJsonSource( diff --git a/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt b/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt index 1acf080ae..8d7364aaf 100644 --- a/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt +++ b/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt @@ -23,4 +23,5 @@ expect fun PlatformMapContainer( extractGeometry: Geometry? = null, forceOnlineTiles: Boolean = false, onInteractionChanged: (Boolean) -> Unit = {}, + onBeaconLocationEdited: ((LngLatAlt) -> Unit)? = null, ) diff --git a/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/locationDetails/SharedSaveAndEditMarkerScreen.kt b/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/locationDetails/SharedSaveAndEditMarkerScreen.kt index fc7ebf1fd..d865daa9b 100644 --- a/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/locationDetails/SharedSaveAndEditMarkerScreen.kt +++ b/shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/home/locationDetails/SharedSaveAndEditMarkerScreen.kt @@ -11,7 +11,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.EditLocationAlt import androidx.compose.material3.AlertDialog +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -22,7 +26,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.backhandler.BackHandler import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.font.FontWeight import org.jetbrains.compose.resources.stringResource @@ -35,7 +41,8 @@ import org.scottishtecharmy.soundscape.resources.Res import org.scottishtecharmy.soundscape.resources.annotation_description_hint import org.scottishtecharmy.soundscape.resources.general_alert_cancel import org.scottishtecharmy.soundscape.resources.general_alert_done -import org.scottishtecharmy.soundscape.resources.location_detail_exit_full_screen_for_edit_hint +import org.scottishtecharmy.soundscape.resources.location_detail_adjust_marker_location +import org.scottishtecharmy.soundscape.resources.location_detail_adjust_marker_location_instructions import org.scottishtecharmy.soundscape.resources.location_detail_full_screen_for_edit_hint import org.scottishtecharmy.soundscape.resources.marker_name_description_hint import org.scottishtecharmy.soundscape.resources.markers_action_delete @@ -47,7 +54,6 @@ import org.scottishtecharmy.soundscape.resources.settings_reset_dialog_title import org.scottishtecharmy.soundscape.resources.ui_continue import org.scottishtecharmy.soundscape.resources.user_activity_save_marker_title import org.scottishtecharmy.soundscape.screens.home.data.LocationDescription -import org.scottishtecharmy.soundscape.screens.home.home.FullScreenMapFab import org.scottishtecharmy.soundscape.screens.home.home.PlatformMapContainer import org.scottishtecharmy.soundscape.screens.markers_routes.components.CustomButton import org.scottishtecharmy.soundscape.screens.markers_routes.components.CustomTextField @@ -60,6 +66,7 @@ import org.scottishtecharmy.soundscape.ui.theme.spacing * Shared screen for creating or editing a marker. * Shows name/annotation fields, a map preview, and save/delete controls. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun SharedSaveAndEditMarkerScreen( locationDescription: LocationDescription, @@ -77,8 +84,21 @@ fun SharedSaveAndEditMarkerScreen( ) var name by rememberSaveable { mutableStateOf(locationDescription.name) } var annotation by rememberSaveable { mutableStateOf(locationDescription.description ?: "") } + // The marker location can be moved in adjust mode, where a full screen map keeps the marker + // pinned to its centre so that panning the map moves the marker. + var latitude by rememberSaveable { mutableStateOf(locationDescription.location.latitude) } + var longitude by rememberSaveable { mutableStateOf(locationDescription.location.longitude) } + val markerLocation = LngLatAlt(longitude, latitude) val isEditing = locationDescription.databaseId != 0L - val fullscreenMap = remember { mutableStateOf(false) } + var adjustingLocation by rememberSaveable { mutableStateOf(false) } + // Where the marker was when adjust mode was entered, so that Cancel can put it back. + var adjustStartLatitude by rememberSaveable { mutableStateOf(latitude) } + var adjustStartLongitude by rememberSaveable { mutableStateOf(longitude) } + val cancelAdjusting = { + latitude = adjustStartLatitude + longitude = adjustStartLongitude + adjustingLocation = false + } var mapInteracting by remember { mutableStateOf(false) } val contentScrollState = rememberScrollState() var showDeleteDialog by rememberSaveable { mutableStateOf(false) } @@ -110,28 +130,44 @@ fun SharedSaveAndEditMarkerScreen( ) } + // System back while adjusting behaves like Cancel rather than leaving the whole screen. + if (adjustingLocation) { + @Suppress("DEPRECATION") + BackHandler(enabled = true) { cancelAdjusting() } + } + Scaffold( modifier = Modifier.imePadding(), topBar = { - TextOnlyAppBar( - title = if (isEditing) stringResource(Res.string.markers_edit_screen_title_edit) - else stringResource(Res.string.user_activity_save_marker_title), - navigationButtonTitle = stringResource(Res.string.general_alert_cancel), - onNavigateUp = onCancel, - rightButtonTitle = stringResource(Res.string.general_alert_done), - onRightButton = { - val updated = LocationDescription( - name = name.ifBlank { locationDescription.name }, - description = annotation.ifBlank { null }, - location = locationDescription.location, - databaseId = locationDescription.databaseId, - ) - onSave(updated) - }, - ) + if (adjustingLocation) { + TextOnlyAppBar( + title = stringResource(Res.string.location_detail_adjust_marker_location), + navigationButtonTitle = stringResource(Res.string.general_alert_cancel), + onNavigateUp = cancelAdjusting, + rightButtonTitle = stringResource(Res.string.general_alert_done), + onRightButton = { adjustingLocation = false }, + ) + } else { + TextOnlyAppBar( + title = if (isEditing) stringResource(Res.string.markers_edit_screen_title_edit) + else stringResource(Res.string.user_activity_save_marker_title), + navigationButtonTitle = stringResource(Res.string.general_alert_cancel), + onNavigateUp = onCancel, + rightButtonTitle = stringResource(Res.string.general_alert_done), + onRightButton = { + val updated = LocationDescription( + name = name.ifBlank { locationDescription.name }, + description = annotation.ifBlank { null }, + location = markerLocation, + databaseId = locationDescription.databaseId, + ) + onSave(updated) + }, + ) + } }, bottomBar = { - if (isEditing && onDelete != null) { + if (isEditing && onDelete != null && !adjustingLocation) { Column(modifier = Modifier.smallPadding()) { CustomButton( onClick = { showDeleteDialog = true }, @@ -150,24 +186,60 @@ fun SharedSaveAndEditMarkerScreen( } }, floatingActionButton = { - if (showMap) FullScreenMapFab( - fullscreenMap = fullscreenMap, - modifier = Modifier.testTag("saveMarkerFullScreenMapFab"), - openMapHint = Res.string.location_detail_full_screen_for_edit_hint, - closeMapHint = Res.string.location_detail_exit_full_screen_for_edit_hint, - ) + if (showMap && !adjustingLocation) { + FloatingActionButton( + onClick = { + adjustStartLatitude = latitude + adjustStartLongitude = longitude + adjustingLocation = true + }, + containerColor = MaterialTheme.colorScheme.surfaceContainer, + contentColor = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.testTag("saveMarkerAdjustLocationButton"), + ) { + Icon( + imageVector = Icons.Rounded.EditLocationAlt, + tint = MaterialTheme.colorScheme.onSurface, + contentDescription = stringResource(Res.string.location_detail_full_screen_for_edit_hint), + ) + } + } }, ) { padding -> - if (fullscreenMap.value && showMap) { - PlatformMapContainer( - beaconLocation = locationDescription.location, - mapCenter = locationDescription.location, - allowScrolling = true, - userLocation = userLocation, - userSymbolRotation = heading, - routeData = null, - modifier = Modifier.fillMaxSize(), - ) + if (adjustingLocation && showMap) { + // Only the top padding is applied: the bottom padding still includes the Delete + // button's bar on the first frame, and the map's surface keeps that first, shorter + // size, leaving a black band at the bottom. + Column( + modifier = Modifier + .fillMaxSize() + .padding(top = padding.calculateTopPadding()) + ) { + Text( + text = stringResource(Res.string.location_detail_adjust_marker_location_instructions), + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier + .fillMaxWidth() + .smallPadding() + .testTag("saveMarkerAdjustLocationInstructions"), + ) + // Fix the centre for this visit to adjust mode, otherwise every edit would + // re-centre the camera and fight the user's pan. + val editStartLocation = remember { markerLocation } + PlatformMapContainer( + beaconLocation = markerLocation, + mapCenter = editStartLocation, + allowScrolling = true, + userLocation = userLocation, + userSymbolRotation = heading, + routeData = null, + modifier = Modifier.fillMaxSize(), + onBeaconLocationEdited = { edited -> + latitude = edited.latitude + longitude = edited.longitude + }, + ) + } } else { Column( modifier = Modifier @@ -202,11 +274,11 @@ fun SharedSaveAndEditMarkerScreen( // Map showing the marker location if (showMap) { PlatformMapContainer( - mapCenter = locationDescription.location, + mapCenter = markerLocation, allowScrolling = false, userLocation = userLocation, userSymbolRotation = heading, - beaconLocation = locationDescription.location, + beaconLocation = markerLocation, routeData = null, modifier = Modifier .fillMaxWidth() diff --git a/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/IosMapContainer.kt b/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/IosMapContainer.kt index 73b98a8f6..11047639e 100644 --- a/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/IosMapContainer.kt +++ b/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/IosMapContainer.kt @@ -85,6 +85,7 @@ fun IosMapContainerLibre( extractGeometry: Geometry? = null, forceOnlineTiles: Boolean = false, onInteractionChanged: (Boolean) -> Unit = {}, + onBeaconLocationEdited: ((LngLatAlt) -> Unit)? = null, ) { val baseStyle = rememberIosMapBaseStyle(location = mapCenter, forceOnlineTiles = forceOnlineTiles) @@ -101,5 +102,6 @@ fun IosMapContainerLibre( baseStyle = baseStyle, extractGeometry = extractGeometry, onInteractionChanged = onInteractionChanged, + onBeaconLocationEdited = onBeaconLocationEdited, ) } diff --git a/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt b/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt index 9e243c2f7..b9dd2e163 100644 --- a/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt +++ b/shared/src/iosMain/kotlin/org/scottishtecharmy/soundscape/screens/home/home/PlatformMapContainer.kt @@ -19,6 +19,7 @@ actual fun PlatformMapContainer( extractGeometry: Geometry?, forceOnlineTiles: Boolean, onInteractionChanged: (Boolean) -> Unit, + onBeaconLocationEdited: ((LngLatAlt) -> Unit)?, ) { IosMapContainerLibre( mapCenter = mapCenter, @@ -32,5 +33,6 @@ actual fun PlatformMapContainer( extractGeometry = extractGeometry, forceOnlineTiles = forceOnlineTiles, onInteractionChanged = onInteractionChanged, + onBeaconLocationEdited = onBeaconLocationEdited, ) }