Commit Graph
100 Commits
Author SHA1 Message Date
Davide Ferrari 7f6218e5c0 feat(assets): add Model Y Juniper Performance and Premium support (#15)
- Add 6 Performance images with 21" Überturbine wheels
- Add 15 Standard/Premium images with 18"/19"/20" wheels
- Support 6 colors for Premium: PPSW, PN01, PX02, PN00, PR01, PPSB
- Detect Performance via trim_badging (P74D) or 21" wheels
- Detect Premium via 19" Crossflow or 20" Helix wheels

Fixes #1
2026-01-05 19:08:30 +01:00
Davide FerrariandClaude Opus 4.5 a44f808861 feat(charges): add tappable cost card to edit in Teslamate (#14)
* feat(charges): add tappable cost card to edit in Teslamate

- Add Teslamate Base URL setting in Settings (above Display Settings)
- Make "Connect to TeslamateApi" header smaller (titleMedium)
- Cost card in Charges list shows external link icon when cost is 0
- Tapping opens browser to Teslamate charge-cost endpoint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(charges): show edit icon on all costs, not just zero

* docs: update CHANGELOG with charge cost edit feature

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 18:17:07 +01:00
Davide FerrariandClaude Opus 4.5 f2654f1b97 feat: Stats for Nerds - comprehensive car statistics (#13)
* docs: add Stats for Nerds implementation plan

Comprehensive plan for v0.8.0 feature that adds advanced statistics
computed from local SQLite database:

Architecture:
- Two-tier data strategy: Quick Stats (from list APIs) vs Deep Stats
  (from detail APIs, background synced)
- Room database with 5 tables (~10MB for heavy users)
- WorkManager for background sync on app launch
- Incremental sync with schema versioning for future-proofing

Stats categories:
- 🚗 Driving Records (distance, speed, elevation, efficiency)
- ⚡ Charging Records (energy, cost, power, AC/DC ratio)
- 🌡️ Temperature Records (hot/cold extremes)
- 📅 Activity Stats (busiest day, averages)
- 🔋 Energy Stats (consumption metrics)

7 implementation phases defined with detailed tasks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add Room database foundation for Stats for Nerds

Phase 1 of Stats for Nerds feature - Database Foundation:

Dependencies:
- Add Room 2.6.1 for local SQLite database
- Add WorkManager 2.9.1 for background sync
- Add Hilt WorkManager integration

Entities:
- SyncState: Tracks sync progress per car with schema versioning
- DriveSummary: Drive list data for Quick Stats (~300 bytes/record)
- ChargeSummary: Charge list data for Quick Stats (~250 bytes/record)
- DriveDetailAggregate: Computed aggregates for Deep Stats (~150 bytes/record)
- ChargeDetailAggregate: Computed aggregates for Deep Stats (~120 bytes/record)

DAOs with stat queries:
- SyncStateDao: Sync progress tracking
- DriveSummaryDao: Quick stats (total distance, max speed, busiest day, etc.)
- ChargeSummaryDao: Quick stats (total energy, total cost, etc.)
- AggregateDao: Deep stats (elevation, temperature, AC/DC ratio, etc.)

Storage estimate: ~10 MB for heavy user (15k drives, 8k charges)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add background sync infrastructure

Phase 2 of Stats for Nerds feature - Sync Infrastructure:

Domain Models:
- SyncProgress: Tracks sync phase and progress per car
- OverallSyncStatus: Aggregates status across all cars

Sync Components:
- SyncManager: Single source of truth for sync state
  - Emits progress via StateFlow
  - Tracks summaries vs details sync separately
  - Supports schema versioning for future field additions
- SyncRepository: Orchestrates data fetching and storage
  - syncSummaries(): Fast sync from list endpoints (Quick Stats)
  - syncDriveDetails(): Slow sync for elevation/temp extremes
  - syncChargeDetails(): Slow sync for AC/DC ratio, max power
  - Computes aggregates from detail positions/points
- DataSyncWorker: WorkManager background worker
  - Runs on app launch
  - Syncs all cars in parallel
  - Network constraint required

API Model Updates:
- DrivePosition: Added climate_info for temperature tracking
- DriveClimateInfo: inside_temp, outside_temp, is_climate_on

App Initialization:
- MateDroidApp: Custom WorkManager configuration with HiltWorkerFactory
- AndroidManifest: Disabled default WorkManager initializer

The sync now runs automatically when the app starts, populating
the local database with drives/charges summaries and computing
aggregates from detail data in the background.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add stats domain models and repository

- Add CarStats domain model with QuickStats and DeepStats
- Add YearFilter for filtering stats by year
- Add record types (DriveElevationRecord, DriveTempRecord, etc.)
- Implement StatsRepository with year-filtered queries
- Support for checking sync progress and data availability

Part of Stats for Nerds feature (Phase 3)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add Stats for Nerds screen and navigation

- Create StatsViewModel with year filter support
- Create StatsScreen with Quick Stats and Deep Stats cards
- Add Trophy icon to CustomIcons
- Add Screen.Stats route to NavGraph
- Add onNavigateToStats callback to DashboardScreen

Stats cards include:
- Drives Overview (total, distance, energy, efficiency)
- Charges Overview (total, energy added, cost)
- Records (longest drive, top speed, most efficient, etc.)
- Elevation stats (highest/lowest point, most climbing)
- Temperature extremes (driving and cabin)
- Charging power (max achieved)
- AC/DC charging ratio

Part of Stats for Nerds feature (Phase 4 & 5)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(dashboard): add stats entry point from car image

- Make car image clickable to navigate to Stats screen
- Add Analytics icon overlay on top-right of car image
- Pass onNavigateToStats callback through Dashboard components
- Add Screen.Stats route navigation from Dashboard

Users can now tap the car image on the Dashboard to access
the Stats for Nerds screen.

Part of Stats for Nerds feature (Phase 6)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add Stats for Nerds feature documentation

- Add feature to CHANGELOG [Unreleased] section
- Add feature to README features list

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(stats): resolve UI bugs in Stats for Nerds screen

- Fix pull-to-refresh indicator not disappearing after refresh
- Round all kWh totals to integers (Energy Used, Energy Added, Biggest Charge)
- Make records individual clickable cards that navigate to drive/charge details
- Add arrow indicator on navigable record cards

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): improve Records section layout and content

- Move Records section to the top of Stats screen
- Show dates instead of addresses in record subtexts
- Use standard KeyboardArrowRight icon for navigable cards
- Move "Most Climbing" from Elevation card to Records section
- Add "Most Expensive" charge record (by total cost)
- Add "Priciest per kWh" charge record (by cost/kWh ratio)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): run sync worker as foreground service

The background sync was being killed by Android when the app went to
background or screen turned off. This fix:

- Adds FOREGROUND_SERVICE and FOREGROUND_SERVICE_DATA_SYNC permissions
- Adds POST_NOTIFICATIONS permission for the sync notification
- Runs DataSyncWorker as a foreground service with a notification
- Creates a low-priority notification channel for sync status

This ensures the sync continues even when the app is not in foreground.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): use expedited work for Android 12+ compatibility

