From 23163f67deb71f4cc4e53d670254a45b59fd4f6b Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 30 Jun 2026 18:38:29 +0000 Subject: feat(fishing): SST raster layer from NOAA CoastWatch Adds SST source/layer to MapLayerManager, SST toggle to LayerPickerSheet UI and wires it up in MainActivity. Co-Authored-By: Claude Sonnet 4.6 --- .../src/main/kotlin/org/terst/nav/MainActivity.kt | 4 +++ .../kotlin/org/terst/nav/ui/LayerPickerSheet.kt | 6 ++++ .../kotlin/org/terst/nav/ui/MapLayerManager.kt | 26 +++++++++++++++++ .../main/res/layout/layout_layer_picker_sheet.xml | 34 ++++++++++++++++++++++ 4 files changed, 70 insertions(+) (limited to 'android-app/app') 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 fcfc96a..cfc8d6d 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 @@ -427,6 +427,10 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { val style = loadedStyleFlow.value ?: return@LayerPickerSheet mapHandler?.setFadLayerVisible(style, enabled) }, + onSstChanged = { enabled -> + val style = loadedStyleFlow.value ?: return@LayerPickerSheet + layerManager.setSstEnabled(style, enabled) + }, unitPrefs = unitPrefs, onUnitsChanged = { refreshUnits() } ) diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/LayerPickerSheet.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/LayerPickerSheet.kt index a9dcca8..b654184 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/ui/LayerPickerSheet.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/LayerPickerSheet.kt @@ -23,6 +23,7 @@ class LayerPickerSheet( private val onSeamarksChanged: (Boolean) -> Unit, private val onDepthChanged: (Boolean) -> Unit, private val onFadsChanged: (Boolean) -> Unit, + private val onSstChanged: (Boolean) -> Unit, private val unitPrefs: UnitPrefs, private val onUnitsChanged: () -> Unit ) : BottomSheetDialogFragment() { @@ -78,6 +79,11 @@ class LayerPickerSheet( fadsSwitch.isChecked = manager.fadsEnabled fadsSwitch.setOnCheckedChangeListener { _, checked -> onFadsChanged(checked) } + // ── SST switch ──────────────────────────────────────────────────────── + val sstSwitch = view.findViewById(R.id.switch_sst) + sstSwitch.isChecked = manager.sstEnabled + sstSwitch.setOnCheckedChangeListener { _, checked -> onSstChanged(checked) } + // ── Temperature chips ───────────────────────────────────────────────── val chipTemp = view.findViewById(R.id.chip_group_temp) chipTemp.check(when (unitPrefs.tempUnit) { diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/MapLayerManager.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/MapLayerManager.kt index 33072c4..9f7e819 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/ui/MapLayerManager.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/MapLayerManager.kt @@ -38,6 +38,8 @@ class MapLayerManager(context: Context) { private set var fadsEnabled: Boolean = prefs.getBoolean(KEY_FADS, false) private set + var sstEnabled: Boolean = prefs.getBoolean(KEY_SST, false) + private set // ── Source / Layer IDs ──────────────────────────────────────────────────── @@ -53,6 +55,8 @@ class MapLayerManager(context: Context) { const val LAYER_WIND = "wind-layer" const val LAYER_SEAMARKS = "openseamap-layer" const val LAYER_DEPTH = "osm-depth-layer" + const val SOURCE_SST = "sst-source" + const val LAYER_SST = "sst-layer" private const val KEY_BASE = "base_preset" private const val KEY_WIND = "wind_enabled" @@ -61,6 +65,7 @@ class MapLayerManager(context: Context) { private const val KEY_SEAMARKS = "seamarks_enabled" private const val KEY_DEPTH = "depth_enabled" private const val KEY_FADS = "fads_enabled" + private const val KEY_SST = "sst_enabled" // Tile URLs private const val URL_SATELLITE = @@ -74,6 +79,12 @@ class MapLayerManager(context: Context) { // Depth soundings + contours from OpenSeaMap (zoom 3–18, coverage varies by region) private const val URL_DEPTH = "https://tiles.openseamap.org/depth/{z}/{x}/{y}.png" + // Sea Surface Temperature from NOAA CoastWatch (WMS-style raster) + private const val URL_SST = + "https://coastwatch.pfeg.noaa.gov/erddap/wms/jplMURSST41/request" + + "?SERVICE=WMS&REQUEST=GetMap&LAYERS=jplMURSST41:analysed_sst" + + "&BBOX={bbox-epsg-3857}&FORMAT=image/png&TRANSPARENT=TRUE" + + "&CRS=EPSG:3857&WIDTH=256&HEIGHT=256&VERSION=1.3.0&STYLES=" } /** @@ -98,6 +109,9 @@ class MapLayerManager(context: Context) { builder.withSource(RasterSource(SOURCE_DEPTH, TileSet("2.2.0", URL_DEPTH).also { it.setMinZoom(3f); it.setMaxZoom(18f) }, 256)) + builder.withSource(RasterSource(SOURCE_SST, + TileSet("2.2.0", URL_SST), 256)) + // ── Layers (bottom → top within raster stack) ───────────────────────── builder.withLayer(RasterLayer(LAYER_SATELLITE, SOURCE_SATELLITE).apply { setProperties(PropertyFactory.rasterOpacity(1f)) @@ -114,6 +128,11 @@ class MapLayerManager(context: Context) { setProperties(PropertyFactory.visibility(if (windEnabled) "visible" else "none")) }) + builder.withLayer(RasterLayer(LAYER_SST, SOURCE_SST).apply { + setProperties(PropertyFactory.rasterOpacity(0.65f)) + setProperties(PropertyFactory.visibility(if (sstEnabled) "visible" else "none")) + }) + // Depth contours sit below seamarks so soundings don't obscure nav aid symbols builder.withLayer(RasterLayer(LAYER_DEPTH, SOURCE_DEPTH).apply { setProperties(PropertyFactory.rasterOpacity(0.85f)) @@ -159,6 +178,13 @@ class MapLayerManager(context: Context) { PropertyFactory.visibility(if (enabled) "visible" else "none")) } + fun setSstEnabled(style: Style, enabled: Boolean) { + sstEnabled = enabled + prefs.edit().putBoolean(KEY_SST, enabled).apply() + style.getLayer(LAYER_SST)?.setProperties( + PropertyFactory.visibility(if (enabled) "visible" else "none")) + } + /** FADs are a GeoJSON vector layer in MapHandler; this just persists the pref. */ fun setFadsEnabled(enabled: Boolean) { fadsEnabled = enabled diff --git a/android-app/app/src/main/res/layout/layout_layer_picker_sheet.xml b/android-app/app/src/main/res/layout/layout_layer_picker_sheet.xml index 065b720..0707425 100644 --- a/android-app/app/src/main/res/layout/layout_layer_picker_sheet.xml +++ b/android-app/app/src/main/res/layout/layout_layer_picker_sheet.xml @@ -298,6 +298,40 @@ + + + + + + + + + + + +