diff options
Diffstat (limited to 'android-app')
| -rw-r--r-- | android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt | 12 | ||||
| -rw-r--r-- | android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt | 43 |
2 files changed, 55 insertions, 0 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 f9d4dbd..5950844 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 @@ -49,6 +49,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { private var mapHandler: MapHandler? = null private var anchorWatchHandler: AnchorWatchHandler? = null private val loadedStyleFlow = MutableStateFlow<Style?>(null) + private var weatherLoaded = false private lateinit var bottomSheetBehavior: BottomSheetBehavior<View> private lateinit var fragmentContainer: FrameLayout @@ -244,7 +245,9 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { loadedStyleFlow.value = style val anchorBitmap = rasterizeDrawable(R.drawable.ic_anchor) val arrowBitmap = rasterizeDrawable(R.drawable.ic_tidal_arrow) + val windArrowBitmap = rasterizeDrawable(R.drawable.ic_wind_arrow) mapHandler?.setupLayers(style, anchorBitmap, arrowBitmap) + mapHandler?.setupWindLayer(style, windArrowBitmap) } } } @@ -255,6 +258,15 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { mapHandler?.centerOnLocation(gpsData.latitude, gpsData.longitude) val sogKnots = gpsData.speedOverGround * 1.94384 viewModel.addGpsPoint(gpsData.latitude, gpsData.longitude, sogKnots, gpsData.courseOverGround.toDouble()) + if (!weatherLoaded) { + weatherLoaded = true + viewModel.loadWeather(gpsData.latitude, gpsData.longitude) + } + } + } + lifecycleScope.launch { + viewModel.windArrow.collect { arrow -> + if (arrow != null) mapHandler?.updateWindLayer(arrow) } } lifecycleScope.launch { 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 cbc2e90..cdf0c25 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 @@ -6,6 +6,7 @@ import org.maplibre.android.camera.CameraUpdateFactory import org.maplibre.android.geometry.LatLng import org.maplibre.android.maps.MapLibreMap import org.maplibre.android.maps.Style +import org.maplibre.android.style.expressions.Expression import org.maplibre.android.style.layers.CircleLayer import org.maplibre.android.style.layers.LineLayer import org.maplibre.android.style.layers.PropertyFactory @@ -21,6 +22,7 @@ import org.maplibre.geojson.Point import org.maplibre.geojson.Polygon import org.terst.nav.AnchorWatchState import org.terst.nav.TidalCurrentState +import org.terst.nav.data.model.WindArrow import org.terst.nav.track.TrackPoint import kotlin.math.cos import kotlin.math.sin @@ -43,10 +45,15 @@ class MapHandler(private val maplibreMap: MapLibreMap) { private val TRACK_SOURCE_ID = "track-source" private val TRACK_LAYER_ID = "track-line" + private val WIND_SOURCE_ID = "wind-source" + private val WIND_LAYER_ID = "wind-arrows" + private val WIND_ARROW_ICON_ID = "wind-arrow" + private var anchorPointSource: GeoJsonSource? = null private var anchorCircleSource: GeoJsonSource? = null private var tidalCurrentSource: GeoJsonSource? = null private var trackSource: GeoJsonSource? = null + private var windSource: GeoJsonSource? = null /** * Initializes map layers for anchor watch and tidal currents. @@ -135,6 +142,42 @@ class MapHandler(private val maplibreMap: MapLibreMap) { } /** + * Registers the wind-arrow bitmap in the style. Call once after style loads. + */ + fun setupWindLayer(style: Style, arrowBitmap: Bitmap) { + style.addImage(WIND_ARROW_ICON_ID, arrowBitmap) + windSource = GeoJsonSource(WIND_SOURCE_ID) + style.addSource(windSource!!) + style.addLayer(SymbolLayer(WIND_LAYER_ID, WIND_SOURCE_ID).apply { + setProperties( + PropertyFactory.iconImage(WIND_ARROW_ICON_ID), + PropertyFactory.iconRotate(Expression.get("direction")), + PropertyFactory.iconRotationAlignment("map"), + PropertyFactory.iconAllowOverlap(true), + PropertyFactory.iconSize( + Expression.interpolate( + Expression.linear(), + Expression.get("speed_kt"), + Expression.stop(0, 0.6f), + Expression.stop(30, 1.4f) + ) + ) + ) + }) + } + + /** + * Places or moves the single wind arrow at the GPS position. + */ + fun updateWindLayer(arrow: WindArrow) { + val feature = Feature.fromGeometry(Point.fromLngLat(arrow.lon, arrow.lat)).apply { + addNumberProperty("direction", arrow.directionDeg) + addNumberProperty("speed_kt", arrow.speedKt) + } + windSource?.setGeoJson(FeatureCollection.fromFeature(feature)) + } + + /** * Updates the GPS track polyline on the map. Lazily initialises the layer on first call. */ fun updateTrackLayer(style: Style, points: List<TrackPoint>) { |
