summaryrefslogtreecommitdiff
path: root/android-app
diff options
context:
space:
mode:
Diffstat (limited to 'android-app')
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookRepository.kt3
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/track/TrackEntity.kt16
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/track/TrackRepository.kt8
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/MainViewModel.kt7
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/anchorwatch/AnchorWatchHandler.kt58
-rw-r--r--android-app/app/src/main/res/layout/fragment_anchor_watch.xml79
6 files changed, 34 insertions, 137 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookRepository.kt b/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookRepository.kt
index fe7b40d..06f95b9 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookRepository.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/logbook/LogbookRepository.kt
@@ -17,6 +17,7 @@ class LogbookRepository(private val storage: LogbookStorage) {
/** Moves a temp camera file into persistent storage, deleting the temp. Returns content:// URI string or file path. */
fun importPhoto(file: File): String? = storage.importFile(file)
+ @Synchronized
fun save(entry: LogEntry): LogEntry {
val saved = entry.copy(id = nextId++)
entries.add(saved)
@@ -24,9 +25,11 @@ class LogbookRepository(private val storage: LogbookStorage) {
return saved
}
+ @Synchronized
fun getAll(): List<LogEntry> = entries.toList()
/** Re-reads entries from storage. Call after SAF is (re-)authorised post-reinstall. */
+ @Synchronized
fun reload() {
entries.clear()
entries.addAll(storage.loadAll())
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackEntity.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackEntity.kt
index 502bfba..b23e159 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackEntity.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackEntity.kt
@@ -19,6 +19,22 @@ data class TrackEntity(
val endLon: Double
)
+/**
+ * Reconstructs a [SavedTrack] from cached summary data without parsing the GPX file.
+ * The two placeholder TrackPoints preserve [SavedTrack.endMs] for logbook filtering.
+ * [SavedTrack.points] contains only start/end; do not use for map rendering or tack detail.
+ */
+fun TrackEntity.toShallowSavedTrack(): SavedTrack {
+ val startPoint = TrackPoint(lat = startLat, lon = startLon, sogKnots = 0.0, cogDeg = 0.0, timestampMs = startMs)
+ val endPoint = TrackPoint(lat = endLat, lon = endLon, sogKnots = 0.0, cogDeg = 0.0, timestampMs = startMs + durationMs)
+ return SavedTrack(
+ points = listOf(startPoint, endPoint),
+ startMs = startMs,
+ summary = TrackSummary(distanceNm, durationMs, maxSogKt, avgSogKt, avgWindKt, avgWaveHeightM),
+ tacks = List(tackCount) { TackEvent(it, startLat, startLon, 0.0, 0.0) }
+ )
+}
+
fun SavedTrack.toEntity(): TrackEntity = TrackEntity(
startMs = startMs,
distanceNm = summary.distanceNm,
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
index 84832f5..4648981 100644
--- 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
@@ -168,6 +168,14 @@ class TrackRepository(context: Context, private val trackDao: TrackDao) {
.sortedBy { it.startMs }
}
+ /**
+ * Fast list from Room cache — no GPX parsing. Returns shallow [SavedTrack] objects
+ * with only start/end placeholder points. Use [getSavedTracks] for full point data.
+ */
+ suspend fun getSavedTracksFromRoom(): List<SavedTrack> = withContext(Dispatchers.IO) {
+ trackDao.getAll().map { it.toShallowSavedTrack() }.sortedBy { it.startMs }
+ }
+
fun safState(): SafState = storage.safState()
fun initSafDirectory(treeUri: Uri) {
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
index 33366f9..7d0ab33 100644
--- 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
@@ -106,6 +106,13 @@ class MainViewModel(
init {
viewModelScope.launch {
+ // Fast path: serve list from Room immediately (no GPX parse)
+ val roomTracks = runCatching { trackRepository.getSavedTracksFromRoom() }.getOrElse { emptyList() }
+ if (roomTracks.isNotEmpty()) {
+ _savedTracks.value = roomTracks
+ _isLoadingTracks.value = false
+ }
+ // Full GPX load — replaces Room data with authoritative tracks (full points)
runCatching { trackRepository.getPastTracks() }
.onSuccess {
_pastTracks.value = it
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/anchorwatch/AnchorWatchHandler.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/anchorwatch/AnchorWatchHandler.kt
deleted file mode 100644
index d435f00..0000000
--- a/android-app/app/src/main/kotlin/org/terst/nav/ui/anchorwatch/AnchorWatchHandler.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.terst.nav.ui.anchorwatch
-
-import android.os.Bundle
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import org.terst.nav.R
-import org.terst.nav.databinding.FragmentAnchorWatchBinding
-import org.terst.nav.safety.AnchorWatchState
-
-class AnchorWatchHandler : Fragment() {
-
- private var _binding: FragmentAnchorWatchBinding? = null
- private val binding get() = _binding!!
-
- private val anchorWatchState = AnchorWatchState()
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- _binding = FragmentAnchorWatchBinding.inflate(inflater, container, false)
- return binding.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- val watcher = object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
- override fun afterTextChanged(s: Editable?) = updateSuggestedRadius()
- }
- binding.etDepth.addTextChangedListener(watcher)
- binding.etRodeOut.addTextChangedListener(watcher)
- }
-
- private fun updateSuggestedRadius() {
- val depth = binding.etDepth.text.toString().toDoubleOrNull()
- val rode = binding.etRodeOut.text.toString().toDoubleOrNull()
-
- if (depth != null && rode != null && depth >= 0.0 && rode > 0.0) {
- val radius = AnchorWatchState.calculateRecommendedWatchCircleRadius(depth, 2.0, rode)
- binding.tvSuggestedRadius.text =
- getString(R.string.anchor_suggested_radius_fmt, radius)
- } else {
- binding.tvSuggestedRadius.text = getString(R.string.anchor_suggested_radius_empty)
- }
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-}
diff --git a/android-app/app/src/main/res/layout/fragment_anchor_watch.xml b/android-app/app/src/main/res/layout/fragment_anchor_watch.xml
deleted file mode 100644
index 96b9969..0000000
--- a/android-app/app/src/main/res/layout/fragment_anchor_watch.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/anchor_watch_title"
- android:textSize="20sp"
- android:textStyle="bold"
- android:layout_marginBottom="24dp" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/anchor_depth_label"
- android:textSize="14sp"
- android:layout_marginBottom="4dp" />
-
- <EditText
- android:id="@+id/etDepth"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/anchor_depth_hint"
- android:inputType="numberDecimal"
- android:importantForAutofill="no"
- android:layout_marginBottom="16dp" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/anchor_rode_label"
- android:textSize="14sp"
- android:layout_marginBottom="4dp" />
-
- <EditText
- android:id="@+id/etRodeOut"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/anchor_rode_hint"
- android:inputType="numberDecimal"
- android:importantForAutofill="no"
- android:layout_marginBottom="24dp" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/anchor_suggested_radius_label"
- android:textSize="14sp"
- android:layout_marginBottom="4dp" />
-
- <TextView
- android:id="@+id/tvSuggestedRadius"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/anchor_suggested_radius_empty"
- android:textSize="18sp"
- android:textStyle="bold"
- android:layout_marginBottom="4dp" />
-
- <TextView
- android:id="@+id/tvSuggestedRadiusHint"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/anchor_suggested_radius_hint"
- android:textSize="12sp"
- android:alpha="0.6" />
-
- </LinearLayout>
-
-</ScrollView>