From ddae982f561e1f812d55b5943f79dc76144d93d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 09:59:26 +0000 Subject: Restyle past tracks: solid dark blue, dim/focus layers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All past tracks render as solid dark navy (#0B3050) at 45% opacity, 2.5px — no dashes. A second focus layer (#2B8FC4, full opacity, 4px) paints on top when a track is selected, making it pop without changing the dim layer's data. Active recording stays red. The dim layer always contains every past track; the focus layer gets the selected track's points independently via setFocusedTrackPoints(). Cleared on dismiss so all tracks return to equal dim opacity. https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn --- .../src/main/kotlin/org/terst/nav/MainActivity.kt | 3 +- .../src/main/kotlin/org/terst/nav/ui/MapHandler.kt | 71 +++++++++++++++------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt index caabe40..6c54500 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt @@ -818,10 +818,11 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { } } - // When a saved track is selected: zoom to it and show tack markers + // When a saved track is selected: zoom to it, highlight it, and show tack markers lifecycleScope.launch { viewModel.selectedTrack.collect { track -> val style = loadedStyleFlow.value ?: return@collect + mapHandler?.setFocusedTrackPoints(track?.points) if (track != null) { mapHandler?.zoomToTrackBounds(track.points) mapHandler?.updateTackLayer(style, track.tacks) diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt index 32b3643..b8ce460 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt @@ -72,10 +72,12 @@ class MapHandler(private val maplibreMap: MapLibreMap) { private val USER_POS_LAYER_ID = "user-pos-layer" private val USER_ICON_ID = "user-icon" - private val TRACK_ACTIVE_SOURCE_ID = "track-active-source" - private val TRACK_ACTIVE_LAYER_ID = "track-line-active" - private val TRACK_PAST_SOURCE_ID = "track-past-source" - private val TRACK_PAST_LAYER_ID = "track-line-past" + private val TRACK_ACTIVE_SOURCE_ID = "track-active-source" + private val TRACK_ACTIVE_LAYER_ID = "track-line-active" + private val TRACK_PAST_DIM_SOURCE_ID = "track-past-dim-source" + private val TRACK_PAST_DIM_LAYER_ID = "track-line-past-dim" + private val TRACK_PAST_FOCUS_SOURCE_ID = "track-past-focus-source" + private val TRACK_PAST_FOCUS_LAYER_ID = "track-line-past-focus" private val WIND_SOURCE_ID = "wind-arrows-source" private val WIND_LAYER_ID = "wind-arrows" @@ -91,7 +93,8 @@ class MapHandler(private val maplibreMap: MapLibreMap) { private var tidalCurrentSource: GeoJsonSource? = null private var userPosSource: GeoJsonSource? = null private var trackActiveSource: GeoJsonSource? = null - private var trackPastSource: GeoJsonSource? = null + private var trackPastDimSource: GeoJsonSource? = null + private var trackPastFocusSource: GeoJsonSource? = null private var windSource: GeoJsonSource? = null private var windGridSource: GeoJsonSource? = null private var tackSource: GeoJsonSource? = null @@ -306,6 +309,34 @@ class MapHandler(private val maplibreMap: MapLibreMap) { * Updates the GPS track polyline on the map. Lazily initialises the layers on first call. */ fun updateTrackLayer(style: Style, activePoints: List, pastTracks: List>) { + if (trackPastDimSource == null) { + trackPastDimSource = GeoJsonSource(TRACK_PAST_DIM_SOURCE_ID) + style.addSource(trackPastDimSource!!) + style.addLayer(LineLayer(TRACK_PAST_DIM_LAYER_ID, TRACK_PAST_DIM_SOURCE_ID).apply { + setProperties( + PropertyFactory.lineColor("#0B3050"), + PropertyFactory.lineOpacity(0.45f), + PropertyFactory.lineWidth(2.5f), + PropertyFactory.lineCap("round"), + PropertyFactory.lineJoin("round") + ) + }) + } + + if (trackPastFocusSource == null) { + trackPastFocusSource = GeoJsonSource(TRACK_PAST_FOCUS_SOURCE_ID) + style.addSource(trackPastFocusSource!!) + style.addLayer(LineLayer(TRACK_PAST_FOCUS_LAYER_ID, TRACK_PAST_FOCUS_SOURCE_ID).apply { + setProperties( + PropertyFactory.lineColor("#2B8FC4"), + PropertyFactory.lineOpacity(1.0f), + PropertyFactory.lineWidth(4f), + PropertyFactory.lineCap("round"), + PropertyFactory.lineJoin("round") + ) + }) + } + if (trackActiveSource == null) { trackActiveSource = GeoJsonSource(TRACK_ACTIVE_SOURCE_ID) style.addSource(trackActiveSource!!) @@ -313,23 +344,16 @@ class MapHandler(private val maplibreMap: MapLibreMap) { setProperties( PropertyFactory.lineColor("#E53935"), PropertyFactory.lineWidth(4f), - PropertyFactory.lineCap("round") + PropertyFactory.lineCap("round"), + PropertyFactory.lineJoin("round") ) }) } - if (trackPastSource == null) { - trackPastSource = GeoJsonSource(TRACK_PAST_SOURCE_ID) - style.addSource(trackPastSource!!) - style.addLayer(LineLayer(TRACK_PAST_LAYER_ID, TRACK_PAST_SOURCE_ID).apply { - setProperties( - PropertyFactory.lineColor("#E53935"), - PropertyFactory.lineWidth(3f), - PropertyFactory.lineDasharray(arrayOf(1f, 2f)), - PropertyFactory.lineCap("round") - ) - }) + val dimFeatures = pastTracks.map { track -> + Feature.fromGeometry(LineString.fromLngLats(track.map { Point.fromLngLat(it.lon, it.lat) })) } + trackPastDimSource?.setGeoJson(FeatureCollection.fromFeatures(dimFeatures)) if (activePoints.size >= 2) { val coords = activePoints.map { Point.fromLngLat(it.lon, it.lat) } @@ -337,15 +361,16 @@ class MapHandler(private val maplibreMap: MapLibreMap) { } else { trackActiveSource?.setGeoJson(FeatureCollection.fromFeatures(emptyList())) } + } - if (pastTracks.isNotEmpty()) { - val features = pastTracks.map { track -> - Feature.fromGeometry(LineString.fromLngLats(track.map { Point.fromLngLat(it.lon, it.lat) })) - } - trackPastSource?.setGeoJson(FeatureCollection.fromFeatures(features)) + /** Highlights [points] in the focus layer (full-opacity bright blue over the dim layer). */ + fun setFocusedTrackPoints(points: List?) { + val geojson = if (points != null && points.size >= 2) { + Feature.fromGeometry(LineString.fromLngLats(points.map { Point.fromLngLat(it.lon, it.lat) })) } else { - trackPastSource?.setGeoJson(FeatureCollection.fromFeatures(emptyList())) + FeatureCollection.fromFeatures(emptyList()) } + trackPastFocusSource?.setGeoJson(geojson) } /** -- cgit v1.2.3