| Age | Commit message (Collapse) | Author |
|
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
|
|
colorBackground is not a Material theme attribute; replace with
colorSurface which is the correct equivalent.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
- 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
|
|
- 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
|
|
- 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
|
|
- 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
|
|
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
|
|
- 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
|
|
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
|
|
Same MapLibre 13.0.1 nullable corner fix — use listOfNotNull() and
guard on size == 4 before calling loadWindGrid.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
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
|
|
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
|
|
Document that default branch is always main, CI triggers on main,
and master must never be used. Prevents recurrence of the
master/main confusion that broke Firebase distribution.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
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
|
|
|
|
Repo default branch is master; workflow was targeting main so CI
never ran and Firebase distribution never fired.
https://claude.ai/code/session_01HXPjBsogsJVRwCiekDGkJX
|
|
simulation
|
|
- 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
|
|
|
|
- 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
|
|
|
|
- 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
|
|
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>
|
|
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>
|
|
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>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
|
|
forecast styles
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 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>
|
|
- 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>
|
|
- 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>
|
|
- 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>
|
|
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>
|
|
6 stories covering findings from codebase audit:
- ct-remove-mock-tidal: remove random fake tidal currents near Solent
- ct-wire-tidal-to-map: wire tidalCurrentState to MapHandler (never called)
- ct-wire-anchor-to-map: wire anchorWatchState to map overlay (text-only)
- ct-show-wind-direction: display TWD fetched but not shown in sheet
- ct-show-swell-direction: display swell dir fetched but not shown
- ct-fix-weather-fallback: remove silent SF fallback in WeatherActivity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|