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
This commit is contained in:
2026-04-07 13:47:07 +02:00
parent d84c856ce7
commit 7b91447cad
71 changed files with 1342 additions and 10 deletions

View File

@@ -1,7 +1,10 @@
import 'dart:async';
import 'package:account/src/features/account_settings/presentation/state/account_settings_view_state.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_auth/legacy_auth.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import 'package:sf_tracking/sf_tracking.dart';
final accountSettingsViewModelProvider =
NotifierProvider.autoDispose<
@@ -10,8 +13,11 @@ final accountSettingsViewModelProvider =
>(AccountSettingsViewModel.new);
class AccountSettingsViewModel extends Notifier<AccountSettingsViewState> {
late final SfTrackingRepository _tracking;
@override
AccountSettingsViewState build() {
_tracking = ref.read(sfTrackingProvider);
return const AccountSettingsViewState();
}
@@ -26,6 +32,8 @@ class AccountSettingsViewModel extends Notifier<AccountSettingsViewState> {
await clearSessionData();
unawaited(_tracking.legacyAuthLogout());
state = state.copyWith(isLoggingOut: false);
}
}

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:account/src/features/change_password/domain/change_password_use_case.dart';
import 'package:account/src/features/change_password/domain/models/entities/change_password_request_entity.dart';
import 'package:account/src/features/change_password/presentation/providers/change_password_use_case_provider.dart';
@@ -5,6 +7,7 @@ import 'package:account/src/features/change_password/presentation/state/change_p
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
final changePasswordViewModelProvider =
NotifierProvider.autoDispose<
@@ -14,6 +17,7 @@ final changePasswordViewModelProvider =
class ChangePasswordViewModel extends Notifier<ChangePasswordViewState> {
late final ChangePasswordUseCase _changePasswordUseCase;
late final SfTrackingRepository _tracking;
late final TextEditingController newPasswordController;
late final TextEditingController repeatPasswordController;
@@ -22,6 +26,7 @@ class ChangePasswordViewModel extends Notifier<ChangePasswordViewState> {
@override
ChangePasswordViewState build() {
_changePasswordUseCase = ref.read(changePasswordUseCaseProvider);
_tracking = ref.read(sfTrackingProvider);
_initControllers();
@@ -123,6 +128,7 @@ class ChangePasswordViewModel extends Notifier<ChangePasswordViewState> {
userId: user.id,
request: request,
);
unawaited(_tracking.legacyAccountPasswordChanged());
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
if (!ref.mounted) return;
@@ -132,6 +138,7 @@ class ChangePasswordViewModel extends Notifier<ChangePasswordViewState> {
}
void _finishWithError({required String message}) {
unawaited(_tracking.legacyAccountPasswordChangeFailed(message));
state = state.copyWith(
isLoading: false,
isComplete: false,

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:account/src/core/domain/repositories/users_repository.dart';
import 'package:account/src/core/providers/users_repository_provider.dart';
import 'package:account/src/features/delete_account/presentation/state/delete_account_view_state.dart';
@@ -5,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
final deleteAccountViewModelProvider =
NotifierProvider.autoDispose<
@@ -15,12 +18,16 @@ final deleteAccountViewModelProvider =
class DeleteAccountViewModel extends Notifier<DeleteAccountViewState> {
late final UsersRepository _usersRepository;
late final SharedDevicesRepository _devicesRepository;
late final SfTrackingRepository _tracking;
late final TextEditingController passwordController;
@override
DeleteAccountViewState build() {
_usersRepository = ref.read(usersRepositoryProvider);
_devicesRepository = ref.read(sharedDevicesRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
unawaited(_tracking.legacyAccountDeletionInitiated());
passwordController = TextEditingController();
passwordController.addListener(_onPasswordChanged);
@@ -86,6 +93,7 @@ class DeleteAccountViewModel extends Notifier<DeleteAccountViewState> {
}
void resetConfirmStep() {
unawaited(_tracking.legacyAccountDeletionCancelled());
state = state.copyWith(confirmStep: 0);
}
@@ -95,9 +103,13 @@ class DeleteAccountViewModel extends Notifier<DeleteAccountViewState> {
try {
state = state.copyWith(isLoading: true, isComplete: false);
unawaited(_tracking.legacyAccountDeletionConfirmed());
await _usersRepository.deleteUser(userId: state.loggedUser!.id);
if (!ref.mounted) return;
unawaited(_tracking.legacyAccountDeletionCompleted());
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,9 +1,12 @@
import 'dart:async';
import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart';
import 'package:account/src/features/linked_devices/presentation/state/linked_devices_view_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/domain/repositories/devices_repository.dart';
import '../../../../core/providers/devices_repository_provider.dart';
@@ -17,6 +20,7 @@ final linkedDevicesViewModelProvider =
class LinkedDevicesViewModel extends Notifier<LinkedDevicesViewState> {
late final SharedDevicesRepository _getDevicesRepository;
late final DevicesRepository _devicesRepository;
late final SfTrackingRepository _tracking;
late final TextEditingController deviceNameController;
@@ -24,6 +28,7 @@ class LinkedDevicesViewModel extends Notifier<LinkedDevicesViewState> {
LinkedDevicesViewState build() {
_getDevicesRepository = ref.read(sharedDevicesRepositoryProvider);
_devicesRepository = ref.read(devicesRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
_initControllers();
_init();
@@ -76,6 +81,8 @@ class LinkedDevicesViewModel extends Notifier<LinkedDevicesViewState> {
ref.invalidate(selectedDeviceProvider);
}
unawaited(_tracking.legacyAccountLinkedDeviceUnlinked());
state = state.copyWith(
linkedDevices: newList,
isLoading: false,

View File

@@ -1,8 +1,11 @@
import 'dart:async';
import 'package:account/src/features/personal_data/domain/entities/update_user_request_entity.dart';
import 'package:account/src/features/personal_data/presentation/state/personal_data_view_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/domain/repositories/users_repository.dart';
import '../../../../core/providers/users_repository_provider.dart';
@@ -14,6 +17,7 @@ final personalDataViewModelProvider =
class PersonalDataViewModel extends Notifier<PersonalDataViewState> {
late final UsersRepository _usersRepository;
late final SfTrackingRepository _tracking;
late final TextEditingController firstNameController;
late final TextEditingController lastNameController;
@@ -22,6 +26,7 @@ class PersonalDataViewModel extends Notifier<PersonalDataViewState> {
@override
PersonalDataViewState build() {
_usersRepository = ref.read(usersRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
firstNameController = TextEditingController();
lastNameController = TextEditingController();
@@ -92,6 +97,8 @@ class PersonalDataViewModel extends Notifier<PersonalDataViewState> {
);
ref.read(userInfoProvider.notifier).setUser(updatedUser);
unawaited(_tracking.legacyAccountPersonalDataEdited());
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -29,6 +29,8 @@ dependencies:
legacy_auth:
path: ../../modules/legacy_auth
#packages dependencies go here
sf_tracking:
path: ../../../../packages/sf_tracking
design_system:
path: ../../../../packages/design_system
navigation:

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:control_panel/src/core/domain/entities/position_entity.dart';
import 'package:control_panel/src/core/domain/repositories/control_panel_repository.dart';
import 'package:control_panel/src/core/providers/control_panel_repository_provider.dart';
@@ -5,6 +7,7 @@ import 'package:control_panel/src/features/control_panel/presentation/state/cont
import 'package:legacy_shared/legacy_shared.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
final controlPanelViewModelProvider =
NotifierProvider.autoDispose<ControlPanelViewModel, ControlPanelViewState>(
@@ -15,12 +18,14 @@ class ControlPanelViewModel extends Notifier<ControlPanelViewState> {
late final ControlPanelRepository _controlPanelRepository;
late final SharedDevicesRepository _devicesRepository;
late final SelectedDeviceNotifier _selectedDeviceNotifier;
late final SfTrackingRepository _tracking;
@override
ControlPanelViewState build() {
_controlPanelRepository = ref.read(controlPanelRepositoryProvider);
_devicesRepository = ref.read(sharedDevicesRepositoryProvider);
_selectedDeviceNotifier = ref.read(selectedDeviceProvider.notifier);
_tracking = ref.read(sfTrackingProvider);
_init();
return const ControlPanelViewState();
}
@@ -106,6 +111,7 @@ class ControlPanelViewModel extends Notifier<ControlPanelViewState> {
);
if (!ref.mounted) return;
_applyPositions(positionLists);
unawaited(_tracking.legacyControlPanelPositionsRefreshed());
} catch (e) {
if (!ref.mounted) return;
state = state.copyWith(errorMessage: formatErrorMessage(e));
@@ -123,5 +129,7 @@ class ControlPanelViewModel extends Notifier<ControlPanelViewState> {
);
_selectedDeviceNotifier.setSelectedDevice(device);
unawaited(_tracking.legacyControlPanelDeviceSelected());
}
}

View File

@@ -36,6 +36,8 @@ dependencies:
legacy_dashboard_shell:
path: ../../modules/legacy_dashboard_shell
#packages dependencies go here
sf_tracking:
path: ../../../../packages/sf_tracking
design_system:
path: ../../../../packages/design_system
navigation:

View File

@@ -1,7 +1,10 @@
import 'dart:async';
import 'package:customer_service/src/presentation/state/contact_view_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:url_launcher/url_launcher.dart';
final contactViewModelProvider =
@@ -14,6 +17,7 @@ class ContactViewModel extends Notifier<ContactViewState> {
late final TextEditingController emailController;
late final TextEditingController subjectController;
late final TextEditingController bodyController;
late final SfTrackingRepository _tracking;
static final RegExp _emailRegex = RegExp(
r'^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$',
@@ -22,6 +26,8 @@ class ContactViewModel extends Notifier<ContactViewState> {
@override
ContactViewState build() {
_tracking = ref.read(sfTrackingProvider);
nameController = TextEditingController();
emailController = TextEditingController();
subjectController = TextEditingController();
@@ -116,6 +122,9 @@ class ContactViewModel extends Notifier<ContactViewState> {
final Uri url = Uri.parse(
'mailto:$receiver?from=$sender&subject=$subject&body=$body',
);
unawaited(_tracking.legacySupportContactInitiated('email'));
if (!await launchUrl(url)) {
throw Exception('Could not launch $url');
}

View File

@@ -28,6 +28,8 @@ dependencies:
#modules dependencies go here
#packages dependencies go here
sf_tracking:
path: ../../../../packages/sf_tracking
design_system:
path: ../../../../packages/design_system
navigation:

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/data/datasources/health_query_builder.dart';
import '../../../../core/presentation/time_range.dart';
@@ -16,12 +19,14 @@ final activityMeterViewModelProvider =
class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
late final StepsRepository _repository;
late final SfTrackingRepository _tracking;
static const int _historyPageSize = 20;
@override
ActivityMeterViewState build() {
_repository = ref.read(stepsRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
_init();
return const ActivityMeterViewState();
}
@@ -262,6 +267,9 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
);
if (!ref.mounted) return false;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacyDeviceActivityPedometerToggled(enabled));
return true;
} catch (e) {
if (!ref.mounted) return false;

View File

@@ -1,7 +1,10 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:image_picker/image_picker.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/domain/repositories/background_image_repository.dart';
import '../../../../core/providers/background_image_repository_provider.dart';
@@ -16,11 +19,13 @@ final backgroundImageViewModelProvider =
class BackgroundImageViewModel extends Notifier<BackgroundImageViewState> {
late final BackgroundImageRepository _repository;
late final SharedDevicesRepository _devicesRepository;
late final SfTrackingRepository _tracking;
@override
BackgroundImageViewState build() {
_repository = ref.read(backgroundImageRepositoryProvider);
_devicesRepository = ref.read(sharedDevicesRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const BackgroundImageViewState();
}
@@ -85,6 +90,8 @@ class BackgroundImageViewModel extends Notifier<BackgroundImageViewState> {
await _refreshDevice(device);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceBackgroundImageUploaded());
state = state.copyWith(
isSaving: false,
successEvent: BackgroundImageSuccessEvent.uploaded,
@@ -120,6 +127,8 @@ class BackgroundImageViewModel extends Notifier<BackgroundImageViewState> {
await _refreshDevice(device);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceBackgroundImageChanged());
state = state.copyWith(
isSaving: false,
successEvent: BackgroundImageSuccessEvent.backgroundSet,

View File

@@ -1,7 +1,10 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:uuid/uuid.dart';
import '../../../../core/data/models/create_contact_request_model.dart';
@@ -20,10 +23,12 @@ class ContactsViewModel extends Notifier<ContactsViewState> {
static const _uuid = Uuid();
late final ContactsRepository _contactsRepository;
late final SfTrackingRepository _tracking;
@override
ContactsViewState build() {
_contactsRepository = ref.read(contactsRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
_init();
return const ContactsViewState();
}
@@ -85,6 +90,8 @@ class ContactsViewModel extends Notifier<ContactsViewState> {
await _contactsRepository.createContact(request: request);
if (!ref.mounted) return false;
unawaited(_tracking.legacyContactsAdded());
await _reload();
return true;
} catch (e) {
@@ -118,6 +125,8 @@ class ContactsViewModel extends Notifier<ContactsViewState> {
await _contactsRepository.updateContact(request: request);
if (!ref.mounted) return false;
unawaited(_tracking.legacyContactsEdited());
await _reload();
return true;
} catch (e) {
@@ -141,6 +150,8 @@ class ContactsViewModel extends Notifier<ContactsViewState> {
await _contactsRepository.deleteContact(contactId: contact.id);
if (!ref.mounted) return false;
unawaited(_tracking.legacyContactsDeleted());
await _reload();
return true;
} catch (e) {

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/data/datasources/health_query_builder.dart';
import '../../../../core/presentation/time_range.dart';
@@ -29,6 +30,7 @@ final healthViewModelProvider =
class HealthViewModel extends Notifier<HealthViewState> {
late final HealthRepository _repository;
late final CommandsRepository _commandsRepository;
late final SfTrackingRepository _tracking;
Timer? _measureTimer;
static const int _historyPageSize = 20;
@@ -38,6 +40,7 @@ class HealthViewModel extends Notifier<HealthViewState> {
HealthViewState build() {
_repository = ref.read(healthRepositoryProvider);
_commandsRepository = ref.read(commandsRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
_init();
_resumeMeasureIfNeeded();
return const HealthViewState();
@@ -305,6 +308,11 @@ class HealthViewModel extends Notifier<HealthViewState> {
);
if (!ref.mounted) return false;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(
_tracking.legacyDeviceHealthHeartRateFrequencyChanged(frequency),
);
return true;
} catch (e) {
if (!ref.mounted) return false;
@@ -327,6 +335,8 @@ class HealthViewModel extends Notifier<HealthViewState> {
await _commandsRepository.send(request: request);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceHealthMeasurementStarted());
ref
.read(_measureEndTimeProvider.notifier)
.set(

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'locate_device_view_state.dart';
@@ -10,10 +13,12 @@ final locateDeviceViewModelProvider =
class LocateDeviceViewModel extends Notifier<LocateDeviceViewState> {
late final CommandsRepository _commandsRepository;
late final SfTrackingRepository _tracking;
@override
LocateDeviceViewState build() {
_commandsRepository = ref.read(commandsRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
final device = ref.read(selectedDeviceProvider);
@@ -36,6 +41,8 @@ class LocateDeviceViewModel extends Notifier<LocateDeviceViewState> {
);
await _commandsRepository.send(request: request);
unawaited(_tracking.legacyDeviceLocateRequested());
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
state = state.copyWith(

View File

@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:device_management/src/features/remote_connection/presentation/state/remote_connection_view_state.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/domain/repositories/pictures_repository.dart';
@@ -18,6 +19,7 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
late final TextEditingController phoneController;
late final CommandsRepository _commandsRepository;
late final PicturesRepository _picturesRepository;
late final SfTrackingRepository _tracking;
Timer? _photoTimer;
static final RegExp _phoneRegex = RegExp(r'^\+?\d{6,15}$');
@@ -27,6 +29,9 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
RemoteConnectionViewState build() {
_commandsRepository = ref.read(commandsRepositoryProvider);
_picturesRepository = ref.read(picturesRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
unawaited(_tracking.legacyDeviceRemoteConnectionStarted());
phoneController = TextEditingController();
phoneController.addListener(_onPhoneChanged);
@@ -109,6 +114,8 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
await _commandsRepository.send(request: request);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceRemoteConnectionPhotoTaken());
state = state.copyWith(
isTakingPicture: false,
isWaitingForPhoto: true,
@@ -188,6 +195,9 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
await _commandsRepository.send(request: request);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceRemoteConnectionCallInitiated());
state = state.copyWith(isCalling: false);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,6 +1,9 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'rewards_view_state.dart';
@@ -14,10 +17,12 @@ class RewardsViewModel extends Notifier<RewardsViewState> {
late final TextEditingController amountController;
late final CommandsRepository _commandsRepository;
late final SfTrackingRepository _tracking;
@override
RewardsViewState build() {
_commandsRepository = ref.read(commandsRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
amountController = TextEditingController(text: '1');
amountController.addListener(_onAmountChanged);
@@ -66,6 +71,8 @@ class RewardsViewModel extends Notifier<RewardsViewState> {
await _commandsRepository.send(request: request);
unawaited(_tracking.legacyDeviceRewardsGranted(amount: state.amount));
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
state = state.copyWith(

View File

@@ -1,6 +1,9 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:uuid/uuid.dart';
import '../../../../core/data/models/create_scheduled_activity_request_model.dart';
@@ -19,11 +22,13 @@ final scheduledActivitiesViewModelProvider =
class ScheduledActivitiesViewModel
extends Notifier<ScheduledActivitiesViewState> {
late final ScheduledActivitiesRepository _repository;
late final SfTrackingRepository _tracking;
static const _uuid = Uuid();
@override
ScheduledActivitiesViewState build() {
_repository = ref.read(scheduledActivitiesRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
_init();
return const ScheduledActivitiesViewState();
}
@@ -98,6 +103,8 @@ class ScheduledActivitiesViewModel
await _repository.createActivity(request: request);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceScheduledActivityAdded());
await _reload();
} catch (e) {
if (!ref.mounted) return;
@@ -138,6 +145,8 @@ class ScheduledActivitiesViewModel
);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceScheduledActivityUpdated());
await _reload();
} catch (e) {
if (!ref.mounted) return;
@@ -152,6 +161,8 @@ class ScheduledActivitiesViewModel
await _repository.deleteActivity(activityId: activityId);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceScheduledActivityRemoved());
await _reload();
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,6 +1,9 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'volume_control_view_state.dart';
@@ -12,10 +15,12 @@ final volumeControlViewModelProvider =
class VolumeControlViewModel extends Notifier<VolumeControlViewState> {
late final DeviceSettingsUpdateDatasource _datasource;
late final SfTrackingRepository _tracking;
@override
VolumeControlViewState build() {
_datasource = ref.read(deviceSettingsUpdateProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(() => _load());
return const VolumeControlViewState();
}
@@ -70,6 +75,14 @@ class VolumeControlViewModel extends Notifier<VolumeControlViewState> {
if (!ref.mounted) return;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(
_tracking.legacyDeviceVolumeControlChanged(
type: 'media',
level: state.media,
),
);
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -28,6 +28,8 @@ dependencies:
#modules dependencies go here
#packages dependencies go here
sf_tracking:
path: ../../../../packages/sf_tracking
design_system:
path: ../../../../packages/design_system
navigation:

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:legacy_auth/src/core/domain/repositories/device_setup_repository.dart';
import 'package:legacy_auth/src/core/providers/device_setup_repository_provider.dart';
import 'package:legacy_auth/src/core/utils/date_format_utils.dart';
@@ -7,6 +9,7 @@ import 'package:legacy_auth/src/features/device_setup/presentation/enums/add_kid
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
final legacyDeviceSetupViewModelProvider =
NotifierProvider<LegacyDeviceSetupViewModel, LegacyDeviceSetupViewState>(
@@ -15,6 +18,7 @@ final legacyDeviceSetupViewModelProvider =
class LegacyDeviceSetupViewModel extends Notifier<LegacyDeviceSetupViewState> {
late final LegacyDeviceSetupRepository _deviceSetupRepository;
late final SfTrackingRepository _tracking;
late final TextEditingController firstNameController;
late final TextEditingController lastNameController;
@@ -29,6 +33,9 @@ class LegacyDeviceSetupViewModel extends Notifier<LegacyDeviceSetupViewState> {
final initial = const LegacyDeviceSetupViewState();
_initControllers(initial);
_addListeners();
_tracking = ref.read(sfTrackingProvider);
unawaited(_tracking.legacyDeviceSetupStarted());
ref.onDispose(disposeControllers);
@@ -62,9 +69,11 @@ class LegacyDeviceSetupViewModel extends Notifier<LegacyDeviceSetupViewState> {
Future<void> next() async {
switch (state.step) {
case LegacyAddKidStep.intro:
unawaited(_tracking.legacyDeviceSetupStepCompleted('intro'));
state = state.copyWith(step: LegacyAddKidStep.linkInfo);
return;
case LegacyAddKidStep.linkInfo:
unawaited(_tracking.legacyDeviceSetupStepCompleted('link_info'));
state = state.copyWith(step: LegacyAddKidStep.scanWatch);
return;
case LegacyAddKidStep.scanWatch:
@@ -90,9 +99,16 @@ class LegacyDeviceSetupViewModel extends Notifier<LegacyDeviceSetupViewState> {
identificator: identificator,
);
if (!ref.mounted) return;
unawaited(_tracking.legacyDeviceSetupStepCompleted('scan_watch'));
state = state.copyWith(isLoading: false, step: LegacyAddKidStep.profile);
} catch (e) {
if (!ref.mounted) return;
unawaited(
_tracking.legacyDeviceSetupFailed(
atStep: 'scan_watch',
reason: e.toString(),
),
);
state = state.copyWith(isLoading: false, errorMessage: e.toString());
}
}
@@ -102,12 +118,15 @@ class LegacyDeviceSetupViewModel extends Notifier<LegacyDeviceSetupViewState> {
case LegacyAddKidStep.intro:
return;
case LegacyAddKidStep.linkInfo:
unawaited(_tracking.legacyDeviceSetupCancelled('link_info'));
state = state.copyWith(step: LegacyAddKidStep.intro, errorMessage: '');
return;
case LegacyAddKidStep.scanWatch:
unawaited(_tracking.legacyDeviceSetupCancelled('scan_watch'));
state = state.copyWith(step: LegacyAddKidStep.linkInfo);
return;
case LegacyAddKidStep.profile:
unawaited(_tracking.legacyDeviceSetupCancelled('profile'));
state = state.copyWith(step: LegacyAddKidStep.scanWatch);
return;
}
@@ -154,11 +173,20 @@ class LegacyDeviceSetupViewModel extends Notifier<LegacyDeviceSetupViewState> {
if (!ref.mounted) return false;
unawaited(_tracking.legacyDeviceSetupCompleted());
state = state.copyWith(isLoading: false, isSuccess: true);
return true;
} catch (e) {
if (!ref.mounted) return false;
unawaited(
_tracking.legacyDeviceSetupFailed(
atStep: 'profile',
reason: e.toString(),
),
);
state = state.copyWith(isLoading: false, errorMessage: e.toString());
return false;
}

View File

@@ -1,6 +1,9 @@
import 'dart:async';
import 'package:legacy_auth/src/features/link_phone/presentation/providers/link_phone_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:legacy_auth/src/features/link_phone/domain/use_cases/link_phone_use_case.dart';
import 'package:legacy_auth/src/features/link_phone/presentation/state/link_phone_view_state.dart';
@@ -13,12 +16,14 @@ final legacyLinkPhoneViewModelProvider =
class LegacyLinkPhoneViewModel extends Notifier<LegacyLinkPhoneViewState> {
late final LegacyLinkPhoneUseCase _linkPhoneUseCase;
late final SfTrackingRepository _tracking;
late final TextEditingController phoneNumberController;
late final TextEditingController codeController;
@override
LegacyLinkPhoneViewState build() {
_linkPhoneUseCase = ref.read(legacyLinkPhoneUseCaseProvider);
_tracking = ref.read(sfTrackingProvider);
phoneNumberController = TextEditingController();
phoneNumberController.addListener(_onPhoneNumberChanged);
@@ -76,6 +81,8 @@ class LegacyLinkPhoneViewModel extends Notifier<LegacyLinkPhoneViewState> {
await _linkPhoneUseCase.requestCode(phone: fullPhone);
if (!ref.mounted) return;
unawaited(_tracking.legacyAuthLinkPhoneCodeRequested());
state = state.copyWith(
isLoading: false,
errorMessage: '',
@@ -125,6 +132,8 @@ class LegacyLinkPhoneViewModel extends Notifier<LegacyLinkPhoneViewState> {
await _linkPhoneUseCase.verifyCode(phone: fullPhone, code: code);
if (!ref.mounted) return;
unawaited(_tracking.legacyAuthLinkPhoneCodeVerified());
state = state.copyWith(
isLoading: false,
errorMessage: '',

View File

@@ -8,6 +8,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
final legacyLoginViewModelProvider =
NotifierProvider.autoDispose<LegacyLoginViewModel, LegacyLoginViewState>(
@@ -18,6 +19,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
with LoginFormValidation {
late final LegacyLoginRepository _repository;
late final GetUserInfoUseCase _getUserInfoUseCase;
late final SfTrackingRepository _tracking;
late final TextEditingController emailController;
late final TextEditingController passwordController;
@@ -30,6 +32,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
LegacyLoginViewState build() {
_repository = ref.read(legacyLoginRepositoryProvider);
_getUserInfoUseCase = ref.read(getUserInfoUseCaseProvider);
_tracking = ref.read(sfTrackingProvider);
emailController = TextEditingController();
emailController.addListener(_onEmailChanged);
@@ -102,6 +105,8 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
twoFAVerified: false,
);
unawaited(_tracking.legacyAuthLoginAttempt());
try {
final response = await _repository.login(
email: email,
@@ -110,6 +115,8 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
if (!ref.mounted) return;
unawaited(_tracking.legacyAuthLoginSuccess());
state = state.copyWith(
token: response.token,
availableMethods: response.availableMethods,
@@ -118,6 +125,8 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
} catch (e) {
if (!ref.mounted) return;
unawaited(_tracking.legacyAuthLoginFailure(formatErrorMessage(e)));
state = state.copyWith(
isLoading: false,
errorMessage: formatErrorMessage(e),
@@ -153,6 +162,8 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
if (!ref.mounted) return;
unawaited(_tracking.legacyAuth2faRequested());
_startResendCooldown();
state = state.copyWith(
twoFARequested: true,
@@ -207,6 +218,8 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
if (!ref.mounted) return;
unawaited(_tracking.legacyAuth2faVerified());
await _getUserInfoUseCase.getUserInfo();
if (!ref.mounted) return;
@@ -223,6 +236,8 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
} catch (e) {
if (!ref.mounted) return;
unawaited(_tracking.legacyAuth2faFailure(formatErrorMessage(e)));
state = state.copyWith(
isLoading: false,
errorMessage: formatErrorMessage(e),
@@ -231,6 +246,7 @@ class LegacyLoginViewModel extends Notifier<LegacyLoginViewState>
}
Future<void> resendCode() async {
unawaited(_tracking.legacyAuth2faResend());
state = state.copyWith(code: '', isLoading: true);
await _requestTwoFACode(updateLoading: true);
}

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_auth/src/features/onboarding/presentation/onboarding_view_state.dart';
import 'package:sf_tracking/sf_tracking.dart';
final legacyOnBoardingViewModelProvider =
NotifierProvider.autoDispose<
@@ -8,12 +11,16 @@ final legacyOnBoardingViewModelProvider =
>(LegacyOnBoardingViewModel.new);
class LegacyOnBoardingViewModel extends Notifier<LegacyOnboardingViewState> {
late final SfTrackingRepository _tracking;
@override
LegacyOnboardingViewState build() {
_tracking = ref.read(sfTrackingProvider);
return const LegacyOnboardingViewState();
}
void onPageChanged(int index) {
unawaited(_tracking.legacyOnboardingStepChanged(index));
state = state.copyWith(cardIndex: index);
}
}

View File

@@ -1,7 +1,10 @@
import 'dart:async';
import 'package:legacy_auth/src/features/recover_password/domain/use_cases/recover_password_use_case.dart';
import 'package:legacy_auth/src/features/recover_password/presentation/state/recover_password_view_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../providers/recover_password_provider.dart';
@@ -14,6 +17,7 @@ final legacyRecoverPasswordViewModelProvider =
class LegacyRecoverPasswordViewModel
extends Notifier<LegacyRecoverPasswordViewState> {
late final LegacyRecoverPasswordUseCase _recoverPasswordUseCase;
late final SfTrackingRepository _tracking;
late final TextEditingController phoneNumberController;
late final TextEditingController emailController;
late final TextEditingController passwordController;
@@ -23,6 +27,7 @@ class LegacyRecoverPasswordViewModel
@override
LegacyRecoverPasswordViewState build() {
_recoverPasswordUseCase = ref.read(legacyRecoverPasswordUseCaseProvider);
_tracking = ref.read(sfTrackingProvider);
phoneNumberController = TextEditingController();
phoneNumberController.addListener(_onPhoneNumberChanged);
@@ -126,6 +131,8 @@ class LegacyRecoverPasswordViewModel
recoveryRequested: false,
);
unawaited(_tracking.legacyAuthPasswordResetRequested());
if (email.isNotEmpty) {
await requestEmail();
} else {
@@ -146,6 +153,8 @@ class LegacyRecoverPasswordViewModel
);
if (!ref.mounted) return;
unawaited(_tracking.legacyAuthPasswordResetEmailSent());
state = state.copyWith(
isLoading: false,
errorMessage: '',

View File

@@ -13,6 +13,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sealed_countries/sealed_countries.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
final legacySignUpViewModelProvider =
NotifierProvider.autoDispose<LegacySignUpViewModel, LegacySignUpViewState>(
@@ -22,6 +23,7 @@ final legacySignUpViewModelProvider =
class LegacySignUpViewModel extends Notifier<LegacySignUpViewState>
with SignUpFormValidation {
late final LegacySignUpRepository _repository;
late final SfTrackingRepository _tracking;
late final TextEditingController firstNameController;
late final TextEditingController lastNameController;
@@ -50,6 +52,7 @@ class LegacySignUpViewModel extends Notifier<LegacySignUpViewState>
@override
LegacySignUpViewState build() {
_repository = ref.read(legacySignUpRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
final initial = LegacySignUpViewState();
_initControllers(initial);
@@ -537,12 +540,16 @@ class LegacySignUpViewModel extends Notifier<LegacySignUpViewState>
showAccountCreated: false,
);
unawaited(_tracking.legacyAuthSignupStarted());
try {
final request = _toRequest();
final response = await _repository.signUp(request: request);
if (!ref.mounted) return false;
unawaited(_tracking.legacyAuthSignupCompleted());
state = state.copyWith(
isLoading: false,
isCreated: response.isCreated,
@@ -558,6 +565,8 @@ class LegacySignUpViewModel extends Notifier<LegacySignUpViewState>
? I18n.errorEmailAlreadyRegistered
: msg;
unawaited(_tracking.legacyAuthSignupFailed(errorMsg));
state = state.copyWith(isLoading: false, errorMessage: errorMsg);
return false;
}

View File

@@ -25,6 +25,8 @@ dependencies:
path: ../../../../packages/utils
sf_shared:
path: ../../../../packages/sf_shared
sf_tracking:
path: ../../../../packages/sf_tracking
legacy_shared:
path: ../../packages/legacy_shared
fonts:

View File

@@ -1,9 +1,12 @@
import 'dart:async';
import 'package:control_panel/control_panel.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:latlong2/latlong.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/features/location/presentation/state/location_map_view_state.dart';
import 'package:sf_tracking/sf_tracking.dart';
final locationMapViewModelProvider =
NotifierProvider.autoDispose<LocationMapViewModel, LocationMapViewState>(
@@ -11,17 +14,24 @@ final locationMapViewModelProvider =
);
class LocationMapViewModel extends Notifier<LocationMapViewState> {
late final SfTrackingRepository _tracking;
@override
LocationMapViewState build() {
_tracking = ref.read(sfTrackingProvider);
return const LocationMapViewState();
}
void toggleGeofences() {
state = state.copyWith(showGeofences: !state.showGeofences);
final newVisible = !state.showGeofences;
unawaited(_tracking.legacyLocationMapGeofencesToggled(newVisible));
state = state.copyWith(showGeofences: newVisible);
}
void toggleFrequentPlaces() {
state = state.copyWith(showFrequentPlaces: !state.showFrequentPlaces);
final newVisible = !state.showFrequentPlaces;
unawaited(_tracking.legacyLocationMapFrequentPlacesToggled(newVisible));
state = state.copyWith(showFrequentPlaces: newVisible);
}
void startPlacing(PlacingMode mode) {

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:location/src/core/data/models/create_frequent_place_request_model.dart';
@@ -11,6 +13,7 @@ import 'package:location/src/core/domain/repositories/location_repository.dart';
import 'package:location/src/core/providers/location_repository_provider.dart';
import 'package:location/src/features/location/presentation/state/location_view_state.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:uuid/uuid.dart';
final locationViewModelProvider =
@@ -20,10 +23,12 @@ final locationViewModelProvider =
class LocationViewModel extends Notifier<LocationViewState> {
late final LocationRepository _locationRepository;
late final SfTrackingRepository _tracking;
@override
LocationViewState build() {
_locationRepository = ref.read(locationRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
final device = ref.read(selectedDeviceProvider);
if (device != null) {
_fetchData(device.id);
@@ -80,6 +85,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
request: request,
);
if (!ref.mounted) return false;
unawaited(_tracking.legacyLocationGeofenceCreated());
state = state.copyWith(
geofences: [...state.geofences, created],
isSubmitting: false,
@@ -117,6 +125,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
request: request,
);
if (!ref.mounted) return false;
unawaited(_tracking.legacyLocationGeofenceUpdated());
state = state.copyWith(
geofences: state.geofences
.map((g) => g.id == id ? updated : g)
@@ -135,6 +146,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
try {
await _locationRepository.deleteGeofence(geofenceId: id);
if (!ref.mounted) return false;
unawaited(_tracking.legacyLocationGeofenceDeleted());
state = state.copyWith(
geofences: state.geofences.where((g) => g.id != id).toList(),
successMessage: LocationSuccessEvent.geofenceDeleted,
@@ -182,6 +196,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
request: request,
);
if (!ref.mounted) return false;
unawaited(_tracking.legacyLocationFrequentPlaceCreated());
state = state.copyWith(
frequentPlaces: [...state.frequentPlaces, created],
isSubmitting: false,
@@ -225,6 +242,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
request: request,
);
if (!ref.mounted) return false;
unawaited(_tracking.legacyLocationFrequentPlaceUpdated());
state = state.copyWith(
frequentPlaces: state.frequentPlaces
.map((f) => f.id == id ? updated : f)
@@ -243,6 +263,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
try {
await _locationRepository.deleteFrequentPlace(frequentPlaceId: id);
if (!ref.mounted) return false;
unawaited(_tracking.legacyLocationFrequentPlaceDeleted());
state = state.copyWith(
frequentPlaces: state.frequentPlaces.where((f) => f.id != id).toList(),
successMessage: LocationSuccessEvent.frequentPlaceDeleted,
@@ -268,6 +291,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
to: to,
);
if (!ref.mounted) return;
unawaited(_tracking.legacyLocationHistoryLoaded());
state = state.copyWith(
positionHistory: positions,
isLoadingHistory: false,
@@ -287,7 +313,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
}
void toggleRouteTrail() {
state = state.copyWith(showRouteTrail: !state.showRouteTrail);
final newVisible = !state.showRouteTrail;
unawaited(_tracking.legacyLocationMapRouteTrailToggled(newVisible));
state = state.copyWith(showRouteTrail: newVisible);
}
Future<bool> updateLocationFrequency({required int frequency}) async {
@@ -307,6 +335,9 @@ class LocationViewModel extends Notifier<LocationViewState> {
if (!ref.mounted) return false;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacyLocationFrequencyUpdated(frequency));
state = state.copyWith(isSubmitting: false);
return true;
} catch (e) {

View File

@@ -23,6 +23,8 @@ dependencies:
path: ../../packages/legacy_shared
sf_shared:
path: ../../../../packages/sf_shared
sf_tracking:
path: ../../../../packages/sf_tracking
utils:
path: ../../../../packages/utils
get_it: ^9.0.5

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:settings/src/core/data/models/create_alarm_request_model.dart';
@@ -7,6 +9,7 @@ import 'package:settings/src/core/providers/alarm_repository_provider.dart';
import 'package:settings/src/features/alarm/domain/entities/alarm_entity.dart';
import 'package:settings/src/features/alarm/presentation/state/alarm_view_state.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:uuid/uuid.dart';
final alarmViewModelProvider =
@@ -16,10 +19,12 @@ final alarmViewModelProvider =
class AlarmViewModel extends Notifier<AlarmViewState> {
late final AlarmRepository _repository;
late final SfTrackingRepository _tracking;
@override
AlarmViewState build() {
_repository = ref.read(alarmRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const AlarmViewState();
}
@@ -63,6 +68,8 @@ class AlarmViewModel extends Notifier<AlarmViewState> {
order: state.alarms.length + 1,
);
unawaited(_tracking.legacySettingsAlarmAdded());
state = state.copyWith(
alarms: [...state.alarms, updatedAlarm],
isSaving: false,
@@ -93,6 +100,8 @@ class AlarmViewModel extends Notifier<AlarmViewState> {
.map((a) => a.id == alarm.id ? alarm : a)
.toList();
unawaited(_tracking.legacySettingsAlarmUpdated());
state = state.copyWith(
alarms: updatedAlarms,
isSaving: false,
@@ -114,6 +123,8 @@ class AlarmViewModel extends Notifier<AlarmViewState> {
final updatedAlarms = state.alarms.where((a) => a.id != alarmId).toList();
unawaited(_tracking.legacySettingsAlarmRemoved());
state = state.copyWith(
alarms: updatedAlarms,
isSaving: false,

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'alerts_view_state.dart';
@@ -10,10 +13,12 @@ final alertsViewModelProvider =
class AlertsViewModel extends Notifier<AlertsViewState> {
late final DeviceSettingsUpdateDatasource _datasource;
late final SfTrackingRepository _tracking;
@override
AlertsViewState build() {
_datasource = ref.read(deviceSettingsUpdateProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const AlertsViewState();
}
@@ -62,6 +67,9 @@ class AlertsViewModel extends Notifier<AlertsViewState> {
);
if (!ref.mounted) return;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacySettingsAlertsConfigured());
state = state.copyWith(isSaving: false, saveSuccess: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'battery_view_state.dart';
@@ -10,10 +13,12 @@ final batteryViewModelProvider =
class BatteryViewModel extends Notifier<BatteryViewState> {
late final DeviceSettingsUpdateDatasource _datasource;
late final SfTrackingRepository _tracking;
@override
BatteryViewState build() {
_datasource = ref.read(deviceSettingsUpdateProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const BatteryViewState();
}
@@ -46,6 +51,9 @@ class BatteryViewModel extends Notifier<BatteryViewState> {
);
if (!ref.mounted) return;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacySettingsBatteryNightModeToggled(value));
state = state.copyWith(
nightMode: value,
isSaving: false,

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:settings/src/core/domain/entities/contact_list_contact_entity.dart';
@@ -5,6 +7,7 @@ import 'package:settings/src/core/domain/repositories/block_phone_repository.dar
import 'package:settings/src/core/providers/block_phone_repository_provider.dart';
import 'package:settings/src/features/block_phone/presentation/state/block_phone_view_state.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
final blockPhoneViewModelProvider =
NotifierProvider.autoDispose<BlockPhoneViewModel, BlockPhoneViewState>(
@@ -13,10 +16,12 @@ final blockPhoneViewModelProvider =
class BlockPhoneViewModel extends Notifier<BlockPhoneViewState> {
late final BlockPhoneRepository _repository;
late final SfTrackingRepository _tracking;
@override
BlockPhoneViewState build() {
_repository = ref.read(blockPhoneRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const BlockPhoneViewState();
}
@@ -51,6 +56,8 @@ class BlockPhoneViewModel extends Notifier<BlockPhoneViewState> {
contacts: updatedContacts,
);
unawaited(_tracking.legacySettingsBlockPhoneContactAdded());
state = state.copyWith(
contacts: updatedContacts,
isSaving: false,
@@ -79,6 +86,8 @@ class BlockPhoneViewModel extends Notifier<BlockPhoneViewState> {
contacts: updatedContacts,
);
unawaited(_tracking.legacySettingsBlockPhoneContactRemoved());
state = state.copyWith(
contacts: updatedContacts,
isSaving: false,

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'disable_functions_view_state.dart';
@@ -11,10 +14,12 @@ final disableFunctionsViewModelProvider =
class DisableFunctionsViewModel extends Notifier<DisableFunctionsViewState> {
late final DeviceSettingsUpdateDatasource _datasource;
late final SfTrackingRepository _tracking;
@override
DisableFunctionsViewState build() {
_datasource = ref.read(deviceSettingsUpdateProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const DisableFunctionsViewState();
}
@@ -59,6 +64,13 @@ class DisableFunctionsViewModel extends Notifier<DisableFunctionsViewState> {
);
if (!ref.mounted) return;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacySettingsDisableFunctionsChanged());
unawaited(
_tracking.legacySettingsDisableFunctionsKeyboardToggled(state.keyboard),
);
unawaited(_tracking.legacySettingsDisableFunctionsGpsToggled(state.gps));
state = state.copyWith(isSaving: false, saveSuccess: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,7 +1,10 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:settings/src/core/domain/repositories/language_repository.dart';
import 'package:settings/src/core/providers/language_repository_provider.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'language_view_state.dart';
final languageViewModelProvider =
@@ -11,10 +14,12 @@ final languageViewModelProvider =
class LanguageViewModel extends Notifier<LanguageViewState> {
late final LanguageRepository _languageRepository;
late final SfTrackingRepository _tracking;
@override
LanguageViewState build() {
_languageRepository = ref.read(languageRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(() => load());
return const LanguageViewState(isLoading: true);
}
@@ -61,6 +66,9 @@ class LanguageViewModel extends Notifier<LanguageViewState> {
device,
device.settings.copyWith(language: state.language),
);
unawaited(_tracking.legacySettingsLanguageChanged(state.language));
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:settings/src/core/domain/entities/contact_list_contact_entity.dart';
@@ -5,6 +7,7 @@ import 'package:settings/src/core/domain/repositories/sos_contacts_repository.da
import 'package:settings/src/core/providers/sos_contacts_repository_provider.dart';
import 'package:settings/src/features/sos_contacts/presentation/state/sos_contacts_view_state.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
final sosContactsViewModelProvider =
NotifierProvider.autoDispose<SosContactsViewModel, SosContactsViewState>(
@@ -13,10 +16,12 @@ final sosContactsViewModelProvider =
class SosContactsViewModel extends Notifier<SosContactsViewState> {
late final SosContactsRepository _repository;
late final SfTrackingRepository _tracking;
@override
SosContactsViewState build() {
_repository = ref.read(sosContactsRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const SosContactsViewState();
}
@@ -53,6 +58,8 @@ class SosContactsViewModel extends Notifier<SosContactsViewState> {
contacts: updatedContacts,
);
unawaited(_tracking.legacySettingsSosContactAdded());
state = state.copyWith(
contacts: updatedContacts,
isSaving: false,
@@ -81,6 +88,8 @@ class SosContactsViewModel extends Notifier<SosContactsViewState> {
contacts: updatedContacts,
);
unawaited(_tracking.legacySettingsSosContactRemoved());
state = state.copyWith(
contacts: updatedContacts,
isSaving: false,

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'sound_view_state.dart';
@@ -10,10 +13,12 @@ final soundViewModelProvider =
class SoundViewModel extends Notifier<SoundViewState> {
late final DeviceSettingsUpdateDatasource _datasource;
late final SfTrackingRepository _tracking;
@override
SoundViewState build() {
_datasource = ref.read(deviceSettingsUpdateProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(() => load());
return const SoundViewState();
}
@@ -61,6 +66,9 @@ class SoundViewModel extends Notifier<SoundViewState> {
if (!ref.mounted) return;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacySettingsSoundChanged());
state = state.copyWith(isLoading: false, isComplete: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,6 +1,9 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../domain/sync_clock_use_case.dart';
import '../providers/set_sound_use_case_provider.dart';
@@ -13,10 +16,12 @@ final syncClockViewModelProvider =
class SyncClockViewModel extends Notifier<SyncClockViewState> {
late final SyncClockUseCase _syncClockUseCase;
late final SfTrackingRepository _tracking;
@override
SyncClockViewState build() {
_syncClockUseCase = ref.read(syncClockUseCaseProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(() => load());
@@ -38,6 +43,7 @@ class SyncClockViewModel extends Notifier<SyncClockViewState> {
try {
state = state.copyWith(isLoading: true);
_syncClockUseCase.syncClock(deviceId: state.deviceId);
unawaited(_tracking.legacySettingsSyncClockTriggered());
} catch (e) {
state = state.copyWith(isLoading: false, errorMessage: e.toString());
}

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'timezone_view_state.dart';
@@ -10,10 +13,12 @@ final timezoneViewModelProvider =
class TimezoneViewModel extends Notifier<TimezoneViewState> {
late final DeviceSettingsUpdateDatasource _datasource;
late final SfTrackingRepository _tracking;
@override
TimezoneViewState build() {
_datasource = ref.read(deviceSettingsUpdateProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const TimezoneViewState();
}
@@ -57,6 +62,11 @@ class TimezoneViewModel extends Notifier<TimezoneViewState> {
);
if (!ref.mounted) return;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(
_tracking.legacySettingsTimezoneChanged(state.timezone.toString()),
);
state = state.copyWith(isSaving: false, saveSuccess: true);
} catch (e) {
if (!ref.mounted) return;

View File

@@ -1,6 +1,9 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/domain/repositories/wifi_repository.dart';
import '../../../../core/providers/wifi_repository_provider.dart';
@@ -13,10 +16,12 @@ final wifiSettingsViewModelProvider =
class WifiSettingsViewModel extends Notifier<WifiSettingsViewState> {
late final WifiRepository _repository;
late final SfTrackingRepository _tracking;
@override
WifiSettingsViewState build() {
_repository = ref.read(wifiRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future.microtask(_load);
return const WifiSettingsViewState();
}
@@ -51,6 +56,8 @@ class WifiSettingsViewModel extends Notifier<WifiSettingsViewState> {
final networks = await _repository.getWifiNetworks(deviceId: device.id);
unawaited(_tracking.legacySettingsWifiAdded());
state = state.copyWith(
networks: networks,
isSaving: false,
@@ -75,6 +82,8 @@ class WifiSettingsViewModel extends Notifier<WifiSettingsViewState> {
final networks = await _repository.getWifiNetworks(deviceId: device.id);
unawaited(_tracking.legacySettingsWifiRemoved());
state = state.copyWith(
networks: networks,
isSaving: false,

View File

@@ -28,6 +28,8 @@ dependencies:
#modules dependencies go here
#packages dependencies go here
sf_tracking:
path: ../../../../packages/sf_tracking
design_system:
path: ../../../../packages/design_system
navigation: