Commit Graph
13 Commits
Author SHA1 Message Date
FuelBoard Contributor 906f8a8429 Small widget: declare config params in display order for every summary branch. If iOS falls back to declaration order when re-rendering the sheet after a parameter change, the favourites branch previously re-ordered to Sort by first (sort was declared before favouriteFuel). Now favouriteFuel, fuel, sort, favourite, distance — Favourites mode reads Fuel · Sort by · Favourite under either ordering mechanism. No encoding change (config keys are identifiers, order-independent). 2026-08-13 18:21:03 +01:00
FuelBoard Contributor 926317236a Widget config sheets: unify row layout across both widgets — Fuel type first, then Sort by, then Favourite (Favourites sort only). Small widget's Favourites branch reordered from Sort/Fuel/Favourite to Fuel/Sort/Favourite, and the favourites-scoped fuel param retitled 'Fuel' so the row reads identically in every mode. Medium widget was already Fuel-first. No parameter type changes, so no stored-config reset beyond the normal reinstall. 2026-08-13 18:02:53 +01:00
FuelBoard Contributor 3e2d3775f2 Widget config sheet: revert WidgetSort to String-backed AppEnum. parameterSummary When(\.$sort, .equalTo, …) silently falls back to the otherwise branch for AppEntity parameters (iOS 17+ bug FB13263902), which hid the Favourite/Favourite Fuel rows on the small widget — the metadata compared against a literal 'WidgetSort.favourites' string instead of the enum case. String AppEnums match reliably (the d8506a0 form). Tradeoff: the Sort picker always offers Favourites; picking it with no favourites shows the empty state. FavouriteFuel entity + IntentParameterDependency filtering unchanged. 2026-08-13 17:48:33 +01:00
FuelBoard Contributor d0bd4e7a8e Small widget favourites config: fuel dictates the favourite list (@IntentParameterDependency filters picker options by the chosen fuel), fuel picker shows only fuels with favourites (FavouriteFuel entity), Favourites sort hidden when no favourites exist (WidgetSort → dynamic AppEntity), fuel tags removed from favourite rows 2026-08-13 17:14:14 +01:00
FuelBoard Contributor d8506a035f Small widget favourite picker: embed station name + multi-fuel flag in the WidgetFavourite entity so picker rows render with no storage read (config-sheet resolution can run without keychain/app-group access, which made every row show the 'Favourite' placeholder) 2026-08-13 17:00:17 +01:00
FuelBoard Contributor 7357eb98c3 Small widget favourites: fuel row returns to the config sheet (picks the default favourite); pinned favourite wins, fuel-tagged picker rows when favourites span >1 fuel; fallback = selected fuel's cheapest favourite 2026-08-13 16:51:21 +01:00
FuelBoard Contributor 1bdef59d78 Small widget: Favourites gains a picker to pin which favourite to show (separate FuelPriceWidgetSmall kind + AppEntity picker; medium keeps the list, no picker). Backlog: dual-unit widget picker labels 2026-08-13 15:49:18 +01:00
FuelBoard Contributor 26e724f48a Widget config: Distance picker as AppEntity so labels resolve dynamically from the app's units (AppEnum labels are static) 2026-08-13 15:33:24 +01:00
FuelBoard Contributor 64330f96a8 Widget config: Distance picker mirrors the app's units setting (5 mi = 8 km) via dynamic AppEnum displayRepresentation 2026-08-13 15:25:20 +01:00
FuelBoard Contributor 1dcd47c6cd Fix widget distance menu + geofence notification chain
Widget distance menu: the Distance picker only makes sense for
Cheapest ordering. It was hidden for Favourites but Closest still
showed it (regressed when the per-widget Distance picker was added).
parameterSummary now nests When clauses: Distance visible for
Cheapest only; Closest and Favourites hide it.

Notifications: three compounding defects kept real geofence alerts
from ever firing while the app was suspended:

1. Always permission was never properly requested. requestPermissions
   fired WhenInUse and Always back-to-back; iOS ignores the second
   call while the first prompt is pending, leaving the app stuck on
   WhenInUse — and region entries are never delivered in the
   background. Added locationManagerDidChangeAuthorization to
   ProximityMonitor: escalate WhenInUse -> Always, and re-register
   geofences on grant (regions registered under WhenInUse-only won't
   deliver in the background).

2. The 18-region window was frozen in the background. Re-registration
   lived in SwiftUI .onChange(of: locationManager.current), which
   never runs while suspended. Added a delegate hook
   (LocationManager.onLocationUpdate) fired from didUpdateLocations on
   every fix including background significant-change wake-ups; the app
   wires it to re-register geofences around the new position.

3. Region-registration failures were invisible. monitoringDidFailFor
   was never implemented, so a failed startMonitoring (region budget,
   auth, radius) silently stopped alerts. Now surfaced as
   monitor.lastRegionError and shown in Settings -> Debug; cleared on
   the next successful registration.
2026-08-12 18:18:24 +01:00
FuelBoard Contributor 5246f41c48 Widget Favourites filter: pinned stations cheapest-first, no radius
- New Sort by value 'Favourites' in Edit Widget (per-widget config).
- ParameterSummary hides the Distance picker when Favourites is selected
  (favourites are not radius-bound).
- Favourites mode reads keychain favourites (shared access group works on
  SideStore free even without App Groups), filters to the widget's fuel,
  refreshes prices from a focused relay fetch when in range, and ranks
  cheapest-first with distance tiebreak. Not radius-filtered.
- App now re-saves refreshed favourites to keychain after every fetch so
  the widget shows current prices instead of star-time snapshots.
- Empty state + headings adapt to favourites mode. 35 tests pass.
2026-08-12 13:45:42 +01:00
FuelBoard Contributor 2a8de27571 Widget: per-widget distance, sanitised names, £ prices
- New Distance picker in Edit Widget (5/10/15 miles), independent of the
  app's distance filter; used for both the relay fetch radius and the
  strict in-widget filter.
- Brand text is now title-cased via sanitizedStationTitle (relay sends
  all-caps brands like SHELL/TESCO/MORRISONS).
- Prices now show as £1.399 (monospaced) matching the app, instead of
  139.9p.
- Directions deep-link (mapsDirectionsURL) already per-row on medium and
  whole-widget on small; unchanged. 35 tests pass.
2026-08-12 12:25:30 +01:00
FuelBoard Contributor 002d7f63e2 Widgets configured per-instance via App Intent
FuelPriceWidget now uses AppIntentConfiguration with a per-widget
FuelBoardWidgetConfigurationIntent (fuel + sort). Each widget placed on
the home screen carries its OWN fuel type (Unleaded/Premium/Diesel) and
ordering (Cheapest/Closest), edited by long-press -> Edit Widget —
independent of the app's selection, so multiple widgets can show
different data side by side. Widget no longer reads the app's selected
fuel. 35 tests pass.
2026-08-12 11:45:37 +01:00