<feed xmlns='http://www.w3.org/2005/Atom'>
<title>nav.git/android-app/app/src/main/kotlin/org/terst/nav/track, branch main</title>
<subtitle>nav — android navigation app
</subtitle>
<id>https://git.terst.org/nav.git/atom?h=main</id>
<link rel='self' href='https://git.terst.org/nav.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/'/>
<updated>2026-07-02T02:56:25+00:00</updated>
<entry>
<title>fix+feat: layer cards, ocean floor, notifications, units, log, photos</title>
<updated>2026-07-02T02:56:25+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-02T02:56:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=80aa2531144563e8a117ffd81f6dd6d9af8bd574'/>
<id>urn:sha1:80aa2531144563e8a117ffd81f6dd6d9af8bd574</id>
<content type='text'>
Layer picker:
- Fix blank cards: app:layout_columnWeight → android:layout_columnWeight
  (GridLayout children require android: namespace for weight attributes)
- Add Distance unit chips (nm/km/mi) to UNITS section

Map layers:
- Fix ocean floor: use addLayerAbove(lastFillLayer) instead of addLayerAt(0)
  so base rasters appear above OFM water/land fills but below roads+labels
- CardView elevation 16dp→4dp to eliminate visible shadow border

Notifications:
- Add POST_NOTIFICATIONS to manifest
- Request it alongside location permissions on Android 13+ (TIRAMISU+)

Conditions sheet:
- showOverlay() now always hides bottom sheet (STATE_HIDDEN) so it can't
  leak onto non-map pages; bottom padding (80dp) added to Safety+Log panes

Log entries:
- Log entry form visible always (was only shown while recording)
- Photo-only events filtered from track timeline; photos appear only when
  paired with real text in a log entry

Anchor watch:
- Inputs and output radius now use configured depth unit (ft/m)
  with label updates and ft→m conversion before calculation

Photos:
- Tap thumbnail in track event log → fullscreen dialog viewer

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: UX improvements + HAW FAD data + fishing mode plan</title>
<updated>2026-06-30T18:19:04+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-06-30T17:16:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=9af38934e8d676bfb8c08ab01e3d57fec5f36d97'/>
<id>urn:sha1:9af38934e8d676bfb8c08ab01e3d57fec5f36d97</id>
<content type='text'>
Dark mode:
- Force light mode (AppCompatDelegate.MODE_NIGHT_NO) in NavApplication

Log screen:
- Tracks sorted newest-first (sortedByDescending startMs)
- Photos/entries saved during a track tagged with trackId; ship's log
  shows only standalone entries (trackId == null)
- "Plan Trip" button moved from safety screen to log screen header row
- Pre-trip report auto-generates (newAutoInstance) when a track starts

Safety screen:
- Removed "Plan Trip" button (now in log screen)
- Quit button moved to top title row
- Anchor Watch section collapses by default (tap header to expand)
- Hardware Data Sources section collapses by default (tap header to expand)

Notifications + idle:
- Tracking notification becomes persistent (setOngoing true) while recording
- Notification title changes to "Recording track" when active
- App exits automatically after 3 hours of idle (resetIdleTimer via
  onUserInteraction + onResume; suspended while recording)

FAD layer:
- FadData.kt: 18 Hawaii Island DLNR FAD coordinates hardcoded
  (source: DLNR Division of Aquatic Resources 6/14/07)
- FAD GeoJSON populated on style load from static data

Fishing mode plan:
- docs/superpowers/plans/2026-06-30-fishing-mode.md: 7-task plan for
  RigAdvisor, SST tiles, FishingModeManager, FishingOverlayView, steering
  bearing line, and FAB integration

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Tech debt: Room list fast-path, delete AnchorWatchHandler orphan, LogbookRepository thread safety</title>
<updated>2026-05-28T07:35:00+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-28T07:35:00+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=e16a5257f5c02034cd9703f465b1ec006d4bb1b0'/>
<id>urn:sha1:e16a5257f5c02034cd9703f465b1ec006d4bb1b0</id>
<content type='text'>
Room fast-path (item 3):
- TrackEntity.toShallowSavedTrack() reconstructs SavedTrack from cached summary
  data using two placeholder TrackPoints that preserve correct endMs for logbook
  filtering without parsing GPX
