Commit Graph

212 Commits

Author SHA1 Message Date
79039b99e2 refactor(legacy): align with Riverpod architecture (DTOs, repos, drop UseCases) 2026-04-26 21:52:52 +02:00
14720b66bf refactor(legacy): split legacy_shared into cohesive packages
legacy_shared was the junk drawer of the legacy app mode — 37 files
mixing device entities, command infrastructure, UI primitives, generic
formatters, and a duplicate of sf_infrastructure's dio_error_mapper.
Any module needing one piece pulled the whole bag into its graph.

Split it by responsibility, following Mandamiento 4 of Real-World Flutter:

- legacy_ui (new): 6 widget/layout primitives (PageLayout, MenuButton,
  SectionButton, PulsingLocationMarker, RefreshableErrorState,
  WeekDayChips) plus mapStyleProvider — shared UI state that was the
  only reason two modules needed a common package.
- legacy_device_state (expanded 9 → 30): absorbed device entities,
  commands infrastructure (datasource + repo + provider + guard),
  device settings update flow, and the CSV exporter. Now one package
  owns the device domain end-to-end.
- packages/utils: absorbed battery_utils and date_format_utils as pure
  formatters that never belonged in a legacy-scoped package.
- legacy_shared: deleted entirely.

The duplicate dio_error_mapper in legacy_shared is gone; callers now use
the sf_infrastructure version (which was always the superset — it adds
ApiException and the dart:io socket handling).

DeviceEntity note: legacy_device_state keeps its own DeviceEntity (with
int timestamps and typed paymentOptions) separate from sf_shared's
DeviceEntity (String timestamps, untyped paymentOptions). The legacy
one is intentionally not exported from the barrel to avoid the
ambiguous_import collision that legacy_shared quietly hid by never
exporting it in the first place. Unifying the two is a domain-model
refactor out of scope here.

0 cross-module imports remain among legacy feature modules.
2026-04-26 21:52:51 +02:00
f7d3dbfd27 refactor(legacy): migrate theming to Material 3 + SfColors extension
Replace the ThemePort/ThemeCode abstraction (GetIt-registered adapter)
with a Riverpod-driven Material 3 ColorScheme, an SfColors ThemeExtension
for brand tokens, and a user-facing appearance selector for light/dark/
system modes. Persisted via SharedPreferences, reacts to system
brightness changes. Payments mode keeps the existing ThemePort API.

Highlights
- New legacy_theme package: LegacyAppTheme (light/dark), LegacyColorSchemes,
  SfColors ThemeExtension, LegacyThemePreferences, LegacyThemeNotifier,
  LegacyThemeSelector. Timeframe-based variants scaffolded but disabled.
- New /legacy/dashboard/control_panel/settings/appearance route + screen.
- MaterialApp.router picks the legacy theme only when isLegacyMode.
- ~90 ThemeCode.* usages migrated to colorScheme.* / context.sfColors.*.
- 25 widgets dropped the 'ThemePort theme' constructor param.
- ~145 hardcoded colors migrated (exact hex 1:1, grey.shade tiers,
  destructive red -> colorScheme.error, background whites -> surface).
  Content-over-color whites, transparents, and brand semantic reds/
  oranges/greens intentionally preserved.
- sf_localizations updated with appearance / appearanceDescription keys
  in all six locales.
2026-04-26 21:52:50 +02:00
6cf994cd5d refactor(legacy): extract shared device state into legacy_device_state package
- New package legacy_device_state hosts shared device/position state
  consumed by both control_panel and location screens. ControlPanel*
  classes renamed to LegacyDevice* in 8 moved files.
- Move PositionEntity + AddressEntity + NetworkEntity +
  LatestPositionsResponseModel + BatteryUtils + DateFormatUtils from
  control_panel to legacy_shared (shared domain entities).
- Remove anti-pattern re-export of sf_infrastructure/dio_error_mapper
  from legacy_shared barrel. Update consumers to import
  sf_infrastructure directly.
- Clean 14 unused legacy_shared imports across view models in
  account, device_management, legacy_auth and settings modules.

