summaryrefslogtreecommitdiff
path: root/android-app/app/src
AgeCommit message (Collapse)Author
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-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
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-10Improve particle and wind overlay visibilityClaude
- Particles: vivid blue (30, 100, 255) instead of white — visible on light charts background; thicker stroke 3.5px vs 2.5px - Wind raster overlay: opacity 0.85 vs 0.60 https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Fix particle disappearance at antimeridian-crossing viewports; use whiteClaude
When the viewport crosses ±180° longitude (e.g. Pacific Ocean view), minOf/maxOf on raw longitudes produces lonWest/lonEast that are backwards. Every particle then satisfies the out-of-bounds check and is respawned on every frame → continue → never drawn. Fix: compute lonSpan from screen-ordered corners (left edge / right edge) with antimeridian wrap: lonSpan = lonEast >= lonWest ? span : span + 360. Bounds check uses normalized particle longitude relative to lonWest mod 360. Particle movement wraps longitude into [-180, 180] to stay consistent. Also change particle color to white so it contrasts against the blue wind raster overlay instead of blending into it. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-10Default map to charts; fix synchronized particle flash on pan/zoomClaude
- MapLayerManager: default base preset changed from SATELLITE to CHARTS - ParticleWindView: respawned particles now get a random age (0..MAX_AGE) instead of always 0, preventing mass synchronized respawns after pan/zoom https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-09Fix startup crash: rename wind source ID to avoid collisionClaude
MapLayerManager registers SOURCE_WIND = "wind-source" as a RasterSource in the style builder. MapHandler was using the same ID for its GeoJsonSource, causing MapLibre to throw on duplicate source IDs at style-load time. Rename MapHandler's source to "wind-arrows-source". https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-09Fix nullable LatLng? crash in MainActivity camera idle listenerClaude
Same MapLibre 13.0.1 nullable corner fix — use listOfNotNull() and guard on size == 4 before calling loadWindGrid. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-09Fix nullable LatLng? crash in ParticleWindViewClaude
MapLibre 13.0.1 types VisibleRegion corners as LatLng? (nullable). Use listOfNotNull() in both onDraw() and scatter() to guard against null corners — mirrors the same fix already applied to MainActivity. https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-09fix(build): replace LatLngBounds properties with VisibleRegion cornersClaude
LatLngBounds.latSouth/latNorth/lonWest/lonEast don't exist in MapLibre 13.0.1. Derive bounds from VisibleRegion corner LatLng points (.nearLeft/.nearRight/.farLeft/.farRight) which are stable across SDK versions. Fixes CI compilation failure in MainActivity and ParticleWindView. 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-08feat(wind): Level 1 — 4×5 viewport grid of wind arrowsClaude
- WeatherApiService: batch endpoint getWeatherForecastBatch with comma-separated lat/lon → List<WeatherResponse> - WeatherRepository.fetchWindGrid: chunks 20 points into two calls of 10, maps each response to a WindArrow at its returned lat/lon - MainViewModel.loadWindGrid(bounds): builds a 4×5 grid from visible map bounds, calls fetchWindGrid, emits to windGrid StateFlow - MapHandler.setupWindGridLayer: GeoJSON source + SymbolLayer reusing the wind-arrow icon; MapHandler.updateWindGridLayer: pushes feature collection - MainActivity: stores mapLibreMapRef; calls setupWindGridLayer after style loads; addOnCameraIdleListener fires loadWindGrid on every pan/zoom; observes windGrid → updateWindGridLayer https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
2026-04-08feat(wind): Level 0 — single wind arrow at GPS positionClaude
- MapHandler.setupWindLayer: registers ic_wind_arrow bitmap, adds GeoJSON source + SymbolLayer with rotation/size driven by direction/speed_kt props - MapHandler.updateWindLayer(arrow): pushes updated feature to the source - MainActivity: calls setupWindLayer after style load; fires loadWeather once on first GPS fix (weatherLoaded flag); observes windArrow StateFlow to drive updateWindLayer 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(nav): replace Map+Instruments with Map+Layers in bottom navPeter Stone
Layers acts as an action button — shows LayerPickerSheet and snaps back to Map so it never stays selected. Instruments tab removed; sheet expand/collapse via swipe as before. 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(map): switch wind layer to OpenWeatherMap wind_new tilesPeter Stone
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(map): add Windy Map Forecast API key to wind tile URLPeter Stone
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(tracks): persist tracks as GPX in Documents/Nav/ — survives uninstallPeter Stone
GpxSerializer/GpxParser: full round-trip of all TrackPoint fields via GPX 1.1 + nav: extensions namespace. 13 unit tests. TrackStorage: MediaStore on API 29+ (no permission needed), direct file I/O on API 24-28 (WRITE_EXTERNAL_STORAGE maxSdkVersion=28). TrackRepository: stopTrack() is now suspend, writes GPX and returns TrackSummary (distance nm, duration, max/avg SOG, avg wind, avg wave). getPastTracks() lazy-loads from Documents/Nav/ on first call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(ui): wave height scales view, period drives speed, whitecaps gated on windPeter Stone
WaveView: animation speed = 8/period so long swell animates slowly; amplitude ceiling raised to 42% of view height; whitecaps only when windSpeedKt >= 12 (Beaufort 4). InstrumentHandler.updateWaveState: sizes view height from swell height (1ft→56dp, 8ft→160dp) and forwards windSpeedKt to WaveView. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(ui): dark theme — match instrument sheet to WaveView sky palettePeter Stone
Surface/background → #1C1B1F (WaveView sky), text tokens updated to light M3 dark-mode values, status bar icons set to light. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06feat(ui): wire redesigned instrument sheet — InstrumentHandler rewrite + ↵Peter Stone
MainActivity InstrumentHandler: direction arrows (SKY/OCEAN palettes), WaveView state, metres→feet conversion, bearing formatting, all helpers top-level for TDD. MainActivity: setupHandlers wires all new view refs; observeDataSources passes cogBearingDeg, twsBearingDeg, raw metres to handler; depth collector wired from nmeaDepthDataFlow. 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-06feat(ui): add DirectionArrowView and WaveView custom viewsPeter Stone
DirectionArrowView: rotating notched-chevron compass indicator in SKY (grey) and OCEAN (blue) palettes, with bearing normalization. WaveView: animated swell + wind-chop canvas divider — sky/sea gradient fills, shimmer line, whitecap highlights; self-animates via postInvalidateOnAnimation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05feat(ui): update instrument sheet typography — weight 300, unit labels, ↵Peter Stone
forecast styles
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-04fix(smoke): resolve MapView inflation crash and wire anchor config navigationPeter Stone
2026-04-04refactor: unify core models and finish org.terst.nav migrationPeter Stone
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-04feat(map): satellite view, windy/chart overlays, and rich track recordingPeter Stone
- Switch default map view to Satellite - Add Windy (partial alpha) and OpenSeaMap overlays - Add custom user position icon (ship arrow) with heading rotation - Update TrackPoint to support rich instrument/weather metadata - Change track visualization to a dotted red line - Robustify NavApplication.isTesting with Espresso detection Co-Authored-By: Gemini CLI <gemini-cli@google.com>
2026-04-04test(smoke): ensure isTesting flag is set before Activity launchPeter Stone
- Use BeforeClass to set isTesting in NavApplication - This ensures MapLibre is bypassed correctly even when ActivityScenarioRule starts before @Before. Co-Authored-By: Gemini CLI <gemini-cli@google.com>
2026-04-04fix(ui): resolve MainActivity crash in smoke tests by reordering ↵Peter Stone
initialization and guarding MapLibre - Ensure lateinit UI properties are assigned before setupMap() and setupHandlers() - Skip MapLibre initialization and lifecycle calls when NavApplication.isTesting is true to avoid emulator Vulkan crashes - Guard MapView lifecycle calls in onResume, onStart, etc. 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>