summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-05fix: remove crash-risk !! operators in UnitPrefs and MainViewModelPeter Stone
UnitPrefs: getString() returns String? even with a non-null default, so !! crashes on corrupted prefs. Replaced with explicit elvis fallback to the same enum default. MainViewModel: forecastResult.getOrThrow() is logically safe (when-branch guards it) but unnecessarily brittle. Replaced with getOrNull() ?: emptyList(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05fix: guard past-track load against SecurityException before permissions grantedPeter Stone
MediaStore.query() throws SecurityException if storage permission hasn't been granted yet. The ViewModel init{} fires before the permission dialog result, so the coroutine crashed the app on first launch. - Wrap contentResolver.query() in runCatching in loadViaMediaStore() - Wrap getPastTracks() call in init{} with runCatching; log failure, don't crash Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05fix(ci): write version to gradle.properties instead of -P flagsPeter Stone
Parentheses in the version name (e.g. "(abc1234 message)") caused gradlew's internal eval to fail with "Syntax error: ( unexpected" because gradlew is /bin/sh and parens have special meaning in eval. Writing the values directly to gradle.properties avoids shell interpretation entirely — Gradle reads it as a plain key=value file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05fix: load past tracks on startup; add debug logging throughoutPeter Stone
Root cause: getPastTracks() was only called inside stopTrack(), so saved tracks were never loaded unless a new track was recorded in the same session. Added init{} block to MainViewModel to load them at startup. Logging added: - getPastTracks(): first-call vs cached, count + point sizes - loadViaMediaStore(): cursor row count, per-file parse attempt, point count per file, any openInputStream null or parse errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05feat: auto-increment build version with commit summaryPeter Stone
versionCode = github.run_number (increments each CI run) versionName = "1.0.<run> (<short-sha> <commit subject>)" e.g. "1.0.47 (2123351 fix: keep bottom nav visible when panning)" Local builds show "1.0-local (1)" as fallback. Firebase release notes also show the version string. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05fix: keep bottom nav visible when panning; expand drag handle touch targetPeter Stone
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>
2026-05-05fix: raise conditions throttle to 20 min / 10 nm to stop 429sPeter Stone
Previous gate (5 min AND 2 nm) meant any pan > 2 nm triggered a fresh fetch regardless of how recently one completed. Raised to 20 min OR 10 nm — marine conditions don't change meaningfully at finer resolution than that. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05fix: hide layers FAB when any overlay is shownPeter Stone
showOverlay/hideOverlay already managed fabRecordTrack visibility; extend the same pattern to fabLayers so it disappears on safety, log, vessel, learn, and anchor watch screens. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05fix: throttle wind/weather fetches to reduce 429sPeter Stone
Camera idle: debounce 1.5s so rapid panning/zooming collapses into one fetch loadWindGrid: skip if center moved < 10 nm AND last fetch < 15 min ago (was unbounded — fired on every camera-idle with no gate at all) loadConditions already had a 5 min + 2 nm gate; unchanged Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04feat: past tracks layer toggle + persist vessel/crew registryPeter Stone
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>
2026-05-04feat: move Layers from bottom nav to dedicated FABPeter Stone
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>
2026-05-03resolve merge conflict in .claude/settings.local.jsonPeter Stone
Keep HEAD version which has the full set of Android emulator and tooling permissions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23Merge origin/main — unite all work onto one branchClaude
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
2026-04-23fix(ci): remove smoke-test job and artifact uploads entirelyClaude
https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-23fix(ci): add retention-days to artifact uploads to prevent quota exhaustionClaude
APKs accumulate across runs with no expiry; 1-day retention for the intermediate test-apks handoff, 7 days for smoke-test results. https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-23Merge branch 'claude/vessel-crew-thermal-features-Qbk4z'Claude
Resolves LatLngBounds conflict in ParticleWindView.scatter() — keeps the correct MapLibre 13.0.1 API (southWest/northEast) over the broken flat property accessors. https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-22fix(build): replace deprecated LatLngBounds property accessorsClaude
MapLibre 13.0.1 only exposes northEast/southWest LatLng corners; the flat latSouth/latNorth/lonWest/lonEast properties don't exist and cause unresolved reference errors. Replace all occurrences in ParticleWindView and MainActivity with the correct .southWest.latitude / .northEast.* accessors. https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-22Merge branch 'claude/hardware-source-flags'Claude
CI fixes + hardware source feature flags. 102 tests, all GREEN. https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-22fix+feat: CI build fixes and hardware source feature flagsClaude
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
2026-04-22Merge branch 'claude/cpa-alerts-track-stats'Claude
CPA/TCPA collision alerts (wired CpaCalculator) + live track stats. 95 tests, all GREEN. https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-22feat: CPA/TCPA collision alerts and live track statsClaude
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
2026-04-22Merge branch 'claude/vessel-crew-thermal-features-Qbk4z'Claude
Vessel registry, crew management, and thermal alarm. All 18 new VesselRepositoryTest cases GREEN (59 total across suite). https://claude.ai/code/session_011h2dXbgXg3PesQMmQUNTCW
2026-04-22feat: vessel registry, crew management, and thermal alarmClaude
- 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
2026-04-15ci: remove smoke-test jobPeter Stone
2026-04-15ci: upload to Firebase before archiving test APKsPeter Stone
2026-04-14CI: run on claude/** branches; skip Firebase deploy on non-mainClaude
Adds claude/** to push triggers so CI runs on every feature branch push — enabling check-run inspection via GitHub API without requiring a manual main push first. Firebase distribution is already gated on refs/heads/main; adding the event_name check ensures it also won't fire on PRs from main. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-13chore: trigger CI buildPeter Stone
2026-04-13Wire NavLogger into track save/load pipelineClaude
TrackStorage now writes to NavLogger at every decision point: - Before MediaStore insert (shows the filename being written) - Successful save: "saved nav_<ts>.gpx (N bytes) → <uri>" - Every failure path: storage not mounted, insert null, openOutputStream null, write exception, load parse error - After loadViaMediaStore: count of tracks found TrackRepository logs stopTrack summary (pts / duration / distance) and explicitly logs when saveTrack returns false. Long-press the drag handle after injecting a test track to see exactly where the save pipeline breaks. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-12Fix Actions storage: set artifact retention-daysClaude
test-apks: 1 day — only needed for the smoke-test job in the same run smoke-test-results: 7 days — enough for post-failure debugging Default is 90 days; at ~30 MB per run this was filling the 500 MB free-tier limit in ~2 weeks. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Throttle conditions API; delay particle view until data loadedClaude
loadConditions now skips the API call if conditions were loaded < 5 min ago and position hasn't moved > 2 nm — prevents 429 from overlapping triggers (startup backstop, GPS first-fix, camera idle). Dev log shows "conditions: skip age=Xs dist=Y.Znm" when throttled. ParticleWindView starts hidden and is revealed only when the first windArrow value arrives, so particles don't flash before the map loads. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Add hidden dev log (long-press drag handle)Claude
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
2026-04-11Surface conditions API errors as SnackbarClaude
Adds _conditionsError SharedFlow to MainViewModel that emits the exception class + message on fetchCurrentConditions failure. MainActivity collects it and shows a LENGTH_LONG Snackbar — no adb required to see why conditions aren't loading. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Stop 1 Hz conditions hammering; improve error loggingClaude
The camera idle listener fires every time following-mode GPS moves the map (~1 Hz). Each fire was calling loadConditions, which meant a new API request (and spinner flash) every second. Fix: skip the camera idle loadConditions call when isFollowing == true — the GPS first-fix handler already owns that trigger. Camera idle only loads conditions when the user has manually panned away from their position. Also include exception class + message in the logcat tag so the actual API failure reason is visible without --stacktrace: adb logcat -s Nav:E https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Fix: use INVISIBLE instead of GONE for condition spinnersClaude
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
2026-04-11Fix: add explicit parent to ShapeAppearance.Nav.BottomSheetClaude
Dot-notation style names imply a parent by convention; AAPT was looking for ShapeAppearance.Nav which doesn't exist. Parent is now ShapeAppearance.Material3.Corner.None (all-zero base) with the top corners overridden to 24dp. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11WaveView adapts sky/sea colors to light/dark modeClaude
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
2026-04-11Fix bottom sheet corners; add full light/dark mode paletteClaude
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
2026-04-11Fix: restore accidentally dropped fun addGpsPoint declarationClaude
Edit tool dropped the function header when inserting injectTestTrack/ buildTestTrack above it. Restore `fun addGpsPoint(...)` so the build compiles. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Show loading spinners next to each instrument value during conditions fetchClaude
- 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
2026-04-11Add dev shortcut to inject a synthetic test trackClaude
Long-press the record FAB while NOT recording to immediately save a pre-built 30-minute west/return circuit from Honokohau Harbor. Uses the existing startTrack/addPoint/stopTrack pipeline so the full save flow — TrackSummarySheet, GPX file write, past-tracks list — all execute without needing to move. Points carry manually-set timestampMs values (30 min in the past, 2-min spacing) so the 2-minute duration validation passes. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Remove bad ASA external links; fix conditions not loading on startupClaude
- 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
2026-04-11Merge branch 'claude/particle-wind-simulation-IMVxT'Claude
Particle wind animation, Learn tab, log text/photo, departure picker, outbound link markers, offline ColRegs + sailing reference content. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-11Four features: outbound link markers, offline content, log text/photo, ↵Claude
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
2026-04-11Improve particle wind animation: longer lifetimes, wind-scaled count, zoom ↵Claude
scatter - MAX_AGE 8s → 25s: particles live much longer, drastically less twinkle - activeN scales 60→300 with wind speed (0–25 kt): calm = sparse drift, strong wind = dense streaks - Zoom-out detection: scatter() fires immediately when latRange grows >1.8×, instantly filling the new viewport instead of waiting for old particles to die - Alpha uses sine curve (sin(π·age/MAX_AGE)) instead of linear fade: particles ease in from birth, peak at mid-life, and ease out — no bright birth flash that caused the twinkle effect https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Add Learn tab; move quit to Safety; remove persistent MOB FABClaude
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
2026-04-10Suppress map label flicker from GPS jitterClaude
GPS settling produces many tiny position updates that each triggered a 1-second animateCamera(), forcing continuous symbol-collision recalculation and label fade cycles. Fix: skip animation entirely (moveCamera) when the new position is < 3 m from the last one; use a shorter easeCamera(400 ms) for real movement so the animation window is smaller. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Lock MainActivity to portrait orientationClaude
Layout doesn't support landscape; rotating was causing a crash. configChanges also prevents unnecessary activity recreation if the system somehow delivers an orientation event anyway. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Fix invalid colorBackground theme attr in pretrip layoutClaude
colorBackground is not a Material theme attribute; replace with colorSurface which is the correct equivalent. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Add boat profiles and overhaul pre-trip departure briefingClaude
- BoatProfileRepository: Moshi+SharedPrefs persistence, pre-seeds Erickson 23 (155%/100%/65% headsails, 2 reefs) and Cal 20 (1 reef) - PreTripModels: expand with SailConfig, ConditionSlice, RouteProjection, WatchItem, SimilarTripSummary; full BoatProfile with sail inventory - PreTripReportGenerator: full rewrite — 4-hour conditions window, Honokohau candidate-heading route projection with TWA scoring and current-component calc, boat-specific sail plan from inventory, hazard watchlist, similar-trip comparison via past GPX tracks - PreTripReportViewModel: inject BoatProfileRepository, fix GPS to LocationService.bestPosition (Honokohau fallback), pass full forecastItems list and pastTracks to generator - PreTripReportFragment: boat selector ChipGroup, auto-generate on open, render all sections (conditions table, route, sail plan, watchlist, similar trips) - fragment_pretrip_report.xml: redesign with all report cards - item_condition_column.xml: new layout for conditions-window columns - NavApplication: instantiate BoatProfileRepository as app singleton https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Add unit settings, wind particles toggle, and recenter-to-topClaude
- New UnitPrefs: persisted C/F, ft/m, hPa/inHg, kt/mph/kph — defaults to °F - InstrumentHandler now accepts raw values (knots, metres, hPa, °C) and formats via UnitPrefs on every update - LayerPickerSheet expanded with wind particles toggle and unit chip selectors; wrapped in ScrollView to handle the additional height - MapLayerManager tracks particlesEnabled (persisted); setParticlesEnabled() added - MainActivity: caches last raw values so refreshUnits() can reformat everything instantly when the user changes a unit without waiting for new sensor data - Recenter button moved to top (below HUD strip) so it's never obscured by the bottom sheet or bottom nav - Unit label TextViews given IDs in HUD and instrument sheet for live updates https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX