Introduce a shared RefreshableErrorState widget that wraps the retry
hint in a RefreshIndicator with an explicit 'pull down to retry'
caption, so users can recover from load failures without navigating
away. Wire it into the location screen's error fallbacks and make the
control_panel body pull-to-refresh at any time, invalidating the device
list so the dashboard picks up fresh data.
Device providers (legacyDevicesProvider, selectedDeviceProvider), repository,
datasource, and GetDevicesResponseModel now live in sf_shared. Also moved
dio_error_mapper (safeCall, mapDioError, formatErrorMessage) to sf_infrastructure.
Consumers import directly from sf_shared instead of re-exporting through legacy_shared.
Introduces legacyDevicesProvider as the canonical AsyncNotifier owning
the devices list, with semantic mutation methods (removeDevice,
renameDevice, refresh) instead of ref.invalidate from outside.
selectedDeviceProvider becomes an AsyncNotifier that persists the
selected device id in SharedPreferences and resolves it against the
shared list at build time, surviving cold starts.
ControlPanelViewModel and LocationViewModel are converted to
AsyncNotifier and react to selection changes, refetching positions /
geofences / frequent_places automatically. Screens use .when with
skipLoadingOnReload to avoid flicker.
Multi-device fixes:
- DeviceBanner cards now look up positions per device by identificator
- LocationMap recenters the camera on device swipe
- Country-level fallback zoom when no position is available
- Banner shows each device's own info while swiping
linked_devices and device_setup feed mutations through the new notifier
methods. 30+ legacy view models updated to read selectedDeviceProvider
via .value (AsyncNotifier shape).
- Type device.settings and device.capabilities from untyped maps to Freezed models
- Centralize all device settings updates through shared DeviceSettingsUpdateDatasource
- Add frequency selectors for location and heart rate, pedometer toggle, and health measurement countdown with Lottie animation
- Replace raw backend error messages with typed i18n error events across location, health, and activity meter
- Fix silent error swallowing in commands datasource and stuck dialog in locate device
- Add volume control screen with sliders for media, ringtone, and alarm
- Update device settings via PUT /devices with CSV (same as language)
- Extract DeviceCsvBuilder to legacy_shared (shared between language and volume)
- Create Riverpod provider for DeviceUpdateDatasource
- Extract VolumeThumbShape to separate widget file
- Merge sound mode feature (SET_SOUND_MODE command, pending backend whitelist)
- Fix sound screen overflow with SingleChildScrollView
- Position history with polyline trail and date range picker
- Map style selector (standard, voyager, light, dark, satellite) persisted via SharedPreferences
- Geofence and frequent place CRUD with info cards
- Device banner with swipeable carousel
- Refresh position button
- Widget extraction: map controls, info cards, device banner, modal overlay
Device management:
- Activity meter with steps charts and history
- Apps usage with daily breakdown and top apps
- Health monitoring (heart rate, oxygen, blood pressure)
- Scheduled activities with timeline and CRUD
- Contacts sync to device via contact-lists
- Locate device, rewards refactor
Settings (new module):
- Block phone
- SOS contacts
- WiFi networks
- Alarm refactor with full CRUD
- Settings menu with feature stubs
Account:
- Personal data and account settings refactor
Shared:
- 100+ i18n keys in 6 languages
- New routes in app_router
- WeekDayChips, TimeRangeSelector shared widgets
- Legacy dashboard shell simplified