| Age | Commit message (Collapse) | Author |
|
- Fix track events persisting on main map: clear selectedTrack and pop
track_detail back stack in hideOverlays() so speed segments and tack
circles are removed when navigating to Map via bottom nav
- Notification: dual channels (recording=DEFAULT, background=MIN);
shows app name + "Recording journey · Xh Ym · X.X nm"; updates live
from trackStats collector; invisible when not recording
- Log tab: unified reverse-chronological ship's log merging saved tracks
+ standalone notes (no photo-only rows); form hidden when not recording
with "New Note" button → AlertDialog (with camera/gallery); combine()
flow keeps list reactive to both tracks and log entries
- Sheet border: bottom nav + fragment container now use colorSurfaceContainerHigh
matching the instrument card's elevated surface color; card elevation set
to 0dp with explicit background to avoid double-tinting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
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 <noreply@anthropic.com>
|
|
- Remove ic_close icon from Quit App button (fragment_safety.xml)
- fab_fishing now hides/shows in showOverlay/showTrackDetail/hideOverlays
so fishing+record FABs always move together and disappear on non-map pages
- Add strokeWidth=0dp to instrument bottom sheet card to remove gray border
- Fix blank map: split addToStyleBuilder into addSourcesToStyleBuilder
(builder time) + addBaseLayersToStyle (inserts at index 0, below OFM
vector layers) + addOverlayLayersToStyle (appends above OFM labels).
Previously withLayer() appended rasters after OFM layers so the opaque
Ocean base covered all labels/roads.
- Add Log.d tracing throughout style load + layer insertion for debugging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
cleanup
- Layer picker: change android:src→android:background on preview ImageViews; shape
drawables have no intrinsic size so centerCrop renders blank — background fills correctly
- Replace ic_fish with ic_fishing_pole (rod + reel + line + hook vector)
- Move fab_fishing to CoordinatorLayout with layout_anchor on instrument_bottom_sheet
top|start, matching fab_record_track positioning so both FABs sit level at sheet top
- Raise fishing_overlay marginBottom 140dp→200dp to clear the realigned FAB
- Safety: remove HELP button + DocFragment import from SafetyFragment; rename Quit→Quit App
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
at zoom 13
- Remove fab_night_mode from layout and all MainActivity code (nightModePrefs,
isNightMode, fabNightMode field, onCreate theme apply, click handler, applyScreenBrightness)
- Raise fab_fishing marginBottom 80dp→136dp so it clears the instrument sheet peek (120dp)
- Set maxZoom=13 on Esri Ocean Base TileSet; tiles stop at z13, MapLibre overzooms
rather than fetching blank 404 tiles at higher zoom levels
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
sections
Replaces ScrollView + flat switch list with NestedScrollView + GridLayout
card sections: BASE MAP (2x2 preview cards), NAVIGATION, OCEAN DATA,
WEATHER, MY DATA (toggle cards with 48dp previews), and UNITS (unchanged).
Stubs out old chip_group_base wiring in LayerPickerSheet.kt pending Task 7 rewrite.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Adds FishingOverlayView + fab_fishing to layout, initializes FishingModeManager,
and wires FAB click to toggle fishing mode with SST layer and target overlay.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Adds SST source/layer to MapLayerManager, SST toggle to LayerPickerSheet
UI and wires it up in MainActivity.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
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 <noreply@anthropic.com>
|
|
- MapLayerManager: depth contour tiles (OpenSeaMap), seamarks made
toggleable (was always visible), FAD pref; layer order is now
satellite → charts → wind → depth → seamarks
- MapHandler: FAD GeoJSON layer (orange circles + zoom-10 labels),
setupFadLayer / setFadLayerVisible / updateFadLayer helpers
- LayerPickerSheet: wire seamarks, depth, FAD switches; fix chip
binding direction bug (DepthUnit.METERS side was swapped)
- layout_layer_picker_sheet: add OCEAN LAYERS section with three
toggles (seamarks/nav aids, depth contours, FADs)
- MainActivity: call setupFadLayer on style load; wire all three
ocean layer callbacks in buildLayerPickerSheet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Transport:
- NmeaStreamManager supports TCP and UDP modes
- NmeaConnectionPrefs replaces hardcoded 192.168.1.1:10110; defaults
to UDP/10110 matching PMIM-1 spec (ESP32 AP at 192.168.4.1)
- LocationService reads prefs via startNmeaFromPrefs()
Parsing:
- NmeaParser.parseXdr() handles $IIXDR attitude (HEEL/PTCH in degrees)
and baro (pressure in bar → hPa, air temp °C)
- New AttitudeData and NmeaBaroData sensor types
UI:
- Heel + pitch row in instrument sheet (hidden until data arrives)
- InclinometerView: canvas circle with rotating waterline (heel) and
displaced dot (pitch), colorPrimary-tinted, respects night mode
- Inclinometer overlay top-left of map, appears on first attitude packet
- NMEA baro overrides device sensor reading when available
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
Single-tap moon FAB (stacked below layers FAB) toggles red-on-black
night vision mode. NightVision theme now has a full M3 color palette
(surface, surfaceVariant, outline, secondary, error) all in dark red
tones. Screen brightness is set to 30% in night mode and restored to
system default on exit. State persists across sessions; recreate()
applies the theme switch cleanly.
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
Replaces monospace text block with:
- Full-bleed MapLibre track map (260dp) at the top
- Structured stats row (distance / avg speed / max speed)
- Conditions row (wave height, temp) in user-preferred units
- Log entries with full-width photo thumbnails
- Pirate mode Easter egg preserved via long-press title
- Speed, temp, and depth formatted with UnitPrefs
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
entries
Layout:
- Stats displayed as three large-number columns (distance / avg kt / max kt)
- Date and time range as a clean header above stats
- Conditions row (seas + temp) conditionally shown
- Log entries rendered as a proper list with HH:mm timestamps
- No GENERATE REPORT button — report auto-generates on open; RETRY shown only on error
- Pirate mode (long-press title) still renders monospace narrative as before
Generator:
- Time format changed from 4-digit HHmm to HH:mm
- "(photo only)" entries display as 📷 instead of literal "(photo only) [photo]"
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
Each track row already has a REPORT button; the standalone button was redundant.
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
LogbookRepository thread safety
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
|
|
- 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
|
|
Replaces the "Configure Anchor Watch" button with depth and rode EditTexts
directly in the anchor card; radius updates live via TextWatcher.
Removes the separate AnchorWatchHandler overlay flow and onConfigureAnchor()
from SafetyListener.
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
Long-press the "Trip Report" header flips the narrative into pirate
dialect (☠ VOYAGE header, "Made X nm by the log", "Avast!" log-entry
prefixes, closing "Fair winds and following seas. Arr."). Long-press
again returns to standard nav voice. Seamanlike output remains the
default; pirate mode is purely opt-in.
https://claude.ai/code/session_01KXYBuAHZkvv63DeUG6XaZD
|
|
- TrackDetailSheet: + Add note button opens a dialog with text, camera,
and gallery. Entry is saved with timestampMs=track.endMs so it lands
inside the track's time window and appears automatically in the event
log. logEventAdapter.update() refreshes the list after save.
- TripReportGenerator: removed NarrativeStyle enum and 4-style branch.
generateNarrative() now emits a concise PASSAGE header (date, time
range, duration), stats line (nm / avg kt / max kt), optional conditions
(seas, temp), and a timestamped deck log. Fragment and layout updated to
remove the ChipGroup style picker.
- TrackColors: replaced Expression.get("color") — which silently fails
for lineColor on LineLayer in MapLibre Android 11.x — with
Expression.step(Expression.get("speed"), ...) that maps the numeric
"speed" property directly to color literals. "color" string property
removed from speedSegments() features.
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
LocationService:
- Add _currentSpeedKt/_currentDirectionDeg to companion state
- Add setCurrentConditions() companion function
- snapshot() now returns real current data instead of null
- MainActivity.applyConditions() calls setCurrentConditions() on each
marine conditions update
TrackDetailSheet:
- buildLogEvents() filters NavApplication.logbookRepository entries by
track time window (startMs..endMs); entries without GPS snap to nearest
track point by timestamp
- Note/photo events added to the event log list with 📝/📷 icons
- drawNotes() adds a green CircleLayer for note/photo markers on the map
- LogEvent extended with photoPath field
- LogEventAdapter shows a downsampled photo thumbnail when present
item_log_entry.xml: add iv_log_thumb ImageView (hidden by default)
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
- LogbookStorage: Moshi-backed JSON persistence to getExternalFilesDir,
photos saved to Pictures/Nav/ instead of cache
- LogbookRepository: file-backed replacement for in-memory store, loads
saved entries on init so they survive app restarts
- VoiceLogViewModel: expose entries StateFlow, accept lat/lon in save()
- VoiceLogFragment: switch camera to TakePicture(Uri) via FileProvider for
full-res photos; gallery copies content URI to persistent storage;
passes current GPS position to save(); shows scrollable entries list
- MainViewModel: expose currentPosition StateFlow updated on each GPS fix
- AndroidManifest: add FileProvider for Pictures/Nav/ directory
- TripReportViewModel: updated to use LogbookRepository
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
past track opacity
- Tack detector: STABILITY_MAX=30, START_SKIP_MS=120s cold-start filter (feature branch)
- TrackDetailSheet: embedded Fragment with MapView, back button pops stack (feature branch)
- layout_track_detail_sheet: MapView top half, detail panel bottom half (feature branch)
- MapHandler past track dim opacity: 0.12 (down from 0.22)
- SavedTracksFragment: fragment transaction to TrackDetailSheet + SAF setup (both)
- VoiceLogFragment: inline track list, logViewModel refs fixed (main)
|
|
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
TackDetector: revert STABILITY_MAX to 30° (was tightened too far to 20°),
add 120s start-skip to filter GPS cold-start false positives, keep 45s
minimum gap between tacks.
TrackDetailSheet: convert from BottomSheetDialogFragment to a regular
Fragment with an embedded MapLibreMap in the top half. This fixes the
map centering issue (the embedded map is always sized to its own frame),
eliminates accidental dismissal when dragging the map, and makes the
view self-contained — back navigation restores the track list via the
fragment back stack. Tack markers rendered on the embedded map; tapping
a log event pans the embedded map directly.
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
Removed the 'Saved Tracks' button that opened a separate overlay.
Tracks now appear directly on the Log screen in a RecyclerView below
the Generate Trip Report button. Tapping a track hides the overlay and
opens the existing TrackDetailSheet bottom sheet over the map.
The log entry section (text field, mic, camera, save/clear) is hidden
with visibility=gone when not recording and shown when a recording is
in progress. The storage-setup prompt is now surfaced here too.
SavedTrackAdapter and DATE_FMT widened to internal so VoiceLogFragment
can reuse them directly. SavedTracksFragment kept for the GPX import flow.
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
sheet
Recenter button was reappearing over overlays because the isFollowing
flow kept calling fadeIn(fabRecenter) even when an overlay was visible.
Added overlayShowing flag — the flow skips FAB updates while an overlay
is shown. hideOverlays() now correctly restores fabRecenter visibility
based on the actual following state instead of just resetting alpha.
Speed up/Slow down events fired on every 1.5 kt GPS jitter, flooding
the log with noise. Removed the detection loop entirely — no reliable
motor on/off signal is available from GPS alone.
TrackDetailSheet converted from a full-screen Fragment to a
BottomSheetDialogFragment: opens at half-screen height so the track
route is visible on the map behind it, draggable to full height, 20%
background dim. SavedTracksFragment now calls hideOverlays() then
sheet.show() instead of fragment-replacing the overlay container.
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
Removed the spurious constraintBottom_toBottomOf="parent" from forecast_row:
ConstraintLayout was vertically centering it between the wave and the sheet
bottom (default bias 0.5) instead of placing it flush below the wave.
Also aligned light-mode wave_sea_bottom (#074B68 → #0D2137) with the
forecast_row background so the wave tail blends seamlessly in light theme.
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
- hideOverlays() now resets bottomSheetBehavior to COLLAPSED/not-hideable,
so the conditions sheet reappears correctly when returning from any overlay
(previously it stayed hidden after navigating away via the track browser)
- Remove btn_saved_tracks from the conditions sheet (layout + click handler)
- Add btn_saved_tracks to the Log screen layout and wire it in VoiceLogFragment
via MainActivity.showSavedTracks(); tracks live with the log, not with weather
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
Intent filter fixes:
- Remove pathSuffix=".gpx" + scheme restriction from the application/octet-stream
ACTION_VIEW filter; pathSuffix matches the URI path, not the filename, so it
never fired against file manager content URIs (opaque paths like /provider/uuid).
The existing display-name check in handleIncomingGpx() is the correct gate.
- Add ACTION_SEND filter for application/octet-stream; Nav was invisible in share
sheets because most file managers send this type for .gpx files.
SAF-based track storage (API 29+):
- Replace fragile SharedPrefs URI cache + OWNER_PACKAGE_NAME MediaStore query with
Storage Access Framework as the primary write/read path. The user grants access to
their tracks folder once via ACTION_OPEN_DOCUMENT_TREE; DocumentFile.listFiles()
finds all GPX files without relying on MediaStore ownership (which Android clears
on uninstall). After reinstall, a one-tap "Restore track access" button in Saved
Tracks re-authorizes the same folder and all tracks immediately reappear.
- MediaStore path (existing) is kept as fallback for tracks saved before this change
- Add SafState enum (CONFIGURED / PERMISSION_LOST / NOT_CONFIGURED) in TrackStorage
- TrackRepository exposes safState() and initSafDirectory() thin wrappers
- MainViewModel exposes safState StateFlow and onSafDirectorySelected()
- SavedTracksFragment observes safState and shows contextual setup / re-auth button
- MainActivity registers safPickerLauncher and exposes launchSafPicker()
- Add androidx.documentfile:documentfile:1.0.1 dependency
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
|
|
Saved tracks browser:
- TrackDetailSheet converted from BottomSheetDialogFragment to Fragment so
it fills the overlay instead of floating over the map
- Adapter tap pushes detail fragment onto the back stack; back button returns
to the list naturally via popBackStack()
- SavedTracksFragment back button calls hideOverlays() (made internal) to
close the overlay and return to the map
- Layout updated to full-screen: header with back button, RecyclerView fills
remaining space via layout_weight instead of fixed 300dp
GPX import persistence:
- TrackRepository.importTrack() saves parsed points to Documents/Nav/ via
TrackStorage (URI is persisted to SharedPreferences) and adds to
in-memory list
- MainViewModel.addImportedTrack() now calls importTrack() so files opened
via the GPX handler load on future launches
https://claude.ai/code/session_01DNjbYxiC1cco83dArNGW3G
|
|
- TackDetector: sliding-window COG algorithm (60-140deg delta = tack/jibe)
with stability check to prevent mixed-window false positives; 13 tests green
- TackEvent, SavedTrack: new models wrapping points + summary + detected tacks
- TrackRepository.getSavedTracks(): returns List<SavedTrack> with lazy load
- MapHandler: zoomToTrackBounds (LatLngBounds fit with padding),
panToPoint (log step-through), updateTackLayer (yellow circle markers)
- MainViewModel: savedTracks + selectedTrack StateFlows, panToPosition SharedFlow
- SavedTracksFragment: RecyclerView list with date/distance/duration/tack count
- TrackDetailSheet: bottom sheet with stats + event log (tacks, speed changes,
start/end); tapping an entry pans the map to that position
- MainActivity: zoom map on track complete, wire Saved Tracks button in
instrument sheet, observe panToPosition to drive map, show tack markers
when a saved track is selected
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Bottom nav: remove it from the following/panning fade cycle — only
fabRecenter and fabRecordTrack swap; nav stays visible throughout.
Drag handle: 4dp × 36dp was too small and competed with BottomSheet
drag gestures. Now 40dp tall via inset drawable (visual bar unchanged,
touch area is a usable 40dp × 36dp).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Layers menu:
- Add "Past tracks" switch to layer picker sheet — hides/shows previous
voyage polylines on the map, persisted across sessions via SharedPrefs
Vessel/crew registry:
- VesselRepository now takes a Context and persists all vessels and crew
to SharedPreferences as JSON (Moshi, same pattern as BoatProfileRepository)
- Wire VesselRepository as a singleton in NavApplication so the Fragment
and ViewModel share one instance — previously each created its own empty repo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Replaces the nav_layers bottom nav item with a mini FloatingActionButton
anchored below the HUD, giving layers access without occupying a nav slot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Brings in dev log (NavLogger), UnitPrefs, MapLayerManager, HUD views,
conditions throttling, track save/load pipeline, improved ParticleWindView
(antimeridian-aware, dynamic particle count), Snackbar error surfacing,
and all other main-branch work from the prior session.
Combined with master's hardware source flags, vessel registry, crew
management, thermal alarm, CPA collision alerts, and track stats.
Also documents primary branch policy in CLAUDE.md and .agent/config.md:
all work merges to main, never master.
https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
|
|
CI fixes:
- ParticleWindView: bounds.lonEast → bounds.northEast.longitude
(MapLibre 13.x API; lonEast not available as property)
- VesselRegistryFragment: Vessel(id="") and CrewMember(id="") →
include required name="" so copy() compiles
Hardware source feature flags:
- HardwareSource enum: AIS_RECEIVER, NMEA_INSTRUMENTS
- FeatureFlags: SharedPreferences-backed; all sources default OFF
(app works phone-only out of the box)
- NavApplication: exposes featureFlags singleton
- SafetyFragment: "HARDWARE DATA SOURCES" card with two MaterialSwitch
toggles; reads initial state from FeatureFlags; calls
SafetyListener.onHardwareSourceChanged on change
- AIS_RECEIVER flag:
- MainViewModel.processAisSentence() / refreshAisFromInternet() skip
when disabled; onHardwareSourceChanged() clears targets + cpaAlerts
- NMEA_INSTRUMENTS flag:
- LocationService skips nmeaStreamManager.start() on service launch
when disabled
- New ACTION_START_NMEA / ACTION_STOP_NMEA intents allow live toggle
- MainActivity.onHardwareSourceChanged() sends the appropriate intent
Tests: 102 total, all GREEN (+7 FeatureFlagsTest)
https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
|
|
CPA/TCPA alerts:
- CpaAlert data class with severity (CAUTION/WARNING/DANGER) and label()
- CpaThresholds: 0.5/1.0/2.0 nm, max TCPA 30 min
- MainViewModel.updateCpaAlerts() runs on every GPS update and AIS
sentence; skips stationary contacts; filters TCPA ≤ 0 or > 30 min;
sorts by TCPA ascending
- SafetyFragment: new COLLISION AVOIDANCE card shows live alert list,
color-coded by severity; clears to "No traffic alerts" when safe
- MainActivity: observes cpaAlerts → safetyFragment.updateCpaAlerts()
Track stats:
- TrackStats data class: distanceNm, durationMs, avgSogKnots,
durationFormatted (m:ss / h:mm:ss)
- TrackRepository.haversineNm() + computeStats() using point timestamps
- MainViewModel exposes trackStats StateFlow, cleared on stopTrack()
- activity_main: dark pill overlay bar (tv_track_stats) above map
- MainActivity: shows "● REC 0.00nm m:ss x.xkt avg" while recording
Tests: 95 total, all GREEN (+16 new — 9 TrackStats, 7 CpaAlert)
https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
|
|
- Vessel/CrewMember data classes with full profile fields
(MMSI, callsign, flag, home port, hull type, dimensions, roles)
- VesselRepository: in-memory CRUD for own vessel, fleet, and crew;
getOwnVessel(), getSkipper(), getCrewByRole() helpers
- VesselRegistryFragment: own-vessel card + crew list + known-vessels
list; AlertDialog editors for add/edit; long-press to delete
- ic_vessel.xml sailboat icon; 5th bottom-nav tab "Vessel"
- ThermalMonitor: thermalFlow() using Intent.ACTION_BATTERY_CHANGED
(battery °C) + PowerManager.OnThermalStatusChangedListener (API 29+);
ThermalState OK/WARM/HOT/CRITICAL with distinct-until-changed filter
- MainActivity: startThermalMonitoring() sounds mob_alarm + Toast on
HOT (≥45°C) and CRITICAL (≥50°C); auto-silences on OK/WARM
- MainViewModel: thermalState and thermalReading StateFlows
- 18 VesselRepositoryTest cases — all GREEN (test-runner)
- design.md: updated competitive matrix + feature implementation status
https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
|
|
NavLogger is a 200-entry in-memory ring buffer with format:
HH:mm:ss.SSS LEVEL tag: message
Entries are written at:
- App start
- First GPS fix (lat/lon/sog/cog)
- fetchCurrentConditions: request params + full success summary
(wind, temp, waves, swell, current) or exception class+message
- fetchForecastItems: request params + item count or error
DevLogSheet (BottomSheetDialogFragment) shows the log in a
monospace ScrollView with Copy and Clear buttons. Trigger: long-press
the drag handle bar on the instrument bottom sheet.
Primary use: copy the log and paste it to Claude to diagnose
conditions API failures without needing adb.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
GONE collapses the spinner's space, causing the value/unit TextViews to
reflow and bounce on every refresh. INVISIBLE keeps the 10dp width
reserved so the surrounding text never moves.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
Day (light mode): vivid sky blue (#2B8FC4 → #87C8DF) fading into
tropical deep-sea blue (#0D7A9A → #074B68) — evokes a clear Kona
afternoon with deep Pacific below. Shimmer is bright white sunlight
on water (#50FFFFFF).
Night (dark mode): retains the existing dark charcoal sky (#1C1B1F →
#162433) and midnight navy sea (#0B3050 → #0D2137) with blue shimmer.
Colors are defined as adaptive color resources (values/ and values-night/)
and read in WaveView.onSizeChanged() and paint init instead of hardcoded
Color.parseColor() calls.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
Rounded corners:
- Replace androidx CardView with MaterialCardView + ShapeAppearance.Nav.BottomSheet
so only the top-left and top-right corners are rounded (24dp); bottom corners
are square flush with the screen edge
Light/dark mode:
- Introduce values-night/colors.xml with the existing dark M3 palette (moved from
values/colors.xml); instrument values stay dark (#E6E1E5 text, #1C1B1F bg)
- values/colors.xml now carries the light M3 palette: surface #FFFBFE,
onSurface #1C1B1F, surfaceVariant #E7E0EB etc.; instrument text flips to dark
(#1C1B1F normal, #6F6878 secondary) for readability on light backgrounds
- Fix InstrumentUnit hardcoded #6B6070 → ?attr/colorOnSurfaceVariant so the
unit labels adapt automatically in both modes
- Mark the forecast row (ocean navy #0D2137) and WaveView with
android:forceDarkAllowed="false" so the system never inverts them — the
ocean section is intentionally always dark regardless of system theme
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
- Add _conditionsLoading StateFlow to MainViewModel; set true when
loadConditions() fires, false when the fetch completes (success or fail)
- Cancel any in-flight conditions job when a new loadConditions() call
arrives (e.g. rapid map pans) so only the latest fetch drives the state
- Add a 10dp ProgressBar after each of the six data values in
layout_instruments_sheet.xml (wind, temp, baro, current, waves, swell);
visibility GONE by default, alpha 0.5; header section tinted
colorOnSurfaceVariant, forecast section tinted #5B9EC2 to match its labels
- Observe conditionsLoading in MainActivity and toggle all six spinners
together (all values come from one API call so they load in sync)
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
- Strip all three unverified external link cards (ASA courses, ASA online,
Quizlet flashcards) from the Learn tab — asa.com is a Brazilian financial
site, not the American Sailing Association
- Remove dead openUrl() click handlers and unused Intent/Uri imports from LearnFragment
- Parallelize the two sequential API calls in fetchCurrentConditions so the HUD
populates in ~half the time (weather + marine fetched concurrently via async/await)
- Add onFailure logging in loadConditions so errors are visible in logcat instead
of silently swallowed
- Eagerly call loadConditions in the setStyle callback as a startup backstop: the
camera-idle listener fires before GPS fixes and the initial position may be (0,0),
so this guarantees a real fetch once the style is ready with a valid camera position
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
departure picker
Learn tab
- ic_open_in_new.xml: external link icon (box + arrow) applied to all browser-opening cards
- Migration guide cards retain internal › chevron; ASA/Flashcards cards show ↗ icon
- New REFERENCE section (offline, works without connectivity):
- ColRegs Rules of the Road → colregs_reference.md (rules 1–38, lights table,
sound signals, day shapes, memory aids)
- Sailing Quick Reference → sailing_reference.md (points of sail, Beaufort scale,
nav lights, knots, buoyage IALA-B, VHF channels, distress signals, tide rule of 12)
- ColRegs card moved from external ASA section to offline REFERENCE section
Log entry
- LogEntry: add photoPath field (absolute file path or content URI string)
- VoiceLogViewModel: replace confirmAndSave() with save(text, photoPath?) so the
fragment controls text (user may edit recognized speech before saving)
- VoiceLogFragment: redesigned layout with EditText (editable, voice fills it),
camera button (TakePicturePreview → JPEG in cacheDir), gallery button (GetContent),
photo thumbnail with remove button, Save / Clear row
- Manifest: add android.hardware.camera uses-feature (required=false)
Departure date/time picker (trip planning)
- ic_calendar.xml: calendar icon for the picker button
- PreTripReportViewModel: _departureMs StateFlow (default = now), setDeparture(ms)
- PreTripReportGenerator.generateReport(): departureDateTimeMs param;
findDepartureSlot() matches nearest UTC forecast item; condition window labels show
actual local times (e.g. "2 PM") when departure is not near-now; buildWatchList
uses departure hour for Kona trades warning instead of system clock
- fragment_pretrip_report.xml: DEPART card with label + calendar button above generate
- PreTripReportFragment: MaterialDatePicker (future dates only) → MaterialTimePicker
chain; auto-regenerates after picker confirms
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
UI cleanup:
- Remove always-visible MOB FAB — Safety screen button is sufficient
- Remove floating quit button; move to bottom of Safety screen
- fragment_container is now clickable/focusable, blocking map touch-through
for all overlays (trip reports, log, safety)
- Record Track FAB hidden while any overlay is shown, visible on map tab
New Learn tab (5th nav item):
- Migration guides for Navionics and Sea People (local markdown via DocFragment)
- ASA Course Catalog, ASA Online Learning, ColRegs, Sailing Flashcards
(open in browser)
- Remove blanket assets/ .gitignore so markdown docs are tracked
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
colorBackground is not a Material theme attribute; replace with
colorSurface which is the correct equivalent.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|