diff options
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> |