Eliminates cross-module dependency location -> control_panel.
0 errors, 0 warnings in flutter analyze across 11 packages/modules.
2026-04-26 21:52:50 +02:00
fa3d7aa1fd fix(location): keep map visible on transient network errors
Show snackbar instead of replacing the entire map with an error state
when a reload fails. Only show RefreshableErrorState on first load failure.
2026-04-26 21:52:50 +02:00
5b4d31e2f1 fix(location): guard frequency timer minimum and filter zero options
Prevent position polling timer from firing with frequency < 60s (protects
against 0s values that saturate the API). Also filter out 0 from location
capability options in the frequency selector.
2026-04-26 21:52:50 +02:00
e7ebe7f403 fix 2026-04-17 15:13:34 +02:00
ed41b82076 chore(legacy): hide wifi settings and forgot password entry points
Comment out the navigation entry points for the wifi settings flow
from the device settings list and for the forgot-password link from
the login screen while these flows wait for product sign-off. The
underlying screens and providers stay in place so re-enabling them is
a single uncomment.
2026-04-17 11:16:08 +02:00
f82d222df3 style(device_setup): redesign activation code dialog with icon and OK action
Replace the bare centered text with a rounded dialog that leads with a
mail icon, keeps the activation-code message, and adds an explicit OK
button to dismiss. Aligns the dialog with the rest of the legacy
design system.
2026-04-17 11:13:53 +02:00
fd8ef27185 feat(splash): route to device setup when a logged-in user has zero devices
Extend CheckSessionUseCase to fetch /devices after confirming the
session and return InitialRoute.deviceSetup when the list is empty
(or the call fails). The splash builder now injects a
SharedDevicesRepository alongside the user repository, and the app
router maps the new route to legacyDeviceSetup / deviceSetup per
shell. The legacy builder reads legacyDevicesProvider to derive
isFirstDevice so the setup screen adapts its copy accordingly.
2026-04-17 11:13:48 +02:00
bf1032245a refactor(device_setup): type API errors with status-code-based enum
Introduce LegacyDeviceSetupErrorEvent and two mappers for the
generate-activation-key and create-device endpoints. 403 on
activation-key maps to invalidIdentificator; 404 to deviceNotFound;
401 (already activated or B2B) unifies as deviceNotAvailable. On
create-device, 403 → invalidField and 404 → invalidActivationKey.
The view state now splits validation vs API errors with a
displayErrorKey extension, replacing the previous e.toString() leak
that could surface stack traces to users.
2026-04-17 11:12:37 +02:00
fad2c8792c refactor(recover_password): type API errors and hide email enumeration
Map PUT /auth/reset-password and PUT /auth/recovery-password failures
into LegacyRecoverPasswordErrorEvent. Reset-password now treats 404
(email not found) as success and surfaces a generic sent-if-exists
flow, closing an account enumeration vector. Recovery-password
differentiates 401 (tokenExpired), 404 (tokenNotFound), 403+Property
(invalidField) from 403 without Property (weakPassword). The view
state splits validation vs API errors with a displayErrorKey extension
for the inline error text.
2026-04-17 11:12:14 +02:00
73d9de45a2 refactor(signup): type API errors with status-code-based enum
Introduce LegacySignupErrorEvent to map backend failures from
POST /auth/signup: 400 → emailAlreadyExists, 403 → invalidField,
429 → tooManyAttempts, timeout → network. The view state now
separates validationErrorKey (pre-submit i18n keys) from apiErrorEvent
(typed API outcomes), and the screen listens to both to show proper
i18n messages instead of leaking raw backend text.
2026-04-17 11:11:52 +02:00
56d89fcdc4 refactor(login): type auth errors with status-code-based enum
Replace the raw errorMessage string in the login view state with a
typed LegacyAuthErrorEvent that classifies backend failures by HTTP
status (403/404 → invalidCredentials, 423 → accountLocked, 401 +
NOT_VERIFIED/expired → dedicated events, 429 → tooManyAttempts,
timeout → network). The login screen and 2FA sheet now switch on the
enum to show specific i18n messages instead of surfacing raw backend
text. Adds auth i18n keys for the full set of mapped states.
2026-04-17 11:11:23 +02:00
72d44b81df feat(legacy): add pull-to-refresh for control_panel and location
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.
2026-04-17 09:44:29 +02:00
2942d7393e feat(wifi_settings): support setting saved networks as current
Add a setNetwork action that sends the setWifi command for a saved
network and waits for wifiCurrent confirmation with a 15s timeout.
Saved network cards are now tappable to trigger the switch, and
dedicated success/error states surface the result via snackbar.
2026-04-17 09:44:16 +02:00
0b160758e2 refactor(legacy): make guardDeviceCommand async with stale TTL refetch
Convert the shared command guard to an async check that refetches
/devices when the cached state is older than 30s, so the isDisconnect
flag reflects reality before a command runs. A TopSnackBar explains the
check only if the fetch takes longer than 400ms, avoiding noise on fast
responses. Update all 44 call sites to await the guard.
2026-04-17 09:43:52 +02:00
e7a4653c01 refactor(shared): move device providers and data layer from legacy_shared to sf_shared
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.
2026-04-17 08:48:38 +02:00
05ffe572c8 fix(logout): invalidate device providers to clear stale data on user switch 2026-04-17 04:10:33 +02:00
cbc40f7d95 feat(alerts): add device alerts screen with pagination, filters, and WebSocket 2026-04-17 04:00:25 +02:00
27e26ca921 refactor(utils): extract query params builder, migrate health and location 2026-04-17 04:00:12 +02:00
973fc2490c feat(wifi-settings): redesign with device commands, WebSocket scan, and connect flow 2026-04-17 03:06:23 +02:00
ddc5086b3b feat(legacy): block device commands when watch is disconnected 2026-04-16 23:48:07 +02:00
769e8fea27 refactor(do-not-disturb): move data layer to core, remove delete action 2026-04-16 21:26:07 +02:00
297fa8241a fix(control-panel): make position model fields nullable to prevent null cast crash 2026-04-16 20:35:48 +02:00
984a87f200 feat(alarm): changed alarm endpoint and modified models, entities and presentation 2026-04-16 18:42:29 +02:00
1230a27d94 fix(location): single-color route, contrasting arrows, time labels on endpoints 2026-04-16 14:52:07 +02:00
bc46f31434 fix(contacts): use dynamic max limits from device capabilities 2026-04-16 13:55:07 +02:00
514daf9c7c feat(do-not-disturb): add DND schedule feature with capabilities-driven UI 2026-04-16 13:54:13 +02:00
51a3979c03 feat(location-map): auto-center on first fix, follow toggle, refresh feedback 2026-04-15 22:13:12 +02:00
c7e32d1399 refactor(activity-meter): redesign screen with honest per-range stats 2026-04-15 21:51:08 +02:00
4e21e8d698 chore(gitignore): untrack IDE and flutter plugin artifacts 2026-04-15 17:13:52 +02:00
9e41090712 refactor(settings): unify SOS and block_phone sheets with shared ContactFormSheet 2026-04-15 17:06:51 +02:00
648d0fc04b refactor(account): migrate personal_data to SfPhoneNumber and fix change_password state 2026-04-15 17:06:46 +02:00
56e437ff13 refactor(device-management): migrate call_watch and remote_connection to SfPhoneNumber 2026-04-15 17:06:41 +02:00
88c1111bd5 refactor(device-management): split contacts feature into list/new/edit view models and migrate to SfPhoneNumber 2026-04-15 17:05:56 +02:00
85be483c4e refactor(legacy-auth): migrate link_phone to SfPhoneNumber with E.164 2026-04-15 17:05:50 +02:00
08e099fc37 refactor(legacy-auth): simplify signup to 2 steps and remove phone from recover password 2026-04-15 17:04:43 +02:00
6b2034612a removed "+" symbol from sign up email 2026-04-14 15:39:01 +02:00
03998f9cf1 router fixes 2026-04-14 14:44:03 +02:00
63a4113d81 refactor(legacy): single source of truth for devices + persisted selection
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).
2026-04-08 16:06:44 +02:00
d352aec5be feat(notifications): register FCM token with backend post-login
Adds NotificationsRemoteDatasource in sf_shared that POSTs the current
Firebase Messaging token to /notifications/push, wired into the legacy
login flow right after getUserInfo so the device can receive targeted
push notifications.

Fire-and-forget with catchError so a failure never blocks login.
2026-04-08 15:40:37 +02:00
60558a4fcf fix(payment): correct hardcoded legacyLogin in onboarding redirect 2026-04-08 15:39:26 +02:00
29887818f9 melos format 2026-04-07 17:07:47 +02:00
42ec003b05 refactor(tracking): tighten sf_tracking package
- Lazy-init sfTracking to avoid touching Firebase at import time
- DRY SfTrackingRepository with a single _broadcast helper
- Drop empty DashboardTracking, fix double step_completed in device_setup
- Move yearsBetween to packages/utils
- Add 5 unit tests for SfTrackingRepository
- Strip noisy comments from mixins and view models
2026-04-07 16:59:38 +02:00
4728e25803 feat(tracking): expand legacy module analytics coverage 2026-04-07 16:17:53 +02:00
7b91447cad feat(tracking): add sf_tracking package and instrument legacy module
Introduces packages/sf_tracking — a multi-client, GDPR-first analytics layer with feature mixins, a GoRouter listener for automatic screen views, and a user properties helper that runs on login.
Wires the package into the legacy module 61 events
2026-04-07 13:47:07 +02:00
c1954497b8 chore: add root .gitignore and untrack auto-generated cache files
The repo had no root-level .gitignore, so .dart_tool/, ephemeral plugin
symlinks and build artifacts were being tracked across the workspace.
Every flutter pub get regenerated them and they polluted PRs as recurring
noise.

- Add root .gitignore covering .dart_tool/, ephemeral plugin symlinks,
  build/, coverage/, IDE files
- Untrack ~39 existing cache files across root, modules and packages
2026-04-07 03:30:35 +02:00
9cdb4c7724 refactor: rename Questia to SaveFamily across the codebase 2026-04-07 00:47:29 +02:00
c263e4227e feat: split legacy/payment apps via APP_MODE flag 2026-04-07 00:09:48 +02:00