|
|
|
|
@ -11,6 +11,7 @@ import 'package:flutter/services.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/api/api_client.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/api_consts.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/app_state.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/cache_consts.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/enums.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
|
|
|
|
@ -55,11 +56,14 @@ import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_mode
|
|
|
|
|
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_view_model.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/presentation/home/navigation_screen.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/presentation/tele_consultation/zoom/call_screen.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/routes/app_routes.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/services/app_lifecycle_service.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/services/navigation_service.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/services/security_service.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/splashPage.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/theme/app_theme.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/unsafe_device.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_calendar_model.dart';
|
|
|
|
|
@ -142,13 +146,13 @@ Future<void> callInitializations() async {
|
|
|
|
|
await callAppStateInitializations();
|
|
|
|
|
|
|
|
|
|
// Initialize Security Service early to catch threats before app logic runs
|
|
|
|
|
if (kReleaseMode) {
|
|
|
|
|
try {
|
|
|
|
|
await getIt.get<SecurityService>().initialize();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
getIt.get<LoggerService>().logError('SecurityService.initialize failed, continuing app startup: $e');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if (kReleaseMode) {
|
|
|
|
|
// try {
|
|
|
|
|
// await getIt.get<SecurityService>().initialize();
|
|
|
|
|
// } catch (e) {
|
|
|
|
|
// getIt.get<LoggerService>().logError('SecurityService.initialize failed, continuing app startup: $e');
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Set up critical threat callback to navigate to unsafe device page
|
|
|
|
|
getIt.get<SecurityService>().setOnCriticalThreatCallback(() {
|
|
|
|
|
@ -386,6 +390,16 @@ class MyApp extends StatelessWidget {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String? _extractJoinSessionId(String? routeName) {
|
|
|
|
|
if (routeName == null || routeName.isEmpty) return null;
|
|
|
|
|
// Matches both "https://hmgapps.com/join/{id}" and "/join/{id}"
|
|
|
|
|
final match = RegExp(r'/join/([^?#]+)').firstMatch(routeName);
|
|
|
|
|
if (match != null && match.group(1)!.isNotEmpty) {
|
|
|
|
|
return Uri.decodeComponent(match.group(1)!);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return SafeArea(
|
|
|
|
|
@ -422,6 +436,51 @@ class MyApp extends StatelessWidget {
|
|
|
|
|
locale: context.locale,
|
|
|
|
|
initialRoute: AppRoutes.initialRoute,
|
|
|
|
|
routes: AppRoutes.routes,
|
|
|
|
|
onGenerateInitialRoutes: (String initialRouteName) {
|
|
|
|
|
final defaultRoute = WidgetsBinding.instance.platformDispatcher.defaultRouteName;
|
|
|
|
|
final sessionId = _extractJoinSessionId(initialRouteName) ?? _extractJoinSessionId(defaultRoute);
|
|
|
|
|
if (sessionId != null) {
|
|
|
|
|
getIt.get<AppState>().deepLinkJoinSessionId = sessionId;
|
|
|
|
|
Utils.saveStringFromPrefs(CacheConst.zoomRoomID, sessionId);
|
|
|
|
|
debugPrint('DeepLink (Cold Start) Join Session ID: $sessionId');
|
|
|
|
|
}
|
|
|
|
|
return [
|
|
|
|
|
MaterialPageRoute(builder: (_) => const SplashPage()),
|
|
|
|
|
];
|
|
|
|
|
},
|
|
|
|
|
onGenerateRoute: (RouteSettings settings) {
|
|
|
|
|
final sessionId = _extractJoinSessionId(settings.name);
|
|
|
|
|
if (sessionId != null) {
|
|
|
|
|
final appState = getIt.get<AppState>();
|
|
|
|
|
Utils.saveStringFromPrefs(CacheConst.zoomRoomID, sessionId);
|
|
|
|
|
debugPrint('DeepLink (Route) Join Session ID: $sessionId');
|
|
|
|
|
// If SplashPage is still initializing, save it so SplashPage navigates when ready
|
|
|
|
|
if (!appState.isSplashInitializationDone) {
|
|
|
|
|
appState.deepLinkJoinSessionId = sessionId;
|
|
|
|
|
return MaterialPageRoute(builder: (_) => const SplashPage());
|
|
|
|
|
}
|
|
|
|
|
// Warm Start: App is already initialized, open CallScreen directly
|
|
|
|
|
return MaterialPageRoute(
|
|
|
|
|
settings: RouteSettings(
|
|
|
|
|
name: AppRoutes.zoomCallPage,
|
|
|
|
|
arguments: CallArguments(sessionId, "123", "Patient", "40", "0", true, 1),
|
|
|
|
|
),
|
|
|
|
|
builder: (_) => const CallScreen(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// Fallback for normal named routes if any reach onGenerateRoute
|
|
|
|
|
final builder = AppRoutes.routes[settings.name];
|
|
|
|
|
if (builder != null) {
|
|
|
|
|
return MaterialPageRoute(builder: builder, settings: settings);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
onUnknownRoute: (RouteSettings settings) {
|
|
|
|
|
// Prevents crash when opened via root link https://hmgapps.com
|
|
|
|
|
return MaterialPageRoute(
|
|
|
|
|
builder: (_) => getIt.get<AppState>().isSplashInitializationDone ? LandingNavigation() : const SplashPage(),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
theme: AppTheme.getTheme(isArabic),
|
|
|
|
|
darkTheme: AppTheme.getDarkTheme(isArabic),
|
|
|
|
|
themeMode: profileVm.isDarkMode ? ThemeMode.dark : ThemeMode.light,
|
|
|
|
|
|