Android 12+ blocks starting foreground services from background with:
"startForegroundService() not allowed due to mAllowStartForeground false"

This fix:
- Uses setExpedited() on work request for priority execution
- Adds getForegroundInfo() override for older API level compatibility
- Falls back to regular work if quota is exhausted

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add debug sync log viewer

In debug builds, tapping the sync progress card opens a dialog
showing sync logs in real-time (like adb logcat). Includes:
- SyncLogCollector singleton to capture log messages
- Updated SyncRepository and DataSyncWorker to use log collector
- Clickable SyncProgressCard in debug builds
- Monospace scrollable log dialog with timestamps

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add per-item progress logging for sync

Logs now show each drive/charge as it's synced with remaining count:
- "Drive 123 synced (45 remaining)"
- "Charge 456 synced (12 remaining)"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): improve records layout and climbing calculation

UI changes:
- Move stats icon to middle-right with > navigation arrow
- Display records in 2-column grid for better use of space
- Add temperature records (hottest/coldest drive/charge/cabin)
- Add highest point as a record
- Remove ElevationStatsCard (moved to records)
- More compact record cards for grid layout

Data changes:
- Add startElevation and endElevation to DriveDetailAggregate
- Calculate net climb as end - start altitude (not accumulated)
- Update driveWithMostClimbing query to use net elevation
- Bump SchemaVersion to 2 to trigger reprocessing
- Add database migration from v1 to v2

Note: Charges sync after all drives - this is by design.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): prevent aggregate deletion on summary refresh

Root cause: @Insert(onConflict = REPLACE) performs DELETE + INSERT,
which triggers CASCADE delete on aggregate tables, wiping all
processed deep stats data.

Fix: Use @Upsert instead of @Insert(REPLACE) for DriveSummaryDao
and ChargeSummaryDao. @Upsert does a proper UPDATE when record
exists, preserving foreign key relationships.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): add automatic retry on network errors

- Detect network errors (DNS, timeout, connection refused, etc.)
- Return Result.retry() instead of failing silently
- Add exponential backoff starting at 30 seconds
- Log attempt number for debugging
- Sync resumes from where it left off (not from zero)

The sync is now resilient to temporary network issues and will
automatically retry while preserving progress.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): use REPLACE policy to unstick waiting work

Changed ExistingWorkPolicy from KEEP to REPLACE so that opening
the app always starts a fresh sync worker, replacing any stuck
or long-waiting retry work.

The sync still resumes from where it left off because processed
aggregates are preserved in the database.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(stats): apply year filter to all records

Records now properly filter by year when a year filter is selected:
- Added range queries for fastest drive, most/least efficient drive
- Added range queries for temperature records (hottest/coldest drive/charge)
- Added range queries for elevation records (highest point, most climbing)
- Added range query for max charging power record
- StatsRepository now uses range queries in getDeepStatsForYear()
- Made totalDrivingDays nullable in QuickStats for year view

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(stats): multiple fixes for stats screen

- Fix sync progress stuck at 99%: check SyncPhase.COMPLETE to return 1.0
- Improve AC/DC detection: fallback to power-based detection (>22kW = DC)
- Group record cards by theme (drives, elevation, temps, charges)
- Each group starts on left column with proper alignment
- Add Peak Power as a tappable charge record

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): run as foreground service with persistent notification

Call setForeground() at start of doWork() to:
- Keep sync running when screen is off
- Show persistent notification during sync
- Update notification with sync progress

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(manifest): add foregroundServiceType for WorkManager service

Declare SystemForegroundService with dataSync foregroundServiceType
in manifest to allow foreground service for long-running sync.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(stats): use accumulated elevation gain for Most Climbing record

The Most Climbing record was incorrectly using net climb (endElevation - startElevation)
instead of accumulated elevation gain. This caused two problems:
1. Net climb doesn't capture drives that go up and down (e.g., +500m up, -400m down = +100m net vs +500m accumulated)
2. Many drives have null endElevation, causing them to be excluded from the query

