summaryrefslogtreecommitdiff
path: root/android-app/app/src/main/kotlin/org/terst
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src/main/kotlin/org/terst')
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt18
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt21
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/sensors/WindData.kt8
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/track/TrackPoint.kt12
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt23
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt44
6 files changed, 126 insertions, 0 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt b/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt
new file mode 100644
index 0000000..810313c
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt
@@ -0,0 +1,18 @@
+package org.terst.nav
+
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import org.terst.nav.sensors.WindData
+
+class LocationService {
+
+ companion object {
+ private val _nmeaWindDataFlow = MutableSharedFlow<WindData>()
+ val nmeaWindDataFlow: SharedFlow<WindData> = _nmeaWindDataFlow
+
+ // line 362 — emit wind data parsed from NMEA sentences
+ suspend fun emitWind(wind: WindData) {
+ _nmeaWindDataFlow.emit(wind)
+ }
+ }
+}
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
new file mode 100644
index 0000000..886d025
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
@@ -0,0 +1,21 @@
+package org.terst.nav
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import org.terst.nav.ui.MainViewModel
+
+class MainActivity {
+
+ private val viewModel = MainViewModel()
+ private val lifecycleScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
+
+ fun observeDataSources() {
+ lifecycleScope.launch {
+ LocationService.nmeaWindDataFlow.collect { wind ->
+ viewModel.updateWind(wind)
+ }
+ }
+ }
+}
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/sensors/WindData.kt b/android-app/app/src/main/kotlin/org/terst/nav/sensors/WindData.kt
new file mode 100644
index 0000000..95fd5e3
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/sensors/WindData.kt
@@ -0,0 +1,8 @@
+package org.terst.nav.sensors
+
+data class WindData(
+ val windAngle: Double, // degrees, relative or true
+ val windSpeed: Double, // knots
+ val isTrueWind: Boolean,
+ val timestampMs: Long
+)
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackPoint.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackPoint.kt
new file mode 100644
index 0000000..d803c8c
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackPoint.kt
@@ -0,0 +1,12 @@
+package org.terst.nav.track
+
+data class TrackPoint(
+ val lat: Double,
+ val lon: Double,
+ val sogKnots: Double,
+ val cogDeg: Double,
+ val windSpeedKnots: Double,
+ val windAngleDeg: Double,
+ val isTrueWind: Boolean,
+ val timestampMs: Long
+)
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt
new file mode 100644
index 0000000..c77852f
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt
@@ -0,0 +1,23 @@
+package org.terst.nav.track
+
+class TrackRepository {
+ private val points = mutableListOf<TrackPoint>()
+ private var tracking = false
+
+ fun startTrack() {
+ points.clear()
+ tracking = true
+ }
+
+ fun stopTrack() {
+ tracking = false
+ }
+
+ fun addPoint(point: TrackPoint): Boolean {
+ if (!tracking) return false
+ points.add(point)
+ return true
+ }
+
+ fun getPoints(): List<TrackPoint> = points.toList()
+}
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt
new file mode 100644
index 0000000..c5b90c3
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt
@@ -0,0 +1,44 @@
+package org.terst.nav.ui
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import org.terst.nav.sensors.WindData
+import org.terst.nav.track.TrackPoint
+import org.terst.nav.track.TrackRepository
+
+class MainViewModel {
+
+ private val trackRepository = TrackRepository()
+ private var latestWind: WindData? = null
+
+ private val _trackPoints = MutableStateFlow<List<TrackPoint>>(emptyList())
+ val trackPoints: StateFlow<List<TrackPoint>> = _trackPoints
+
+ fun startTrack() {
+ trackRepository.startTrack()
+ _trackPoints.value = emptyList()
+ }
+
+ fun stopTrack() {
+ trackRepository.stopTrack()
+ }
+
+ fun updateWind(wind: WindData) {
+ latestWind = wind
+ }
+
+ fun addGpsPoint(lat: Double, lon: Double, sogKnots: Double, cogDeg: Double) {
+ val wind = latestWind
+ val point = TrackPoint(
+ lat = lat, lon = lon,
+ sogKnots = sogKnots, cogDeg = cogDeg,
+ windSpeedKnots = wind?.windSpeed ?: 0.0,
+ windAngleDeg = wind?.windAngle ?: 0.0,
+ isTrueWind = wind?.isTrueWind ?: false,
+ timestampMs = System.currentTimeMillis()
+ )
+ if (trackRepository.addPoint(point)) {
+ _trackPoints.value = trackRepository.getPoints()
+ }
+ }
+}