- TrackRepository.getSavedTracksFromRoom() returns shallow tracks sorted by startMs
- MainViewModel.init{} now shows Room data immediately (no spinner on warm start),
  then replaces with full GPX-parsed tracks once background load completes

AnchorWatchHandler orphan (item 4):
- Deleted ui/anchorwatch/AnchorWatchHandler.kt — the anchor depth/rode form was
  inlined into SafetyFragment; this Fragment had no navigation entry points left
- Deleted layout/fragment_anchor_watch.xml (only referenced by the deleted Fragment)

LogbookRepository thread safety (item 6):
- Added @Synchronized to save(), getAll(), and reload() to prevent concurrent
  mutation of the entries list and nextId counter across coroutine contexts

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Sort track history chronologically; add Report button to track list</title>
<updated>2026-05-27T16:45:10+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-27T16:45:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=91f5816120a6260fb8f057f6b7c0d6f0f2337c0e'/>
<id>urn:sha1:91f5816120a6260fb8f057f6b7c0d6f0f2337c0e</id>
<content type='text'>
- getSavedTracks() now returns tracks sorted by startMs ascending so
  the overview list shows oldest→newest
- item_saved_track.xml gets a small REPORT text button below the stats row
- SavedTrackAdapter wires onReport callback; SavedTracksFragment navigates
  to TripReportFragment.newInstanceForSavedTrack() after selecting the track
- TripReportViewModel.generateReportForSavedTrack(track) generates a
  post-trip narrative from a completed SavedTrack's points + logbook entries
- TripReportFragment detects ARG_FOR_SAVED_TRACK, reads selectedTrack from
  MainViewModel, and uses the saved-track variant; Refresh button re-runs
  the same variant

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Add Room database as track summary cache</title>
<updated>2026-05-27T15:41:28+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-27T15:41:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=e0df3913fe451056e6c5490f02faf3e8b2f2d33d'/>
<id>urn:sha1:e0df3913fe451056e6c5490f02faf3e8b2f2d33d</id>
<content type='text'>
Adds TrackEntity/TrackDao/NavDatabase (Room v2.6.1). TrackRepository
writes to Room on stopTrack() and importTrack(), and backfills existing
tracks on first cold-start when the Room cache is empty. GPX/SAF remains
source-of-truth for reinstall; Room is a fast metadata cache for future
list-view optimisation.

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Add RACE mode to TackDetector for rapid mark-rounding detection</title>
<updated>2026-05-27T05:38:24+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-27T05:38:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=4f87ae6cda6131012447a8b2ddde088bb8844b04'/>
<id>urn:sha1:4f87ae6cda6131012447a8b2ddde088bb8844b04</id>
<content type='text'>
Introduces TackMode enum (CRUISING/RACE) and per-mode Config, replacing
the previous single set of hardcoded constants.

RACE config: T_SETTLE=12s, T_MANEUVER=20s, STAB_MAX=30°, MIN_GAP=20s,
START_SKIP=20s — tighter windows for quick successive tacks at race
starts and mark roundings. CRUISING remains the default.

Two new tests demonstrate the behavioral difference: RACE fires earlier
(past 20s cold-start vs 60s) and keeps separate events for a 50s gap
that CRUISING deduplicates (50s &lt; 60s MIN_GAP). 18/18 passing.

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Persist logbook JSON and photos in SAF so they survive reinstall</title>
<updated>2026-05-26T20:35:38+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T20:35:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=0db33911ca4841c658b22912d3ecf32477e5e827'/>
<id>urn:sha1:0db33911ca4841c658b22912d3ecf32477e5e827</id>
<content type='text'>
- LogbookStorage: reads/writes nav_logbook.json and photos into the SAF
  logbook/ subfolder, using the same saf_tree_uri pref as TrackStorage.
  Automatically migrates legacy getExternalFilesDir JSON on first SAF
  write. Falls back to external files when SAF is not yet configured.
- LogbookRepository: expose cameraDir (cache-backed temp for FileProvider),
  copyPhoto(Uri), and importPhoto(File) instead of the old photoDir.
