summaryrefslogtreecommitdiff
path: root/android-app/app/src/main/res/layout
AgeCommit message (Collapse)Author
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
2026-04-10Area conditions HUD redesign: map-center conditions refresh + boat HUD stripClaude
- Persistent top-of-map HUD strip (SOG/COG/BSP/Depth) replaces instrument grid in bottom sheet - Bottom sheet now shows area conditions only (Wind/Temp/Baro + wave forecast) — always visible - loadConditions() fires on every camera idle event so panning the map refreshes conditions - Crosshair appears at map center while panning; hides when following GPS - Added tempC field to MarineConditions (already fetched from Open-Meteo hourly) - InstrumentHandler slimmed to area conditions only; updateDisplay() removed - LocationService pipes nmeaBoatSpeedData from NmeaStreamManager to companion flow https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-09merge: reconcile master particle-wind work with origin/main redesignClaude
Merged divergent branches (common ancestor a9d87b6). Took origin/main as base (layer manager, recenter, quit button, GPX tracks, marine conditions, dark theme, user position layer, active/past track layers) and layered in particle wind simulation work: - MapHandler: added setupWindLayer, updateWindLayer, updateWindGridLayer; kept their user-pos layer, follow/recenter state, active+past tracks - WeatherRepository: kept their fetchCurrentConditions, added fetchWindGrid - MainViewModel: kept their track/marine/summary changes, added windGrid StateFlow, loadWindGrid, buildGrid - MainActivity: kept their full UI (layer picker, quit, recenter, fade animations), added particleWindView wiring, weatherLoaded guard, windArrow/windGrid observers - activity_main.xml: took their LinearLayout redesign, added ParticleWindView overlay inside ConstraintLayout https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-08feat(wind): Level 2 — canvas particle simulation (uniform field)Claude
- ParticleWindView: transparent View overlay on the map; tracks 300 particles as three FloatArrays (lat, lon, age) — no per-frame allocation; projects lat/lon → screen via MapLibreMap.projection each frame; draws a 14px tail segment in the wind travel direction with alpha fading by age; respawns out-of-bounds/aged particles randomly within visible bounds; speed scaled to viewport so animation is consistent at any zoom level; animates via postInvalidateOnAnimation() - activity_main.xml: ParticleWindView added above MapView, match_parent, non-interactive (clickable/focusable=false) - MainActivity: finds particle_wind_view; calls attachMap after getMapAsync; feeds directionDeg/speedKt from windArrow StateFlow https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-07fix(track): fix silent GPX save failure + add stop friction + quit buttonPeter Stone
TrackStorage: openOutputStream null returned true (file never written). Added IS_PENDING flag to fix Android 10-11 race where insert succeeds but file isn't physically created yet. Added storage-mounted guard. TrackRepository now logs save failures. Stop tracking now requires a long press (haptic feedback) — prevents accidental mid-sail stops from a single tap. Quit button (top-right, tonal X) stops LocationService and calls finishAffinity(). Prompts if a track is in progress. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(map): layer manager — satellite/charts/hybrid + wind toggle, ↵Peter Stone
long-press picker MapLayerManager: all raster sources registered at style-build time, visibility toggled on demand. Persists base preset and wind state to SharedPreferences. Sources: Google satellite, NOAA RNC charts (tileservice.charts.noaa.gov), OWM wind, OpenSeaMap seamarks. LayerPickerSheet: bottom sheet with chip group (Satellite/Charts/Hybrid) and wind toggle, launched from map long-press. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(tracks): show summary sheet on track stop; 2-min minimumPeter Stone
TrackSummarySheet: bottom sheet showing distance (nm), duration, max/avg speed, avg wind and waves (when available, waves in ft). Only shown for tracks ≥ 2 minutes — shorter tracks are discarded silently. MainViewModel: exposes trackSummary SharedFlow (replay=0) and trackStartMs. MainActivity: observes flow, shows sheet after stopTrack completes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(ui): restructure instrument sheet layout — inline arrows, WaveView, ↵Peter Stone
ocean forecast section Full layout rewrite: 3×2 GridLayout instrument grid with inline DirectionArrowView for AWS/TWS/HDG/COG, depth+baro row, animated WaveView divider, and ocean-blue forecast section for Current/Waves/Swell. Stubs valueCurrDir/valueWaveDir as nullable in InstrumentHandler to compile; full handler rewrite follows in Task 6. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05feat(ui): remove report section from instrument sheet, fix touch-throughPeter Stone
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04feat(ui): surface trip planning and reports in instrument sheetPeter Stone
2026-04-04refactor(ui): stabilize layout by moving BottomNav outside CoordinatorLayoutPeter Stone
2026-04-04feat(tripreport): add pre-trip planning and past track visualizationPeter Stone
- Fix compilation errors (missing imports for PropertyFactory and MaterialButton) - Implement Pre-Trip Report with weather summary, boat profile, and sail suggestions - Differentiate between active track (solid red) and past tracks (dotted red) on map - Add navigation to Pre-Trip Report from Safety Dashboard - Robustify track storage to preserve multiple tracks in session Co-Authored-By: Gemini CLI <gemini-cli@google.com>
2026-04-04feat(tripreport): add AI trip narrative generator with multiple stylesPeter Stone
- Consolidate track data, weather, and log entries into a TripSummary - Implement TripReportGenerator with Professional, Adventurous, Journal, and Pirate styles - Add TripReportFragment and ViewModel for UI interaction - Share TrackRepository and LogbookRepository via NavApplication singleton - Fix compilation error in MainViewModel rich metadata recording Co-Authored-By: Gemini CLI <gemini-cli@google.com>
2026-04-03feat(instruments): add forecast wind, wave, swell and current from Open-MeteoPeter Stone
- Add swell params to MarineApiService request - Add swell fields to MarineHourly model - Add MarineConditions snapshot model - Add WeatherRepository.fetchCurrentConditions() (first forecast hour) - Add MainViewModel.loadConditions() + marineConditions StateFlow - Add Forecast section to instrument sheet: Curr / Wave / Swell - Populate TWS from forecast wind speed on first GPS fix - Trigger loadConditions() once on first GPS position received Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03feat(instruments): replace simulation with real GPS and barometer dataPeter Stone
- Drop VMG, Polar %, and PolarDiagramView — no NMEA source on boat - Shrink grid to 3×2 (AWS/HDG/BSP / TWS/COG/SOG) - Move Depth + Baro to expanded section side by side - Initialize all instruments to "—" on startup - Wire LocationService.locationFlow → SOG + COG display (real GPS) - Wire LocationService.barometerStatus → Baro display (device sensor) - Delete startInstrumentSimulation() fake loop entirely Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02feat(map): interactive map with auto-follow, recenter button, and UI ↵Peter Stone
immersive mode (#2) * docs: add map interaction design spec Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add map interaction implementation plan Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(map): add isFollowing state and gesture-driven manual mode to MapHandler * feat(ui): add fab_recenter pill button to map layout * feat(map): wire UI fade-out and recenter button to MapHandler.isFollowing * fix(map): prevent fadeIn flash on cold start; consolidate fab_mob listener * fix(map): preserve user zoom level on recenter Capture the current camera zoom when the user gestures (entering manual mode) and pass it back to centerOnLocation in recenter(), so tapping Recenter returns to the user's chosen zoom rather than always snapping to the default 14. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(map): capture lastZoom on camera idle, not gesture start OnCameraMoveStartedListener fires before the gesture completes, so it captured the pre-gesture zoom. OnCameraIdleListener fires after the camera settles, giving the user's final intended zoom level. Only update lastZoom while in manual mode (isFollowing=false). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(map): guard recenter against null island and add KDoc - Skip recenter() if no GPS fix received (lastLat/lastLon still 0.0) to avoid animating to 0°N, 0°E - Add KDoc comment to recenter() consistent with other public methods Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03fix(ui): raise FAB elevation above CardView sheet to fix z-orderPeter Stone
The instrument sheet CardView has cardElevation=16dp which was rendering on top of the FABs (default ~6dp elevation). Set app:elevation=20dp on both FABs so they always appear above the sheet. Also reverts oversized marginBottom back to standard 16dp all-round now that elevation stacking is correct. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03fix(ui): raise both FABs fully above instrument sheet top edgePeter Stone
anchorGravity=top centers the FAB on the sheet edge, leaving half the button occluded. Increase marginBottom to 44dp (28dp to clear the FAB radius + 16dp gap) so both buttons sit fully above the sheet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02fix(ui): anchor both FABs to instrument sheet (squash merge recovery)Peter Stone
Both fab_mob and fab_record_track now anchor to instrument_bottom_sheet so they sit above the sheet peek zone rather than being occluded by the sheet's 16dp elevation. Resolves stash conflict in settings.local.json. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02fix(ui): make record track FAB visible (#1)Peter Stone
* Add GpsPosition data class and NMEA RMC parser with tests - GpsPosition: latitude, longitude, sog (knots), cog (degrees true), timestampMs - NmeaParser.parseRmc: handles GP/GN talker IDs, void status, malformed input - SOG/COG default to 0.0 when fields absent; S/W coords are negative - 13 unit tests: GpsPositionTest (2), NmeaParserTest (11) — all GREEN Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add harmonic tide height predictions (Section 3.2 / 4.2) Implement offline harmonic tide prediction as specified in COMPONENT_DESIGN.md: - TideConstituent: name, speedDegPerHour, amplitudeMeters, phaseDeg - TidePrediction: timestampMs, heightMeters - TideStation: id, name, lat, lon, datumOffsetMeters, constituents - HarmonicTideCalculator: predictHeight(), predictRange(), findHighLow() Formula: h(t) = Z0 + Σ [ Hi × cos( ωi × (t − t0) − φi ) ] - 15 unit tests covering all calculation paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: implement isochrone-based weather routing (Section 3.4) * feat: implement PDF logbook export (Section 4.8) - LogbookEntry data class: timestampMs, lat/lon, SOG, COG, wind, baro, depth, event/notes - LogbookFormatter: UTC time, position (deg/dec-min), 16-pt compass, row/page builders - LogbookPdfExporter: landscape A4 PDF via android.graphics.pdf.PdfDocument with column headers, alternating row shading, and table border - 20 unit tests covering all formatting helpers and data model behaviour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: offline GRIB staleness checker, ViewModel integration, and UI badge - Add GribRegion, GribFile data models and GribFileManager interface - Add InMemoryGribFileManager for testing and default use - Add GribStalenessChecker with FreshnessResult sealed class (Fresh/Stale/NoData) - Integrate weatherStaleness StateFlow into MainViewModel (checked after loadWeather) - Add yellow staleness banner TextView to fragment_map.xml - Wire staleness banner in MapFragment (shown on Stale, hidden on Fresh/NoData) - Add GribStalenessCheckerTest (4 TDD tests) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: satellite GRIB download with bandwidth optimisation (§9.1) Implements weather data download over Iridium satellite links: - GribParameter enum with SATELLITE_MINIMAL set (wind + pressure only) - SatelliteDownloadRequest data class (region, params, forecast hours, resolution) - SatelliteGribDownloader: size/time estimation, abort-on-oversized, pluggable fetcher - 8 unit tests covering estimation scaling, minimal param set, and download outcomes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add AnchorWatchHandler UI with Depth/Rode Out inputs and suggested radius - Add AnchorWatchState with calculateRecommendedWatchCircleRadius, which uses ScopeCalculator.watchCircleRadius (Pythagorean scope formula) and falls back to rode length when geometry is invalid - Add AnchorWatchHandler Fragment with EditText inputs for Depth (m) and Rode Out (m); updates suggested watch circle radius live via TextWatcher - Add fragment_anchor_watch.xml layout - Wire AnchorWatchHandler into bottom navigation (MainActivity + menu) - Add AnchorWatchStateTest covering valid geometry, short-rode fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(safety): log wind and current conditions at MOB activation (Section 4.6) Per COMPONENT_DESIGN.md Section 4.6, the MOB navigation view must display wind and current conditions at the time of the event. - MobEvent: add nullable windSpeedKt, windDirectionDeg, currentSpeedKt, currentDirectionDeg fields captured at the exact moment of activation - MobAlarmManager.activate(): accept optional wind/current params and forward them into MobEvent (defaults to null for backward compatibility) - LocationService (new): aggregates live SensorData (resolves true wind via TrueWindCalculator) and marine-forecast current conditions; snapshot() provides a point-in-time EnvironmentalSnapshot for safety-critical logging - MobAlarmManagerTest: add tests for wind/current storage and null defaults - LocationServiceTest (new): covers snapshot, true-wind resolution, current-condition updates, and the latestSensor flow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(gps): implement NMEA/Android GPS sensor fusion in LocationService Adds priority-based selection between NMEA GPS (dedicated marine GPS, higher priority) and Android system GPS (fallback) within LocationService. Selection policy: 1. Prefer NMEA when its most recent fix is fresh (≤ nmeaStalenessThresholdMs, default 5 s) 2. Fall back to Android GPS when NMEA is stale 3. Use stale NMEA only when Android has never reported a fix 4. bestPosition is null until at least one source reports New public API: - GpsSource enum (NONE, NMEA, ANDROID) - LocationService.updateNmeaGps(GpsPosition) - LocationService.updateAndroidGps(GpsPosition) - LocationService.bestPosition: StateFlow<GpsPosition?> - LocationService.activeGpsSource: StateFlow<GpsSource> - Injectable clockMs parameter for deterministic unit tests Adds 7 unit tests covering: no-data state, fresh NMEA priority, stale NMEA fallback, only-NMEA/only-Android scenarios, exact-threshold edge case, and NMEA recovery after Android takeover. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(gps): add fix-quality (accuracy) tier to GPS sensor fusion Extend LocationService's source-selection policy with a quality-aware "marginal staleness" zone between the primary and a new extended staleness threshold (default 10 s): 1. Fresh NMEA (≤ primary threshold, 5 s) → always prefer NMEA 2. Marginally stale NMEA (5–10 s) → prefer NMEA only when GpsPosition.accuracyMeters is strictly better than Android's; fall back to Android conservatively when accuracy data is absent 3. Very stale NMEA (> 10 s) → always prefer Android 4. Only one source available → use it regardless of age Changes: - GpsPosition: add nullable accuracyMeters field (default null, no breaking change to existing callers) - LocationService: add nmeaExtendedThresholdMs constructor parameter; recomputeBestPosition() now implements three-tier logic; extract GpsPosition.hasStrictlyBetterAccuracyThan() helper - LocationServiceTest: expose nmeaExtendedThresholdMs in fusionService helper; add posWithAccuracy helper; add 4 new test cases covering accuracy-based NMEA preference, worse-accuracy fallback, no-accuracy conservative fallback, and very-stale unconditional fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add .gitignore, pull-crash-logs script, updated agent permissions - .gitignore: exclude agent artifacts (.claudomator-env, .agent-home/, crash-logs/) - scripts/pull-crash-logs: download Crashlytics crash reports via Firebase CLI - .claude/settings.local.json: add Android SDK/emulator/adb permission rules Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update CI workflow to target main branch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: resolve all Kotlin compilation errors blocking CI build - Migrate kapt → KSP (Kotlin 2.0 + kapt is broken; KSP is the supported path) - Fix duplicate onResume() override in MainActivity - Fix wrong package imports: com.example.androidapp.data.model → org.terst.nav.data.model across GribFileManager, GribStalenessChecker, SatelliteGribDownloader, LogbookFormatter, LogbookPdfExporter, IsochroneRouter, AnchorWatchHandler - Create missing SensorData, ApparentWind, TrueWindData, TrueWindCalculator classes - Inline missing ScopeCalculator formula (Pythagorean) in AnchorWatchState Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(track): implement GPS track recording with map overlay - TrackRepository + TrackPoint wired into MainViewModel: isRecording/trackPoints StateFlows, startTrack/stopTrack/addGpsPoint - MapHandler.updateTrackLayer(): lazily initialises a red LineLayer and updates GeoJSON polyline from List<TrackPoint> - fab_record_track FAB in activity_main.xml (top|end of bottom nav); icon toggles between ic_track_record and ic_close while recording - MainActivity feeds every GPS fix into viewModel.addGpsPoint() and observes trackPoints to redraw the polyline in real time - ic_track_record.xml vector drawable (red record dot) - 8 TrackRepositoryTest tests all GREEN Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(ci): share APKs between jobs and expand smoke tests CI — build job now uploads both APKs as the 'test-apks' artifact. smoke-test job downloads them and passes -x assembleDebug -x assembleDebugAndroidTest to skip recompilation (~4 min saved). Test results uploaded as 'smoke-test-results' artifact on every run. Smoke tests expanded from 1 → 11 tests covering: - MainActivity launches without crash - All 4 bottom-nav tabs are displayed - Safety tab: Safety Dashboard, ACTIVATE MOB, ANCHOR WATCH visible - Log tab: voice-log mic FAB visible - Instruments tab: bottom sheet displayed - Map tab: returns from overlay, mapView visible - MOB FAB: always visible, visible on Safety tab - Record Track FAB: displayed, toggles to Stop Recording, toggles back MainActivity: moved isRecording observer to initializeUI() so the FAB content description updates without requiring GPS permission (needed for emulator tests that run without location permission). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: address simplify review findings TrackRepository.addPoint() now returns Boolean (true if point was added). MainViewModel.addGpsPoint() only updates _trackPoints StateFlow when a point is actually appended — eliminates ~3,600 no-op flow emissions per hour when not recording. MainActivity: loadedStyle promoted from nullable field to MutableStateFlow<Style?>; trackPoints observer uses filterNotNull + combine so no track points are silently dropped if the style loads after the first GPS fix. Smoke tests: replaced 11× ActivityScenario.launch().use{} with a single @get:Rule ActivityScenarioRule — same isolation, less boilerplate. CI: removed redundant app-debug artifact upload (app-debug.apk is already included inside the test-apks artifact). Removed stale/placeholder comments from MainActivity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ui): anchor record track FAB to instrument sheet to prevent it being hidden The FAB was anchored to bottom_navigation, placing it in the peek zone of the instrument bottom sheet (120dp) and making it invisible to users. Re-anchoring to instrument_bottom_sheet keeps the button visible and makes it track naturally with sheet drag gestures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ui): anchor MOB FAB to instrument sheet to match record-track FAB The fab_mob was still anchored to bottom_navigation using the same top|start pattern that caused fab_record_track to be hidden behind the instrument sheet's 16dp elevation. Apply the same fix so the safety-critical MOB button is not occluded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claudomator Agent <agent@claudomator> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Agent <agent@example.com> Co-authored-by: Claude Agent <agent@claude.ai>
2026-03-25feat(track): implement GPS track recording with map overlayPeter Stone
- TrackRepository + TrackPoint wired into MainViewModel: isRecording/trackPoints StateFlows, startTrack/stopTrack/addGpsPoint - MapHandler.updateTrackLayer(): lazily initialises a red LineLayer and updates GeoJSON polyline from List<TrackPoint> - fab_record_track FAB in activity_main.xml (top|end of bottom nav); icon toggles between ic_track_record and ic_close while recording - MainActivity feeds every GPS fix into viewModel.addGpsPoint() and observes trackPoints to redraw the polyline in real time - ic_track_record.xml vector drawable (red record dot) - 8 TrackRepositoryTest tests all GREEN Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25feat: add AnchorWatchHandler UI with Depth/Rode Out inputs and suggested radiusAgent
- Add AnchorWatchState with calculateRecommendedWatchCircleRadius, which uses ScopeCalculator.watchCircleRadius (Pythagorean scope formula) and falls back to rode length when geometry is invalid - Add AnchorWatchHandler Fragment with EditText inputs for Depth (m) and Rode Out (m); updates suggested watch circle radius live via TextWatcher - Add fragment_anchor_watch.xml layout - Wire AnchorWatchHandler into bottom navigation (MainActivity + menu) - Add AnchorWatchStateTest covering valid geometry, short-rode fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25feat: offline GRIB staleness checker, ViewModel integration, and UI badgeClaudomator Agent
- Add GribRegion, GribFile data models and GribFileManager interface - Add InMemoryGribFileManager for testing and default use - Add GribStalenessChecker with FreshnessResult sealed class (Fresh/Stale/NoData) - Integrate weatherStaleness StateFlow into MainViewModel (checked after loadWeather) - Add yellow staleness banner TextView to fragment_map.xml - Wire staleness banner in MapFragment (shown on Stale, hidden on Fresh/NoData) - Add GribStalenessCheckerTest (4 TDD tests) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25fix: add missing layout_width/height to instruments sheet include tagPeter Stone
Caused a fatal InflateException crash on app launch. Android requires layout_width and layout_height on <include> tags explicitly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23fix: resolve Kotlin compilation errors from UI refactorPeter Stone
- Make InstrumentHandler.labelTrend and barometerTrendView nullable - Remove anchorWatchHandler init block referencing non-existent view IDs - Fix state.radiusM -> state.watchCircleRadiusMeters - Add bottom_nav_weather_menu.xml with nav_forecast; point WeatherActivity at it Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23feat: refactor UI to BottomNavigationView with Safety and Doc fragmentsPeter Stone
Replace FAB-based navigation with a 4-tab BottomNavigationView (Map, Instruments, Log, Safety). Instruments use a collapsible bottom sheet; Log and Safety display as full-screen overlay fragments. - Add SafetyFragment with MOB and Anchor Watch controls - Add DocFragment for in-app markdown help (Markwon: core, tables, images) - Add layout_instruments_sheet with 3x3 instrument grid and PolarDiagramView - Add fragment_safety and fragment_doc layouts - Add vector drawables: ic_map, ic_instruments, ic_log, ic_safety, ic_close - Update activity_main.xml to CoordinatorLayout with bottom sheet + overlay - Fix: set isHideable=true before STATE_HIDDEN to avoid silent no-op from behavior_hideable=false default; restore false on Map/Instruments tabs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15merge: integrate weather/forecast feature from local remotePeter Stone
Merges wind/current overlay and weather forecast implementation: - Weather feature: WeatherRepository, MainViewModel, MapFragment, ForecastFragment, ForecastAdapter - Data models: WindArrow, ForecastItem, WeatherResponse, MarineResponse - API services: WeatherApiService, MarineApiService (Open-Meteo, no key required) - Layouts: activity_weather.xml, fragment_map.xml, fragment_forecast.xml, item_forecast.xml - Resources: merged colors (wind_slow/medium/strong), strings, themes (Theme.NavApp added) - Manifest: added ACCESS_COARSE_LOCATION - build.gradle: merged deps — kept Firebase+MapLibre 11.5.1, added kotlin-kapt, retrofit, moshi, turbine - Fix: re-packaged com.example.androidapp → org.terst.nav; weather MainActivity uses ActivityWeatherBinding Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15feat: add voice log UI with FAB, fragment container, and logbook domain modelsPeter Stone
- Add VoiceLogFragment, VoiceLogViewModel, VoiceLogState, LogEntry, InMemoryLogbookRepository - Wire voice log FAB in MainActivity to show/hide fragment container - Add RECORD_AUDIO permission to manifest - Add native CMakeLists.txt and native-lib.cpp stubs - Fix missing BufferOverflow import in LocationService Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14fix: correct ConstraintLayout attribute typo in activity_main.xmlPeter Stone
layout_bottom_toTopOf → layout_constraintBottom_toTopOf on fab_tidal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14Implement barometric pressure trend monitoring and visualizationClaudomator Agent
2026-03-14Implement tidal current overlay on the chart with toggle FABClaudomator Agent
2026-03-13fix: resolve MapLibre 11.x migration issues and layout/resource errorsPeter Stone
2026-03-13fix: resolve XML syntax and resource formatting errorsPeter Stone
2026-03-13refactor: update package name to org.terst.nav and setup CI/CD with Firebase ↵Peter Stone
App Distribution
2026-03-13Implement polar performance diagram visualizationClaudomator Agent
2026-03-13feat: Implement MOB (Man Overboard) alarm functionalityClaudomator Agent
This commit introduces the core functionality for the Man Overboard (MOB) alarm. Key changes include: - Added a persistent, high-contrast red MOB Floating Action Button to the UI. - Implemented dynamic location permission requests and initialization of LocationService. - Created a MobWaypoint data class to store MOB location and timestamp. - Developed the activateMob() function to: - Capture current GPS coordinates. - Set the active MOB waypoint and mark MOB as activated. - Switch to a dedicated MOB navigation view, hiding other UI elements. - Start a continuous, looping audible alarm (assumes R.raw.mob_alarm exists). - Log the MOB event to the console (placeholder for future logbook integration). - Implemented a MOB navigation view (ConstraintLayout) with real-time distance to MOB and elapsed time display. - Added a recoverMob() function, triggered by a 'Recovered' button, to: - Deactivate MOB mode. - Stop and release the audible alarm. - Restore the main UI visibility. - Location updates are observed to continuously update the MOB navigation display. - Ensured MediaPlayer resources are properly released on activity destruction. Future enhancements (not part of this commit) include: - Implementing a bearing arrow in the MOB navigation view. - Integrating with a persistent logbook system.
2026-03-13feat: add wind/current map overlay and weather forecast on startupClaudomator Agent
Implements the wind/current map overlay and 7-day weather forecast display that loads on application launch: Data layer: - Open-Meteo API (free, no key): WeatherApiService + MarineApiService - Moshi-annotated response models (WeatherResponse, MarineResponse) - WeatherRepository: parallel async fetch, Result<T> error propagation - Domain models: WindArrow (with beaufortScale/isCalm) + ForecastItem (with weatherDescription/isRainy via WMO weather codes) Presentation layer: - MainViewModel: StateFlow<UiState> (Loading/Success/Error), windArrow and forecast streams - MainActivity: runtime location permission, FusedLocationProvider GPS fetch on startup, falls back to SF Bay default - MapFragment: MapLibre GL map with wind-arrow SymbolLayer; icon rotated by wind direction, size scaled by speed in knots - ForecastFragment + ForecastAdapter: RecyclerView ListAdapter showing 7-day hourly forecast (time, description, wind, temp, precip) Resources: - ic_wind_arrow.xml vector drawable (north-pointing, rotated by MapLibre) - BottomNavigationView: Map / Forecast tabs - ViewBinding enabled throughout Tests (TDD — written before implementation): - WindArrowTest: calm detection, direction normalisation, Beaufort scale - ForecastItemTest: weatherDescription, isRainy for WMO codes - WeatherApiServiceTest: MockWebServer request params + response parsing - WeatherRepositoryTest: MockK service mocks, data mapping, error paths - MainViewModelTest: Turbine StateFlow assertions for all state transitions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13Implement basic instrument displayClaudomator Agent
2026-03-13Implement GPS navigation with position, SOG, and COGClaudomator Agent