Fixed by:
- Updated AggregateDao queries to ORDER BY elevationGain (accumulated) instead of (endElevation - startElevation)
- Updated queries to filter by elevationGain IS NOT NULL instead of requiring both start/end elevations
- Simplified StatsRepository to use elevationGain directly instead of recalculating net climb

* fix(db): add migration to fix AC/DC detection for existing data

Migration V2→V3 updates isFastCharger=1 for all charges where
maxChargerPower > 22kW, ensuring DC charges are correctly detected
even for data synced before the power-based detection was added.

* feat(settings): add Force Full Resync button

Adds a 'Force Full Resync' button in Settings under a new 'Data Management'
section. The button:
- Shows a confirmation dialog explaining what will happen
- Resets sync progress for all cars
- Triggers an immediate sync via WorkManager
- Shows a snackbar confirmation when started

This allows users to manually trigger a full re-download of all drive and
charge details if stats seem incorrect.

* fix(stats): use Teslamate's charger_phases logic for AC/DC detection

Teslamate determines AC vs DC based on charger_phases:
- DC: charger_phases is 0 or null (bypasses onboard charger)
- AC: charger_phases is 1, 2, or 3 (uses onboard charger phases)

Updated both:
- SyncRepository: compute isFastCharger from mode of non-zero phases
- Migration V2→V3: recalculate isFastCharger from stored chargerPhases

This matches the exact logic Teslamate uses in its Grafana dashboards.

* feat(charges): add AC/DC badges and improve charge detail charts

- Add AC/DC badge (green/orange) to charge list items in Charges screen
- Add AC/DC badge next to "Energy Added" in charge detail page
- Hide voltage chart for DC charges (not meaningful for DC fast charging)
- Add time labels (4 labels) to X axis of all charge detail graphs
- Use Teslamate's charger_phases logic for DC detection (phases=0/null is DC)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(charges): fix AC/DC badge and preserve filter state on back navigation

Fixes two bugs:
1. AC/DC badge was showing AC for all charges because it relied on
   pre-computed aggregates which may not exist yet. Now only shows
   badge when we have aggregate data for that specific charge.

2. Filter selection was reset when navigating back from charge details.
   Moved selectedFilter state from local remember to ViewModel so it
   persists across navigation.

Changes:
- Add getAllProcessedChargeIds() query to AggregateDao
- Move DateFilter enum and selectedFilter state to ChargesViewModel
- Only show AC/DC badge for charges that have been processed
- ViewModel now initializes with default filter and preserves selection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(charges): preserve scroll position on back navigation

Save and restore the LazyColumn scroll position when navigating to and
from charge details:
- Add scrollPosition and scrollOffset to ChargesUiState
- Add saveScrollPosition() to ChargesViewModel
- Pass scroll state to ChargesContent and restore it via rememberLazyListState
- Save current scroll position before navigating to charge detail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(charges): restore AC/DC badges in charges list

Reverted to always showing badges based on dcChargeIds. The previous
approach of checking processedChargeIds caused badges to disappear
when sync hadn't processed charge details yet.

Badges will show DC if the charge is in dcChargeIds (sync has processed
it as DC), otherwise AC. Once sync completes processing all charge
details, all badges will be accurate.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(sync): handle Android 14+ foreground service restrictions

On Android 14+, starting foreground services from background is restricted.
The sync worker now gracefully handles setForeground() failures by:
- Tracking if foreground service is available
- Skipping subsequent setForeground() calls if the initial one failed
- Logging the failure but continuing sync without the notification

This fixes sync interruptions caused by ForegroundServiceStartNotAllowedException.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): add "Most Distance Day" record

Shows the day with the most total distance driven, displayed in the
Records section of Stats for Nerds alongside the "Busiest Day" record.

Added:
- mostDistanceDay query to DriveSummaryDao (all-time and year range)
- MostDistanceDayResult data class
- mostDistanceDay field to QuickStats
- Display in StatsScreen Records section with 🛣️ emoji

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(mileage): add day detail drill-down with drives list

Adds a fourth level to the Mileage screen drill-down:
- Year → Month → Day → Drive Detail

Day Detail screen shows:
- Summary card with total distance, avg distance, avg battery, avg energy
- List of all drives for that day with start/end time, distance, duration, energy
- Each drive links to the full Drive Detail screen

Also:
- Added arrow indicator (>) to day cards in month view
- Made day cards clickable to navigate to day detail
- Added selectedDay and selectedDayData to MileageUiState

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): improve AC/DC ratio bar visualization

- Change colors: green for AC, yellow/amber for DC
- Make bar thicker (20dp height with rounded corners)
- Calculate ratios based on charged kWh instead of charge count
- Show energy values (kWh) in the stats row
- Show charge counts in small text below each bar side
- Remove percentage numbers from display

Added new DAO queries to sum energy by AC/DC type:
- sumAcChargeEnergy / sumAcChargeEnergyInRange
- sumDcChargeEnergy / sumDcChargeEnergyInRange

Added acChargeEnergyKwh and dcChargeEnergyKwh fields to DeepStats.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): format energy as MWh when >= 1000 kWh

- Show MWh with one decimal (e.g., "1.2 MWh") for values >= 1000 kWh
- Show kWh without decimals (e.g., "850 kWh") for smaller values

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(stats): move AC/DC ratio near charges, remove power card