- VoiceLogFragment / TrackDetailSheet: camera writes temp to cacheDir then
  imports to SAF after capture; gallery delegates to copyPhoto(); photo
  display and decodeThumbnail handle both content:// URIs and file paths.
- file_paths.xml: add cache-path entry so FileProvider can serve camera
  temp files from cacheDir/nav_camera/.

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Fix gallery photo timestamp and map pin not updating after note save</title>
<updated>2026-05-26T09:13:38+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T09:13:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=9f298ac64183bcf54d2531e0363b205a04e3366a'/>
<id>urn:sha1:9f298ac64183bcf54d2531e0363b205a04e3366a</id>
<content type='text'>
Gallery photos were always anchored to track.endMs with the final GPS
position. Now reads EXIF DateTimeOriginal (parsed in device local time)
after copying the file; if the timestamp falls within the track window
the note is positioned at the correct time and nearest track point.
Notes taken outside the window fall back to the previous behaviour.

Map note layer was never refreshed after saving — drawNotes() ran once
at style-load time and the GeoJsonSource was never updated. Added
refreshNoteLayer() which updates the existing source or creates it if
no notes existed before.

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Fix ANR, false tack detections, and empty-state flash on track load</title>
<updated>2026-05-26T07:46:09+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T07:46:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=3673ed0ef79d776c6da3bfa0db9de8b08326fd32'/>
<id>urn:sha1:3673ed0ef79d776c6da3bfa0db9de8b08326fd32</id>
<content type='text'>
ANR: getSavedTracks() had no IO dispatcher — TackDetector ran on main
thread at O(n²) cost (~77M ops for a 2.5h track). Added withContext(IO).

TackDetector: replaced O(n) list.filter with O(log n) binary-search
subList for before/after windows; O(n²) → O(n log n). Raised MIN_DELTA
60°→75° to stop detecting ordinary course corrections as maneuvers.
Removed MAX_DELTA cap entirely — 180° crash-tacks are valid; the
circularMAD stability windows are the real quality gate.

TrackDetailSheet: dropped the arbitrary abs(delta)&gt;70 Tack/Jibe
heuristic. Now uses true wind angle when available for classification;
falls back to "Maneuver" when TWD is absent.

SavedTracksFragment: added isLoadingTracks StateFlow (MainViewModel);
combine() suppresses the empty-state layout while the initial IO load
runs so it no longer flashes "No saved tracks yet" before data arrives.

16/16 TackDetector tests pass.

https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
</content>
</entry>
<entry>
<title>Redesign tack detection: time-based windows + circularMAD stability</title>
<updated>2026-05-26T06:39:05+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T06:39:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/nav.git/commit/?id=8dbf3f883274fc0ddd16e5507f732629c85e3c91'/>
<id>urn:sha1:8dbf3f883274fc0ddd16e5507f732629c85e3c91</id>
<content type='text'>
Replace the point-count window (HALF_WIN=2) with 30s time-based settle
windows that give consistent reliability regardless of GPS update rate
(1 Hz FULL vs 0.2 Hz ECONOMY). Key changes:

- Before/after windows are time-based (T_SETTLE=30s) around a guard
  zone (T_MANEUVER=30s), not point counts.
- Stability uses circularMAD (&lt;20°) across all fixes in each window,
  replacing the single-pair spread check. This correctly handles
  0°/360° wrap and suppresses random anchor-watch COG noise (MAD≈90°).
- No SOG gate: averaging 30 fixes over 30s reduces noise by √30
  regardless of boat speed. A boat at anchor has MAD≈90° and is
  rejected by the stability check.
- MAX_DELTA raised to 160° (covers deep jibes the old 140° missed).
- START_SKIP reduced to 60s (stability check handles cold-start noise).
- De-duplication uses adjacent-candidate comparison so a long stream
  of raw candidates from one maneuver stays in a single group even if
  it spans &gt;MIN_GAP_MS in total.
- Position refined to max instantaneous heading rate within the
  maneuver zone.
- Mode: CRUISING (conservative). Race mode noted as future backlog.

16/16 unit tests pass at 1 Hz (FULL mode GPS rate).

https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
</content>
</entry>
</feed>
