Skip to content

feat: trip cost intelligence, cost widget, and battery history - #334

Open
raykellyjr wants to merge 7 commits into
vide:mainfrom
raykellyjr:cursor/trip-cost-intelligence-e380
Open

feat: trip cost intelligence, cost widget, and battery history#334
raykellyjr wants to merge 7 commits into
vide:mainfrom
raykellyjr:cursor/trip-cost-intelligence-e380

Conversation

@raykellyjr

Copy link
Copy Markdown

Summary

Major read-only analytics leap for MateDroid — deeper use of owned TeslaMate data for trips, charging costs, and battery health. No vehicle commands.

Trip intelligence

  • Richer Trips summary: energy used/charged, efficiency, known cost, cost/100 only when every charge is priced, honest partial/missing coverage notes
  • Trip highlights card: most/least efficient, cheapest/priciest per 100 (complete pricing only), longest, highest charging overhead, energy gap, avg charging minutes — tap to open the trip

Cost intelligence

  • New Costs screen from the dashboard (7/30/90-day or all-time): known cost, cost/100, avg cost/kWh, energy, missing/free session coverage
  • New Cost summary home-screen widget (7/30/90 days) over Room cache only — refreshes after sync, never polls the car

Battery health

  • Persists daily max-range snapshots (Room v13) and charts history on the Battery screen once enough samples exist

Notes

Test plan

  • ./gradlew :app:testDebugUnitTest
  • ./gradlew :app:lintDebug
  • Manual: open Costs from dashboard, switch ranges, confirm partial pricing labels
  • Manual: add Cost summary widget, confirm offline numbers after sync
  • Manual: Trips highlights navigate to trip detail
  • Manual: Battery screen shows history after ≥2 daily loads

Raymond Kelly added 5 commits July 18, 2026 02:03
Only show cost per 100 distance when every charge in the filtered
trips is priced. Keep known totals visible with clearer coverage
notes, including when charges exist but none are priced.
- TripIntelligenceCalculator surfaces per-trip standouts on top of
  the existing TripsSummaryCalculator: most/least efficient, cheapest
  and priciest per 100 km/mi (Complete cost-coverage only), longest,
  biggest charging-overhead share, plus ensemble energy gap and
  average charging minutes per trip.
- New IntelligenceCard on the Trips screen renders those highlights
  under the summary card; tapping a trip-backed row opens the trip.
- New BatteryHealthSnapshot Room entity + DAO records the max-range
  figure every time the Battery screen loads, debounced to at most
  once per day per car and pruned to 90 rows.
- Room migration 12 -> 13 adds the snapshots table; DatabaseModule
  provides the new DAO to Hilt consumers.
- BatteryScreen renders a max-range trend using OptimizedLineChart
  once at least two snapshots exist, with 5 X labels and a tap
  tooltip per the project chart rules.
- Full set of strings localized across en/it/es/ca/de/zh and the
  changelog entry updated.
- CostAnalyticsCalculator turns a range of ChargeSummary rows + total
  distance into an honest set of cost metrics: known cost, cost/100
  distance (Complete coverage only), avg cost/kWh, energy added, and
  missing/free session counts. Reuses TripCostCoverage semantics.
- CostAnalyticsRepository loads charges + distance from Room using the
  new ChargeSummaryDao.getInRange query, and stitches in the user's
  currency + unit-of-length from SettingsDataStore. All work happens on
  Dispatchers.IO and never touches the API.
- CostAnalyticsScreen (Material3, car palette) shows range chips
  (7/30/90/all-time), a headline card with the cost, energy and distance
  figures, and a coverage card that explains partial or missing pricing.
  Reachable from the dashboard via a new "Costs" nav button.
- CostSummaryWidget is a read-only Glance widget that mirrors the same
  numbers on the home screen with 7/30/90-day ranges, configurable per
  car. All formatting happens in the worker; the widget itself only
  renders preformatted strings and never talks to TeslaMate.
- CostSummaryWidgetUpdateWorker owns DB access + formatting; scheduled
  by the receiver on install (periodic 6h) and by DataSyncWorker after
  each successful sync so widgets refresh with the freshest cache.
- SettingsDataStore caches teslamate_units.unit_of_length under a new
  key; DashboardViewModel and SettingsViewModel update the cache when
  they fetch global settings so widgets can format distances offline.
- MainActivity honours EXTRA_SKIP_CAR_WIDGET_UPDATE so tapping the cost
  widget does not schedule an unrelated car-status refresh.
- New DAO queries for cost coverage: countWithCostInRange,
  countMissingCostInRange, countZeroCostInRange, getInRange.
- Unit tests cover the calculator's complete/partial/missing/zero-cost
  cases, the widget formatter's coverage semantics, and the widget's
  date-range helper.
Document the read-only widget stack and Room v13 battery history
cache so contributors know where cost/trip intelligence lives.
Use cached TeslaMate unit-of-length as a Cost Analytics fallback,
refresh units from global settings in the cost widget worker, and
update the cost widget after summary sync even when detail sync retries.
@raykellyjr

Copy link
Copy Markdown
Author

Review + polish pass complete

Self-reviewed and pushed follow-up fixes:

  • Cost Analytics now falls back to cached TeslaMate unit_of_length so Room distances are never mislabeled as km for imperial users
  • Cost widget worker refreshes units from TeslaMate global settings (not the vehicle) before formatting
  • Cost widget also refreshes after summary sync even when detail sync is still retrying

Local verification: :app:testDebugUnitTest + :app:lintDebug green.

CI note: GitHub Actions shows action_required for first-time fork PRs — please approve the workflow run on this PR so CI can fully execute.

Cache unit-of-length during summary sync and stop live-fetching
TeslaMate units in the cost widget/worker so Room values and labels
cannot drift after a unit change.
@raykellyjr

Copy link
Copy Markdown
Author

Final correctness pass: cost widget/screen now label Room data using the unit cached at summary-sync time only (no live settings fetch during widget update). Ready for workflow approval.

@raykellyjr

Copy link
Copy Markdown
Author

Hello, these are ready for review.

GitHub has the fork stuck on "action_required" (I'm a first-time contributor). Could you approve the workflows on this pull PR and then merge?

Suggested order is to merge 334 and then 332.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants