From d09f8036b6ef2ad379a02e7693692b8227fcd9cf Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 5 Oct 2026 15:19:15 -0400 Subject: [PATCH] fix(geocaching): open the cache map at zoom 3 instead of tiling the world With no location the map sat at osmdroid's zoom 0, one 256px world tile repeated down the screen with gaps. Starts at zoom 3, turns off vertical repetition and stops scrolling at the poles. The "not positioned yet" check that auto-centres on the first cache now tolerates the float noise a programmatic zoom can leave on the 0,0 centre. Co-Authored-By: Claude Opus 5.5 --- .../loggedIn/geocaches/map/GeocacheMapTab.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt index 58c4c595e0..fb020736b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt @@ -80,6 +80,7 @@ import org.osmdroid.views.CustomZoomButtonsController import org.osmdroid.views.MapView import org.osmdroid.views.overlay.MapEventsOverlay import org.osmdroid.views.overlay.Marker +import kotlin.math.abs import kotlin.math.pow import kotlin.math.roundToLong @@ -131,6 +132,11 @@ fun GeocacheMapTab( setTileSource(TileSourceFactory.MAPNIK) setMultiTouchControls(true) zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER) + // osmdroid opens at zoom 0, one 256px world tile repeated down the screen. Zoom 3 fills + // a phone, and the world stops at the poles instead of stacking copies of itself. + isVerticalMapRepetitionEnabled = false + setScrollableAreaLimitLatitude(MapView.getTileSystem().maxLatitude, MapView.getTileSystem().minLatitude, 0) + controller.setZoom(INITIAL_ZOOM) setOnTouchListener { view, event -> when (event.action) { MotionEvent.ACTION_DOWN -> view.parent?.requestDisallowInterceptTouchEvent(true) @@ -232,7 +238,7 @@ fun GeocacheMapTab( } first?.let { - if (map.mapCenter.latitude == 0.0 && map.mapCenter.longitude == 0.0) { + if (map.isUnpositioned()) { map.controller.setZoom(11.0) map.controller.setCenter(it) } @@ -250,7 +256,7 @@ fun GeocacheMapTab( first?.let { // Only recentre while the map has not been positioned yet, so a pan is not // yanked back every time a new cache arrives from a relay. - if (map.mapCenter.latitude == 0.0 && map.mapCenter.longitude == 0.0) { + if (map.isUnpositioned()) { map.controller.setZoom(13.0) map.controller.setCenter(it) } @@ -316,6 +322,11 @@ private fun GeocachePeekSheet( */ private const val CLUSTER_THRESHOLD = 50 +private const val INITIAL_ZOOM = 3.0 + +/** Still on the untouched initial view: centred on 0,0, which a zoom can leave a hair off exact zero. */ +private fun MapView.isUnpositioned() = abs(mapCenter.latitude) < 1e-6 && abs(mapCenter.longitude) < 1e-6 + /** * Degrees per cluster cell at [zoom]. Roughly a fixed number of screen pixels: each zoom level * halves the ground covered by a pixel, so the cell halves with it and clusters break apart at