import 'dart:async'; import 'dart:math'; import 'package:Intaleq/controller/functions/crud.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/onbording_page.dart'; import 'package:Intaleq/views/auth/login_page.dart'; import 'package:Intaleq/controller/auth/login_controller.dart'; import 'package:Intaleq/controller/functions/secure_storage.dart'; import 'package:quick_actions/quick_actions.dart'; import '../../../constant/notification.dart'; import '../../../main.dart'; import '../firebase/firbase_messge.dart'; import '../firebase/local_notification.dart'; import '../functions/encrypt_decrypt.dart'; class SplashScreenController extends GetxController with GetTickerProviderStateMixin { late AnimationController _animationController; late Animation titleFadeAnimation, titleScaleAnimation, taglineFadeAnimation, footerFadeAnimation; late Animation taglineSlideAnimation; final progress = 0.0.obs; Timer? _progressTimer; @override void onInit() { super.onInit(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 2000)); // Animation definitions titleFadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.0, 0.5, curve: Curves.easeOut))); titleScaleAnimation = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.0, 0.5, curve: Curves.easeOut))); taglineFadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.3, 0.8, curve: Curves.easeOut))); taglineSlideAnimation = Tween(begin: const Offset(0, 0.5), end: Offset.zero).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.3, 0.8, curve: Curves.easeOut))); footerFadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _animationController, curve: const Interval(0.5, 1.0, curve: Curves.easeOut))); _animationController.forward(); _initializeApp(); } Future _initializeApp() async { _startProgressAnimation(); // Run navigation logic and background services in parallel. final logicFuture = _performNavigationLogic(); final backgroundServicesFuture = _initializeBackgroundServices(); // Ensure the splash screen is visible for a minimum duration. final minTimeFuture = Future.delayed(const Duration(seconds: 3)); // Wait for all tasks to complete. await Future.wait([logicFuture, backgroundServicesFuture, minTimeFuture]); } void _startProgressAnimation() { // Visual timer for the progress bar. const totalTime = 2800; // ms const interval = 50; // ms int elapsed = 0; _progressTimer = Timer.periodic(const Duration(milliseconds: interval), (timer) { elapsed += interval; progress.value = (elapsed / totalTime).clamp(0.0, 1.0); if (elapsed >= totalTime) timer.cancel(); }); } /// Initializes all heavy background services while the splash animation is running. Future _initializeBackgroundServices() async { try { await EncryptionHelper.initialize(); // --- [LAZY LOADING IN ACTION] --- // This `Get.find()` call will create the NotificationController instance // for the first time because it was defined with `lazyPut`. final notificationController = Get.find(); await notificationController.initNotifications(); // The same happens for FirebaseMessagesController. final fcm = Get.find(); await fcm.requestFirebaseMessagingPermission(); _scheduleDailyNotifications(notificationController); _initializeQuickActions(); } catch (e, st) { CRUD.addError('background_init_error: $e', st.toString(), 'SplashScreen'); } } /// Determines the next screen based on user's login state. Future _performNavigationLogic() async { await _getPackageInfo(); SecureStorage().saveData('iss', 'mobile-app:'); if (box.read(BoxName.onBoarding) == null) { Get.off(() => OnBoardingPage()); } else if (box.read(BoxName.email) != null && box.read(BoxName.phone) != null && box.read(BoxName.isVerified) == '1') { // `Get.find()` creates the LoginController instance here. final loginController = Get.find(); // The loginController itself will handle navigation via Get.offAll() upon success. await loginController.loginUsingCredentials( box.read(BoxName.passengerID).toString(), box.read(BoxName.email).toString(), ); } else { Get.off(() => LoginPage()); } } Future _getPackageInfo() async { try { final info = await PackageInfo.fromPlatform(); box.write(BoxName.packagInfo, info.version); update(); } catch (e) { print("Could not get package info: $e"); } } void _scheduleDailyNotifications(NotificationController controller) { try { final List msgs = passengerMessages ?? const []; if (msgs.isEmpty) { controller.scheduleNotificationsForSevenDays( 'Intaleq', 'مرحباً بك! تابع رحلاتك بأمان مع انطلق.', "tone1"); } else { final rnd = Random(); final raw = msgs[rnd.nextInt(msgs.length)]; final parts = raw.split(':'); final title = parts.isNotEmpty ? parts.first.trim() : 'Intaleq'; final body = parts.length > 1 ? parts.sublist(1).join(':').trim() : 'مرحباً بك! تابع رحلاتك بأمان مع انطلق.'; controller.scheduleNotificationsForSevenDays( title.isEmpty ? 'Intaleq' : title, body.isEmpty ? 'مرحباً بك! تابع رحلاتك بأمان مع انطلق.' : body, "tone1"); } } catch (e, st) { CRUD.addError('notif_init: $e', st.toString(), 'SplashScreen'); } } void _initializeQuickActions() { final QuickActions quickActions = QuickActions(); quickActions.initialize((String shortcutType) { Get.toNamed('/$shortcutType'); }); quickActions.setShortcutItems([ ShortcutItem( type: 'shareApp', localizedTitle: 'Share App'.tr, icon: 'icon_share'), ShortcutItem( type: 'wallet', localizedTitle: 'Wallet'.tr, icon: 'icon_wallet'), ShortcutItem( type: 'profile', localizedTitle: 'Profile'.tr, icon: 'icon_user'), ShortcutItem( type: 'contactSupport', localizedTitle: 'Contact Support'.tr, icon: 'icon_support'), ]); } @override void onClose() { _progressTimer?.cancel(); _animationController.dispose(); super.onClose(); } }