diff --git a/BACKLOG.md b/BACKLOG.md index d259547..b74b6e8 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -106,6 +106,19 @@ Status: TODO / IN PROGRESS / DONE / BLOCKED. scene (CPListTemplate) for navigation deep-links. - [ ] **Alert region tuning** — make alert trigger radius + dedup window user-configurable (currently fixed 300 m trigger / 1 per station per hour). +- [ ] **Price-drop alerts: threshold control + Check now** — keep the current + cache-first / 12 h refresh policy, but add a per-alert sensitivity control + for favourite price-drop alerts instead of a fetch-frequency slider. Scope: + `Minimum change` picker (e.g. 0.5p / 1.0p / 2.0p), plus a `Check now` + action in the Alerts tab that forces a fetch and immediately re-evaluates the + cheapest-favourite alert. Copy should set expectation honestly: standard + mode checks when FuelBoard refreshes prices (up to twice daily). +- [ ] **Price-drop alerts: optional frequent-check mode** — if the app ever + relaxes the current "twice daily max" data policy, expose this as a clearly + separate mode rather than a freeform frequency slider. Example framing: + `Standard` (current behaviour) vs `Frequent` (best-effort extra checks), + with conservative caps (e.g. every 4–6 h, not hourly) and copy that does not + promise exact timing under iOS background scheduling. - [ ] **Pull-to-refresh spinner state** — surface refresh in-flight state (currently `refreshable` fires but no visible progress in the row list). - [x] **Offline first-run** — bundled REAL 8,022-station dump (`FuelBoardDump`, @@ -135,6 +148,12 @@ Status: TODO / IN PROGRESS / DONE / BLOCKED. trend, after the Trends UI lands (one-kind rule preserved). - [ ] **Price alerts for a specific station** — notify when a starred station's price drops below a user threshold. +- [ ] **Price-drop alerts: mode = Cheapest favourite / All favourites** — keep + `Cheapest favourite` as the default low-noise mode, but explore an optional + `All favourites` mode for one fuel. Guardrails if built: threshold required, + per-station dedupe based on last-alerted price (not just time), and combine + multiple drops from one refresh into a single summary notification rather + than one alert per station. - [ ] **Share sheet** — share "Cheapest Unleaded near me" as text/image card. - [ ] **Watch app** — glanceable cheapest-price complication (WatchKit + shared app-group store; watch target would need to be added to the project). diff --git a/FuelBoard/AlertsView.swift b/FuelBoard/AlertsView.swift index 956b9f7..e5508cd 100644 --- a/FuelBoard/AlertsView.swift +++ b/FuelBoard/AlertsView.swift @@ -32,6 +32,7 @@ struct AlertsView: View { let distanceUnit: DistanceUnit let monitoredCount: Int let lastAlert: String? + let onCheckFavouriteDropNow: () -> Void /// The Stations-tab search distance shown in the user's unit, e.g. /// "5 miles" or "8 km" — for the "Follow search" rows. @@ -139,6 +140,8 @@ struct AlertsView: View { Text(fuel.displayName).tag(fuel) } } + Button("Check now", action: onCheckFavouriteDropNow) + .disabled(!favouriteDropEnabled) } header: { Text("Price-drop alerts") } footer: { diff --git a/FuelBoard/ContentView.swift b/FuelBoard/ContentView.swift index 1d6b61d..eeee2f1 100644 --- a/FuelBoard/ContentView.swift +++ b/FuelBoard/ContentView.swift @@ -623,7 +623,10 @@ struct ContentView: View { stationLimit: stationLimit, distanceUnit: distanceUnit, monitoredCount: monitor.monitoredStationIDs.count, - lastAlert: monitor.lastAlert + lastAlert: monitor.lastAlert, + onCheckFavouriteDropNow: { + Task { await refresh(force: true) } + } ) }