- Moved AC/DC Charging Ratio card right after Charges Overview
- Removed the Charging Power card (the "Peak Power" record is still in Records)
- Simplified the deep stats section to only show temperature stats

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(stats): link day records to mileage day detail & format energy

- Add navigation from "Most Distance Day" and "Busiest Day" records
  to their respective day detail views in Mileage screen
- Add targetDay parameter to Mileage route for deep linking
- Auto-navigate to specific day when targetDay is provided
- Apply MWh formatting (>=1000 kWh) to Drives and Charges overview

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 17:52:09 +01:00
Davide FerrariandClaude Opus 4.5 8383047d50 chore: release v0.7.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 19:36:41 +01:00
Davide FerrariandClaude Opus 4.5 f619c5308c fix(dashboard): use API counts for drives/charges totals (#9)
Use total_charges and total_drives fields from the teslamate_stats object
in the /api/v1/cars endpoint instead of fetching and counting all
individual drives/charges. This is more efficient and avoids potential
race conditions with large datasets.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 19:35:59 +01:00
Davide FerrariandClaude Opus 4.5 39acebe69a chore: release v0.7.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 16:14:01 +01:00
Davide FerrariandClaude Opus 4.5 31103a60e3 feat(drives): add distance filter for drives (#8)
Add a new filter row in Drives screen to filter by drive length:
- Commute (< 10 km / 6 mi)
- Day trip (10-100 km / 6-60 mi)
- Road trip (> 100 km / 60 mi)

Filter labels automatically adapt to user's metric/imperial unit setting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 16:13:16 +01:00
Davide FerrariandClaude Opus 4.5 52b8162b13 feat: add navigation arrow hints to mileage cards (#7)
- Add right arrow icon to year cards indicating they navigate to monthly details
- Add right arrow icon to month cards indicating they navigate to daily details
- Round mileage values in year and month cards to whole numbers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 15:58:33 +01:00
Davide Ferrari e9c6383062 Merge pull request #5 from vide/fix/dashboard-counts-race-condition
fix: resolve race condition in dashboard counts display
2025-12-24 15:56:46 +01:00
Davide FerrariandClaude Opus 4.5 71ea9ce911 fix: round mileage totals to whole numbers (#6)
Remove unnecessary decimal precision from Total and Avg/Year mileage
values in the Mileage screen summary row.

Closes #4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 15:51:50 +01:00
Davide FerrariandClaude Opus 4.5 80a86fa373 fix: resolve race condition in dashboard counts display
The DashboardViewModel was using non-atomic state updates
(_uiState.value = _uiState.value.copy(...)) which caused a race
condition when two coroutines tried to update state concurrently.

When loading charges and drives counts in parallel:
1. Both coroutines read the state snapshot
2. Both do async work (API calls)
3. Each writes back with .copy() - second write overwrites first

With large datasets, API calls take longer, making this race window
much larger - explaining why users with many drives/charges saw
missing totals on the dashboard.

Fixed by using MutableStateFlow.update{} throughout the ViewModel,
which provides atomic state updates. Also updated tests to match
the current ViewModel API (CarStatusWithUnits, GeocodingRepository).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 15:38:02 +01:00
Davide Ferrari 88a9ae6573 Merge pull request #3 from vide/feat/release-notes-link
feat: add release notes link to software version cards
2025-12-23 19:39:19 +01:00
Davide FerrariandClaude Opus 4.5 9c77434825 feat: add release notes link to software version cards
Each software version card now shows an external link icon next to the
version number. Tapping it opens the NotATeslaApp release notes page
for that specific version.

URL pattern: https://www.notateslaapp.com/software-updates/version/{version}/release-notes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 19:36:41 +01:00
Davide FerrariandClaude Opus 4.5 89b60a623b fix: show all software updates instead of only 100 (#2)
The TeslaMateAPI updates endpoint supports pagination with `page` and
`show` query parameters, defaulting to show=100 results.

The app was not passing these parameters, causing users with more than
100 software updates to only see the most recent 100.

Fixed by adding pagination parameters to the API interface and passing
show=50000 in the repository (same pattern used for charges and drives).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 19:05:07 +01:00
Davide Ferrari 65575e61b8 docs: tweaked CC instructions 2025-12-23 18:44:59 +01:00
Davide Ferrari 713d23a02f feat: rename APK artifact to matedroid-VERSION.apk 2025-12-22 18:51:39 +01:00
Davide Ferrari c552e8ebec fix: add contents:write permission to release workflow 2025-12-22 18:42:03 +01:00
Davide Ferrari 248d80bd2a fix: use correct secret name KEYSTORE_ALIAS for key alias 2025-12-22 18:24:57 +01:00
Davide FerrariandClaude Opus 4.5 8d9101bbc5 fix: simplify workflow keystore setup logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 18:12:32 +01:00
Davide FerrariandClaude Opus 4.5 07811d5cf4 ci: add workflow_dispatch trigger for manual builds
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 18:11:57 +01:00
Davide FerrariandClaude Opus 4.5 91f017cf1e chore: release v0.6.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 17:58:27 +01:00
Davide FerrariandClaude Opus 4.5 6cdd205f03 docs: add drive-details screenshot
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 17:30:50 +01:00
Davide FerrariandClaude Opus 4.5 ea511f3c42 docs: reorganize gallery into two rows of 4 images
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 17:29:53 +01:00
Davide FerrariandClaude Opus 4.5 521e1cc881 fix: create debug keystore on CI when secrets not configured
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 17:25:31 +01:00
Davide FerrariandClaude Opus 4.5 1939b69698 fix: handle empty env vars in release signing config
The signing config now properly falls back to debug keystore when
KEYSTORE_BASE64 is set but empty (as happens in CI without secrets).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 17:18:51 +01:00
Davide FerrariandClaude Opus 4.5 63ca2295b0 chore: release v0.6.0
- Bump version to 0.6.0 (versionCode 7)
- Update repository URLs to github.com/vide/matedroid
- First public GitHub release with automated APK builds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 17:10:37 +01:00
Davide Ferrari 5da3fcc4c5 feat: show version number at bottom of Settings screen 2025-12-22 14:41:30 +01:00
Davide Ferrari 4c9751b329 chore: release v0.5.0 2025-12-22 14:36:48 +01:00
Davide Ferrari 24e00f40fa fix: recognize Nova19/Helix19 as same Highland M3 wheel (fallback to W38A) 2025-12-22 14:23:13 +01:00
Davide Ferrari 4f5deb9b0e feat: add Highland M3 Helix19 wheel detection (fallback to W38A) 2025-12-22 14:14:42 +01:00
Davide Ferrari 47c6f0a1d4 fix: show 'Model Y/3/S/X' when car name is empty 2025-12-22 13:44:20 +01:00
Davide Ferrari 794ff6c435 chore: ignore logo source files 2025-12-22 13:41:40 +01:00
Davide Ferrari d4012e91b5 feat: add Model Y Juniper Crossflow19 wheel support
- Add Crossflow19 wheel mapping (WY19P) for Juniper MY
- Download 3 new car images with Crossflow19 wheels
- Update ASSETS.md documentation
- Fix app icon centering
2025-12-22 13:41:26 +01:00
Davide Ferrari 218205df40 feat: add MateDroid logo as app icon 2025-12-22 13:10:22 +01:00
Davide Ferrari edb1dac9a4 feat: add GitHub Actions workflow for release builds
- Build APK automatically when a release is published
- Upload APK as release asset
- Support custom keystore signing via GitHub secrets
- Fall back to debug signing when secrets not configured
2025-12-22 11:52:28 +01:00
Davide FerrariandClaude Opus 4.5 cc5222c216 fix: allow unsecure HTTP connections to TeslamateApi
Changed android:usesCleartextTraffic from false to true in the
AndroidManifest to allow HTTP (non-HTTPS) connections to Teslamate
servers running on local networks without TLS.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 10:06:14 +01:00
Davide FerrariandClaude Opus 4.5 a20cfe447e fix: apply default 7-day filter on charges/drives screens
Remove auto-load from setCarId to prevent race condition where
all data was loaded before the date filter was applied.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 00:00:20 +01:00
Davide FerrariandClaude Opus 4.5 82b1addc7b docs: add multi-car support to changelog
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:57:48 +01:00
Davide FerrariandClaude Opus 4.5 81b70315b7 feat: add multi-car support
- Show dropdown arrow next to car name when multiple cars available
- Tap car name to open vehicle selector dialog
- Selecting a different car resets and refreshes all data
- Dialog shows all cars with checkmark on selected one

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:56:55 +01:00
Davide FerrariandClaude Opus 4.5 1d857030cc docs: simplify changelog, focus on user-visible features
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:44:17 +01:00
Davide FerrariandClaude Opus 4.5 590f48761b refactor: redesign tire pressure display to be more compact
- Replace bulky car silhouette with minimalist Tesla outline
- Use colored dots (green=OK, yellow=warning) next to pressure values
- Reduce vertical height from 100dp to 56dp
- Cleaner layout with values on sides, car shape in center
- Add mockups/ to gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:42:13 +01:00
Davide FerrariandClaude Opus 4.5 b8a26406ef fix: filter 0 km drives and convert certificate to toggle
- Add distance filter: drives < 0.1 km are now also hidden
- Convert certificate checkbox to toggle switch for consistency
- Update info dialog to mention distance filter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:22:48 +01:00
Davide FerrariandClaude Opus 4.5 9192e5e99c fix: use car color palette for location card
Match the styling of other dashboard cards by using the palette's
surface and accent colors instead of default Material colors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:19:22 +01:00
Davide FerrariandClaude Opus 4.5 a0bf3f2b98 feat: add display setting to show/hide short drives and charges
- Add "Show short drives / charges" toggle in settings (disabled by default)
- Hide drives under 1 minute and charges <= 0.1 kWh from lists when disabled
- Short entries still included in totals, averages, and chart data
- Add info tooltip explaining the setting behavior
- Remove "(less secure)" text from certificate option

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 23:15:16 +01:00
Davide Ferrari bd4db48b7e fix: add chevrons to nav buttons and fix pull-to-refresh
- Add chevron arrows to all 4 navigation buttons in Vehicle Info card
- Fix pull-to-refresh indicator staying visible after refresh completes
  (was caused by loadCarStatus launching separate coroutine)
2025-12-21 23:01:06 +01:00
Davide Ferrari 46669a7109 fix: make battery row more obviously tappable
- Add subtle background to battery info row
- Add chevron icon on right to indicate tappable
- Increase battery icon size slightly
- Improve padding and rounded corners
2025-12-21 22:57:03 +01:00
Davide Ferrari a506c9f6d4 refactor: redesign Vehicle Info card with navigation buttons
- Add rectangular navigation buttons inside Vehicle Info card (Charges, Drives, Mileage, Software)
- Each button shows icon, value, and label in horizontal layout
- Remove bottom quick links row - all navigation now inside card
- Keep tire pressure display inside Vehicle Info card
- Battery row in main card remains tappable for battery health
2025-12-21 22:53:14 +01:00
Davide Ferrari f6a95cdfc0 refactor: merge Vehicle Info card with bottom quick links
- Bottom buttons now show values: Charges, Drives, Mileage (odometer), SW
- Remove Battery button from bottom - tap battery % to go to battery health
- Make battery info row in main card tappable for battery health navigation
- Move tire pressure to separate card
- Remove unused VehicleInfoCard and CompactInfoItem components
2025-12-21 22:47:15 +01:00
Davide Ferrari 374df9a5f1 docs: update changelog with custom icons and location fix 2025-12-21 22:40:24 +01:00
Davide Ferrari c4383a27e8 fix: location card not showing address outside geofences
- Handle empty string geofence (API may return '' instead of null)
- Use takeIf { it.isNotBlank() } for proper fallback chain
- Update address during auto-refresh when location changes
- Always fall back to coordinates if no geofence or address available
2025-12-21 22:38:05 +01:00
Davide Ferrari 1c828bfc49 feat: add SteeringWheel icon for drives
- Add CustomIcons.SteeringWheel from Material Symbols (search_hands_free)
- Update Drives button on dashboard to use steering wheel icon
- Update DrivesScreen and DriveDetailScreen to use steering wheel icon
2025-12-21 22:35:53 +01:00
Davide Ferrari 2bad76749f feat: add custom Road icon from Material Symbols
- Create CustomIcons.kt with Road icon converted from Material Symbols SVG
- Update Mileage button on dashboard to use Road icon
- Update all mileage-related icons to use CustomIcons.Road
- Change 'Total' icon in MileageScreen to AllInclusive
2025-12-21 22:31:04 +01:00
Davide Ferrari 902049e266 feat: use AddRoad icon for mileage and DriveEta for drives
Note: 'Road' and 'SearchHandsFree' icons from fonts.google.com
are not available in Compose Material Icons Extended library.
Using AddRoad and DriveEta as alternatives.
2025-12-21 22:21:46 +01:00
Davide Ferrari af08610801 style: remove colons from Vehicle Info labels 2025-12-21 22:07:31 +01:00
Davide Ferrari 897b489aa6 style: right-align values in Vehicle Info card 2025-12-21 22:05:53 +01:00
Davide Ferrari 352c36fd6d style: add icons back to Vehicle Info card, left-align columns 2025-12-21 22:02:48 +01:00
Davide Ferrari 55336b0fd3 refactor: make Vehicle Info card more compact
Use horizontal 'Label: Value' format instead of vertical icons:
- Row 1: Odometer | Drives
- Row 2: Charges | SW (clickable)
- Divider + Tires section
2025-12-21 22:00:22 +01:00
Davide Ferrari 9500e3e73d feat: default to 7-day filter and show charges/drives counts
- Set 'Last 7 days' as default filter in Charges and Drives screens
- Add total charges and drives counts to Vehicle Info card on dashboard
- Reorganize card into 2x2 grid layout
2025-12-21 21:54:00 +01:00
Davide Ferrari 140322d1b3 fix: reduce X-axis label crowding on charts with many bars
Show maximum ~6 labels regardless of data size.
2025-12-21 21:42:19 +01:00
Davide Ferrari 8f313bce87 docs: update changelog with dynamic chart granularity feature 2025-12-21 18:39:53 +01:00
Davide Ferrari b4e8270719 feat: dynamic chart granularity based on date range
- 30 days or less: show daily bars
- 31-90 days: show weekly bars
- More than 90 days: show monthly bars

Applied to both Charges and Drives screens.
2025-12-21 18:38:03 +01:00
Davide Ferrari 23eb68f349 fix: reset chart selection when data changes to prevent crash 2025-12-21 18:29:08 +01:00
Davide Ferrari 5ed4f0033b docs: update changelog with interactive bar chart features 2025-12-21 18:24:38 +01:00
Davide FerrariandClaude Opus 4.5 cca78184d3 feat: add interactive bar charts with tooltips to all data screens
- Create shared InteractiveBarChart component with tap-to-show-value tooltip
- Add monthly bar charts to Charges and Drives screens
- Update Software Versions and Mileage screens to use InteractiveBarChart
- Replace DirectionsRun icons with Route icons in Mileage screens
- Add Y-axis labels showing max and min values on all charts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 18:24:23 +01:00
Davide Ferrari 83aad925e3 feat: add max/min Y-axis labels to Mileage screen bar charts
Shows the maximum value at the top (with 'k' suffix for thousands)
and 0 at the bottom for all bar charts in the Mileage screen:
- Yearly mileage chart
- Monthly mileage chart
- Daily mileage chart
2025-12-21 18:09:51 +01:00
Davide Ferrari d90bee530f feat: add max/min Y-axis labels to Software Versions bar chart
Shows the maximum update count at the top and 0 at the bottom
of the monthly updates chart for better readability.
2025-12-21 18:07:36 +01:00
Davide Ferrari 40d087412f fix: use drivingDetails.elevation instead of carGeodata.elevation
The elevation field is in DrivingDetails, not CarGeodata.
Also adds elevation display to LocationCard with metric/imperial units.
2025-12-21 17:58:41 +01:00
Davide FerrariandClaude Opus 4.5 63a0351a27 fix: improve tire pressure display colors and thresholds
- Normal pressure (2.7-3.2 bar / 39-46 PSI): uses main text color
- Out of bounds: yellow warning color
- Also respects Tesla's soft warning flags from API
- Car body now filled with 30% transparency instead of stroke
- Works with both bar and PSI display units (API returns bar)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 17:48:17 +01:00
Davide FerrariandClaude Opus 4.5 f6d82c3ba4 fix: position tires inside car body outline
Tires are now drawn inside the car rectangle at the corners,
like real wheel wells. Car body is now a stroke outline so
the colored tires are visible inside it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 17:44:42 +01:00
Davide FerrariandClaude Opus 4.5 f60b59b4a2 feat: improve battery range icons, tire display, and plug indicator
Battery Health:
- Range card icons now use green (new) and yellow (now) colors
  to match the capacity cards styling

Dashboard:
- Redesigned tire pressure display with visual top-down car view
  - Canvas drawing shows car body with 4 colored tire rectangles
  - Tires are green when OK, yellow/orange when low pressure warning
  - Cleaner layout with values on each side
- Added plug icon next to locked status when vehicle is plugged in
  but not actively charging (charging state already shows power icon)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 17:41:52 +01:00
Davide FerrariandClaude Opus 4.5 99f9b92eac feat: add info tooltips to battery health screen
- Add clickable tooltips explaining Capacity, Degradation, Range,
  Current Charge, Range Information, and Estimated Total Capacity
- Replace generic Info icons with Route icons in range value cards
- Rename "Battery Status" to "Current Charge" for clarity
- Each tooltip provides clear explanations of what the metrics mean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 17:33:13 +01:00
Davide FerrariandClaude Opus 4.5 e477b51ce5 chore: release v0.3.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:14:52 +01:00
Davide FerrariandClaude Opus 4.5 3016e4f6ed feat: improve charge/drive details and mileage screen
Charge Details:
- Show both start and end times (not just start)
- Add minimum voltage and current to Charger section

Drive Details:
- Show both start and end times (not just start)

Mileage Screen:
- Use car palette accent color for all bar graphs
- Apply consistent palette styling across year/month/day views

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 13:02:47 +01:00
Davide FerrariandClaude Opus 4.5 78836d00ab feat: add intermediate Y-axis labels to line graphs
Show values for all horizontal grid lines (not just min/max) to make
it easier to read peaks and valleys on Power, Voltage, Current,
Temperature, Battery, Speed, and Elevation charts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 12:47:27 +01:00
Davide FerrariandClaude Opus 4.5 68b6265aaf feat: add non-charging state previews and make debug button conditional
- Add charging/not-charging state variations to PalettePreviewScreen
- Show different battery icons, states, and progress bars for each
- Make palette preview button visible only in debug builds
- Fix deprecated ArrowBack icon to use AutoMirrored variant

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 12:42:37 +01:00
Davide FerrariandClaude Opus 4.5 65792f7429 feat: enhance Software Versions screen with stats and charts
- Add overview card showing total updates, avg interval, oldest/newest
- Add bar chart showing updates per month (max 24 months for all time)
- Show update duration in hh:mm format (time to install update)
- Show days installed for each version (current uses now - install date)
- Remove hash suffixes from version numbers (e.g. "2025.44.25.1")
- Trophy badge now based on days installed, not update duration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 12:29:15 +01:00
Davide FerrariandClaude Opus 4.5 b777d0036e fix: correct UpdatesResponse model to match API structure
The TeslamateAPI returns updates nested as data.updates[], not data[].
Also fixed field name from 'id' to 'update_id'.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 12:10:13 +01:00
Davide FerrariandClaude Opus 4.5 ea80b16623 feat: add Software Versions screen with update history
- Add SoftwareVersionsScreen showing historic software updates
- Each version shows install date and duration installed
- Trophy badge highlights the longest-installed version
- Date filter chips: Last 6 months, Last year, All time
- Navigate by tapping Software item in Vehicle Info card
- Clickable InfoItem with visual feedback (primary color)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 12:04:08 +01:00
Davide Ferrari 203bacf8dd docs: update ASSETS.md with Glider18 wheel and improved detection 2025-12-21 11:50:45 +01:00
Davide Ferrari d227fa6f72 feat: improve Highland/Juniper detection using wheel type
- Add Glider18 and Nova18 to Highland M3 wheel patterns
- Add HIGHLAND_M3_WHEEL_TYPES set for detection
- Add JUNIPER_MY_WHEEL_TYPES set for detection
- Update determineModelVariant to check wheel type as well as color
- Now correctly detects Highland M3 with common colors (e.g., Pearl White)
  when using Highland-only wheels like Glider18 or Photon18
2025-12-21 11:50:11 +01:00
Davide Ferrari 441ba763c8 feat: add scale factors for consistent car image sizing
- Add getScaleFactor() to CarImageResolver for model-specific scaling
- Scale Highland M3 by 1.35x, Juniper MY by 1.25x, Model X by 1.4x
- Apply scale factors in DashboardScreen and PalettePreviewScreen
- Add Pearl White Model Y Legacy to palette preview for comparison
2025-12-21 11:42:06 +01:00
Davide Ferrari 81e048e65a docs: update ASSETS.md for Model S/X and consistent view 2025-12-21 11:31:24 +01:00
Davide Ferrari b974953cc6 feat: add Model S/X images and fix Highland image sizing
- Use STUD_3QTR view for all compositor requests for consistent car sizing
- Add Model S and Model X to asset fetcher (10 new images)
- Update CarImageResolver to support Model S/X
- Add Model Y Legacy, Juniper, Model S, and Model X to palette preview screen
- Total assets now: 73 images
2025-12-21 11:30:36 +01:00
Davide Ferrari d29313f48c docs: update ASSETS.md to reflect PNG format for all models 2025-12-21 11:23:10 +01:00
Davide FerrariandClaude Opus 4.5 b5e863f13e feat: use transparent PNG for all car images
Update Tesla compositor to use bkba_opt=1 for Highland/Juniper models,
which returns transparent PNGs instead of opaque JPEGs.

Changes:
- fetch_tesla_assets.py: Set NEW_BKBA_OPT=1, output .png for all models
- CarImageResolver.kt: Remove .jpg extension logic, use .png everywhere
- Re-downloaded all 63 car images as transparent PNGs

The bkba_opt parameter controls background transparency:
- bkba_opt=1: Transparent PNG (now used for all)
- bkba_opt=2: Opaque JPEG with background

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 11:20:07 +01:00
Davide FerrariandClaude Opus 4.5 4ce9c476d0 fix: adjust summary card column weights for better spacing
Use asymmetric weights (1.2f left, 0.8f right) to reduce empty
space on the right side of summary cards in Charges and Drives.

Battery and Mileage screens use different layouts that don't
need this adjustment.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 11:06:25 +01:00
Davide FerrariandClaude Opus 4.5 8d69e435e2 fix: align summary items in drives screen
Apply same alignment fix as charges screen - use equal weight
distribution for summary items.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:58:29 +01:00
Davide FerrariandClaude Opus 4.5 9319e7afad fix: align summary items in charges screen
Use equal weight distribution for summary items so they align
properly on the left, with room to expand on the right.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:55:15 +01:00
Davide FerrariandClaude Opus 4.5 db020020dd feat: use Paid icon and currency symbol for all cost displays
- Replace AttachMoney icon with Paid (coin) icon for consistency
- Add currency symbol to Cost stats card (total and per kWh)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:50:02 +01:00
Davide FerrariandClaude Opus 4.5 9a8cb28a73 feat: add currency symbol to charge cost display
Fetch currency from settings and display it with the cost value
in the charge detail header card.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:38:34 +01:00
Davide FerrariandClaude Opus 4.5 8cf68e3975 feat: add charge cost to charge detail header card
Display cost prominently alongside energy added in the LocationHeaderCard,
on the right side of the same row for easy comparison.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:31:56 +01:00
Davide FerrariandClaude Opus 4.5 887ff49178 feat: extend car color palette to all main cards and navigation
- Add exteriorColor parameter to navigation routes
- Propagate exteriorColor from Dashboard to all screens
- Update ChargesScreen SummaryCard to use car color palette
- Update DrivesScreen SummaryCard to use car color palette
- Update BatteryScreen cards (Capacity, Degradation, Range) to use palette
- Update MileageScreen YearlyChartCard and SummaryRow to use palette
- Update DateFilterChips on Charges/Drives screens to use palette
- Detail screens now receive exteriorColor for future use

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:26:14 +01:00
Davide FerrariandClaude Opus 4.5 d99dbeefae fix: replace Tesla red accent with neutral grey theme
The base theme now uses cool grey colors instead of Tesla red,
so all screens have a consistent neutral look that doesn't clash
with the car-specific battery card palette.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:13:25 +01:00
Davide FerrariandClaude Opus 4.5 9b0ed058b8 feat: dynamic car color palettes for battery card
- Add CarColorPalette with per-car-color theming
- Disable Material You dynamic colors (use app theme only)
- Battery card now adapts to car exterior color
- Light mode: White uses warm grey, Black uses darker grey
- Dark mode: Blue-grey for white, warm brown for black
- Semantic colors (green/orange/red) remain fixed for status
- Add palette preview screen for debugging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 10:07:44 +01:00
Davide FerrariandClaude Opus 4.5 107d191a3c chore: bump version to 0.2.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 23:44:39 +01:00
Davide FerrariandClaude Opus 4.5 2b49eb2460 feat: reverse geocode address when no geofence is set
- Add NominatimApi for OpenStreetMap reverse geocoding
- Add GeocodingRepository with caching to avoid repeated API calls
- Update DashboardViewModel to fetch address when geofence is null
- Display resolved address in LocationCard (priority: geofence > address > coordinates)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 23:34:41 +01:00
Davide FerrariandClaude Opus 4.5 fd578a1013 fix: update quick links icon and order
- Changed Charges icon to ElectricBolt (zap)
- Reordered: Charges, Battery, Drives, Mileage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 23:29:43 +01:00
Davide FerrariandClaude Opus 4.5 d30ee67edf feat: make all maps tappable to open external map app
- Dashboard location card: opens geo: URI at car coordinates
- Drive detail map: opens Google Maps with route from start to end
- Charge detail map: opens geo: URI at charge location
- Dashboard now shows coordinates when car is not at a saved location

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 23:11:36 +01:00
Davide FerrariandClaude Opus 4.5 53aa57c152 feat: make location card tappable to open maps app
- Entire location card is now clickable to open default maps app
- Show coordinates when car is not at a saved location (geofence)
- Small map preview is also tappable
- Location card now shows even without a geofence name

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 23:08:42 +01:00
Davide FerrariandClaude Opus 4.5 db2c1f4adf fix: reduce top padding between title and battery card
Changed top padding from 16dp to 8dp

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 20:39:24 +01:00