Merge remote-tracking branch 'origin/feature/remote-management' into feature/remote-management

This commit is contained in:
2026-03-16 12:47:18 +01:00
8 changed files with 230 additions and 45 deletions

View File

@@ -26,7 +26,7 @@ late final GoRouter appRouter;
void configureAppRouter() {
appRouter = GoRouter(
navigatorKey: rootNavigatorKey,
initialLocation: AppRoutes.onboarding,
initialLocation: AppRoutes.splash,
debugLogDiagnostics: true,
routes: [
GoRoute(

View File

@@ -0,0 +1,42 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
class LegacyHeartbeatService {
LegacyHeartbeatService({
required QuestiaRepository repository,
required void Function() onUnauthorized,
}) : _repository = repository,
_onUnauthorized = onUnauthorized;
final QuestiaRepository _repository;
final void Function() _onUnauthorized;
Timer? _timer;
static const _interval = Duration(minutes: 3);
void start() {
if (_timer != null) return;
_beat();
_timer = Timer.periodic(_interval, (_) => _beat());
debugPrint('[LegacyHeartbeat] started');
}
void stop() {
_timer?.cancel();
_timer = null;
debugPrint('[LegacyHeartbeat] stopped');
}
Future<void> _beat() async {
try {
await _repository.get<dynamic>('/auth/me');
debugPrint('[LegacyHeartbeat] /auth/me => OK');
} catch (e) {
debugPrint('[LegacyHeartbeat] error: $e');
stop();
_onUnauthorized();
}
}
}

View File

@@ -6,7 +6,9 @@ import 'package:sf_app_platform/navigation/app_router.dart';
import 'package:navigation/navigation.dart';
import 'package:sf_app_platform/providers/app_state_provider.dart';
import 'package:sf_app_platform/providers/permissions/permissions_provider.dart';
import 'package:sf_app_platform/providers/legacy_heartbeat_service.dart';
import 'package:sf_app_platform/providers/wallet_heartbeat_service.dart';
import 'package:get_it/get_it.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_localizations/sf_localizations.dart';
@@ -23,6 +25,7 @@ class SaveFamilyApp extends ConsumerStatefulWidget {
class SaveFamilyAppState extends ConsumerState<SaveFamilyApp>
with WidgetsBindingObserver {
late final WalletHeartbeatService walletHeartbeat;
late final LegacyHeartbeatService legacyHeartbeat;
@override
void initState() {
@@ -33,13 +36,25 @@ class SaveFamilyAppState extends ConsumerState<SaveFamilyApp>
sessionLocal: SessionLocalDatasourceImpl(),
onError: () => appRouter.go(AppRoutes.scaTreezor),
);
onBeforeSessionCleared = walletHeartbeat.stop;
legacyHeartbeat = LegacyHeartbeatService(
repository: GetIt.I<QuestiaRepository>(),
onUnauthorized: () {
clearSessionData();
appRouter.go(AppRoutes.legacyLogin);
},
);
onBeforeSessionCleared = () {
walletHeartbeat.stop();
legacyHeartbeat.stop();
};
// walletHeartbeat.start();
legacyHeartbeat.start();
}
@override
void dispose() {
walletHeartbeat.stop();
legacyHeartbeat.stop();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@@ -50,9 +65,11 @@ class SaveFamilyAppState extends ConsumerState<SaveFamilyApp>
ref.read(appLifecycleStateProvider.notifier).setState(state);
if (state == AppLifecycleState.resumed) {
// walletHeartbeat.start();
legacyHeartbeat.start();
ref.read(permissionsProvider.notifier).checkPermissions();
} else if (state == AppLifecycleState.paused) {
// walletHeartbeat.stop();
legacyHeartbeat.stop();
}
super.didChangeAppLifecycleState(state);
}

View File

@@ -26,14 +26,14 @@ class AccountSettingsScreen extends ConsumerWidget {
accountSettingsViewModelProvider.select((s) => s.isLoggingOut),
);
ref.listen(
accountSettingsViewModelProvider.select((s) => s.isLoggingOut),
(prev, isLoggingOut) {
if (prev == true && !isLoggingOut) {
navigationContract.goTo(AppRoutes.legacyLogin);
}
},
);
ref.listen(accountSettingsViewModelProvider.select((s) => s.isLoggingOut), (
prev,
isLoggingOut,
) {
if (prev == true && !isLoggingOut) {
navigationContract.goTo(AppRoutes.legacyLogin);
}
});
return LegacyPageLayout(
theme: theme,
@@ -46,11 +46,39 @@ class AccountSettingsScreen extends ConsumerWidget {
),
child: Column(
children: [
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.personalData), icon: SFIcons.account, text: I18n.personalData, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.changePassword), icon: Icons.lock, text: I18n.changePassword, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.legacyDeviceSetup), icon: Icons.add_circle_outline, text: I18n.addNewSF, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.linkedDevices), icon: Icons.account_circle_outlined, text: I18n.linkedDevices, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.appUsers), icon: Icons.groups_outlined, text: I18n.appUsers, color: color),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.personalData),
icon: SFIcons.account,
text: I18n.personalData,
color: color,
),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.changePassword),
icon: Icons.lock,
text: I18n.changePassword,
color: color,
),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.legacyDeviceSetup),
icon: Icons.add_circle_outline,
text: I18n.addNewSF,
color: color,
),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.linkedDevices),
icon: Icons.account_circle_outlined,
text: I18n.linkedDevices,
color: color,
),
// _item(context, onPressed: () => navigationContract.pushTo(AppRoutes.appUsers), icon: Icons.groups_outlined, text: I18n.appUsers, color: color),
_item(
context,
onPressed: () async {
@@ -82,7 +110,14 @@ class AccountSettingsScreen extends ConsumerWidget {
text: I18n.regCode,
color: color,
),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.deleteAccount), icon: Icons.no_accounts, text: I18n.deleteAccount, color: color),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.deleteAccount),
icon: Icons.no_accounts,
text: I18n.deleteAccount,
color: color,
),
],
),
),
@@ -121,7 +156,9 @@ class AccountSettingsScreen extends ConsumerWidget {
required Color color,
}) {
return Padding(
padding: EdgeInsets.only(bottom: SizeUtils.getByScreen(small: 16, big: 15)),
padding: EdgeInsets.only(
bottom: SizeUtils.getByScreen(small: 16, big: 15),
),
child: SectionButton(
onPressed: onPressed,
icon: Icon(

View File

@@ -27,14 +27,14 @@ class DeviceManagementScreen extends ConsumerWidget {
),
child: Column(
children: [
AppMenuButton(
color: theme.getColorFor(ThemeCode.legacyPrimary),
onPressed: () =>
navigationContract.pushTo(AppRoutes.remoteConnection),
icon: SFIcons.connection,
text: context.translate(I18n.remoteConnection),
),
SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)),
// AppMenuButton(
// color: theme.getColorFor(ThemeCode.legacyPrimary),
// onPressed: () =>
// navigationContract.pushTo(AppRoutes.remoteConnection),
// icon: SFIcons.connection,
// text: context.translate(I18n.remoteConnection),
// ),
// SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)),
AppMenuButton(
color: theme.getColorFor(ThemeCode.legacyPrimary),
onPressed: () =>
@@ -106,8 +106,7 @@ class DeviceManagementScreen extends ConsumerWidget {
SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)),
AppMenuButton(
color: theme.getColorFor(ThemeCode.legacyPrimary),
onPressed: () =>
navigationContract.pushTo(AppRoutes.appsUse),
onPressed: () => navigationContract.pushTo(AppRoutes.appsUse),
icon: SFIcons.screenTime,
text: context.translate(I18n.appsUse),
),

View File

@@ -27,21 +27,111 @@ class SettingsScreen extends ConsumerWidget {
),
child: Column(
children: [
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.alarm), icon: Icons.notifications_outlined, text: I18n.alarm, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.appStore), icon: Icons.apps_rounded, text: I18n.appStore, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.blockPhone), icon: Icons.phone_outlined, text: I18n.blockPhone, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.timezone), icon: Icons.check, text: I18n.timezone, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.language), icon: Icons.translate_outlined, text: I18n.language, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.battery), icon: Icons.nightlight_outlined, text: I18n.battery, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.remoteManagement), icon: Icons.settings_remote_outlined, text: I18n.remoteManagement, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.legacyNotifications), icon: Icons.message_outlined, text: I18n.legacyNotifications, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.smsAlert), icon: Icons.sms_outlined, text: I18n.smsAlert, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.sosContacts), icon: Icons.perm_contact_calendar_outlined, text: I18n.sosContacts, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.sound), icon: Icons.volume_up_outlined, text: I18n.sound, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.wifiSettings), icon: Icons.wifi_find_outlined, text: I18n.wifiSettings, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.remoteOnOff), icon: Icons.settings_power_outlined, text: I18n.remoteOnOff, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.disableFunctions), icon: Icons.dashboard_customize_outlined, text: I18n.disableFunctions, color: color),
_item(context, onPressed: () => navigationContract.pushTo(AppRoutes.syncClock), icon: Icons.share_arrival_time_outlined, text: I18n.syncClock, color: color),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.alarm),
icon: Icons.notifications_outlined,
text: I18n.alarm,
color: color,
),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.appStore),
icon: Icons.apps_rounded,
text: I18n.appStore,
color: color,
),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.blockPhone),
icon: Icons.phone_outlined,
text: I18n.blockPhone,
color: color,
),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.timezone),
icon: Icons.check,
text: I18n.timezone,
color: color,
),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.language),
icon: Icons.translate_outlined,
text: I18n.language,
color: color,
),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.battery),
icon: Icons.nightlight_outlined,
text: I18n.battery,
color: color,
),
// _item(context, onPressed: () => navigationContract.pushTo(AppRoutes.remoteManagement), icon: Icons.settings_remote_outlined, text: I18n.remoteManagement, color: color),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.legacyNotifications),
icon: Icons.message_outlined,
text: I18n.legacyNotifications,
color: color,
),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.smsAlert),
icon: Icons.sms_outlined,
text: I18n.smsAlert,
color: color,
),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.sosContacts),
icon: Icons.perm_contact_calendar_outlined,
text: I18n.sosContacts,
color: color,
),
// _item(
// context,
// onPressed: () => navigationContract.pushTo(AppRoutes.sound),
// icon: Icons.volume_up_outlined,
// text: I18n.sound,
// color: color,
// ),
// _item(
// context,
// onPressed: () =>
// navigationContract.pushTo(AppRoutes.wifiSettings),
// icon: Icons.wifi_find_outlined,
// text: I18n.wifiSettings,
// color: color,
// ),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.remoteOnOff),
icon: Icons.settings_power_outlined,
text: I18n.remoteOnOff,
color: color,
),
_item(
context,
onPressed: () =>
navigationContract.pushTo(AppRoutes.disableFunctions),
icon: Icons.dashboard_customize_outlined,
text: I18n.disableFunctions,
color: color,
),
_item(
context,
onPressed: () => navigationContract.pushTo(AppRoutes.syncClock),
icon: Icons.share_arrival_time_outlined,
text: I18n.syncClock,
color: color,
),
],
),
),

View File

@@ -12,7 +12,7 @@ class CheckSessionUseCaseImpl implements CheckSessionUseCase {
@override
Future<InitialRoute> execute() async {
try {
await _userRepository.getChildProfiles();
await _userRepository.getUserInfo();
return InitialRoute.home;
} catch (e) {
debugPrint('[CheckSessionUseCase] error: $e');

View File

@@ -53,8 +53,8 @@ class _SplashScreenState extends State<SplashScreen>
if (!_animationDone || _route == null || !mounted) return;
final destination = switch (_route!) {
InitialRoute.login => AppRoutes.login,
InitialRoute.home => AppRoutes.dashboardHome,
InitialRoute.login => AppRoutes.legacyLogin,
InitialRoute.home => AppRoutes.controlPanel,
};
widget.navigationContract.goTo(destination);
}