25-10-5/1
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
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';
|
||||
@@ -7,22 +9,21 @@ 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:Intaleq/views/widgets/my_scafold.dart';
|
||||
import 'package:Intaleq/constant/style.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';
|
||||
|
||||
import '../../main.dart';
|
||||
|
||||
// كنترولر مع منطق تحميل محسن ينتظر العمليات غير المتزامنة
|
||||
class SplashScreenController extends GetxController
|
||||
with GetTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
|
||||
// الحركات الخاصة بكل عنصر من عناصر الواجهة
|
||||
late Animation<double> titleFadeAnimation;
|
||||
late Animation<double> titleScaleAnimation;
|
||||
late Animation<double> taglineFadeAnimation;
|
||||
late Animation<double> titleFadeAnimation,
|
||||
titleScaleAnimation,
|
||||
taglineFadeAnimation,
|
||||
footerFadeAnimation;
|
||||
late Animation<Offset> taglineSlideAnimation;
|
||||
late Animation<double> footerFadeAnimation;
|
||||
|
||||
final progress = 0.0.obs;
|
||||
Timer? _progressTimer;
|
||||
@@ -30,111 +31,160 @@ class SplashScreenController extends GetxController
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 2000),
|
||||
);
|
||||
vsync: this, duration: const Duration(milliseconds: 2000));
|
||||
|
||||
// --- تعريف الحركات المتتالية ---
|
||||
// Animation definitions
|
||||
titleFadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.0, 0.5, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.0, 0.5, curve: Curves.easeOut)));
|
||||
titleScaleAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.0, 0.5, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.0, 0.5, curve: Curves.easeOut)));
|
||||
taglineFadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.3, 0.8, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.3, 0.8, curve: Curves.easeOut)));
|
||||
taglineSlideAnimation =
|
||||
Tween<Offset>(begin: const Offset(0, 0.5), end: Offset.zero).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.3, 0.8, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.3, 0.8, curve: Curves.easeOut)));
|
||||
footerFadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.5, 1.0, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.5, 1.0, curve: Curves.easeOut)));
|
||||
|
||||
_animationController.forward();
|
||||
|
||||
// بدء عملية التهيئة والتحميل
|
||||
_initializeApp();
|
||||
}
|
||||
|
||||
/// تهيئة التطبيق وانتظار انتهاء التحميل قبل الانتقال
|
||||
Future<void> _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));
|
||||
|
||||
// الانتظار حتى انتهاء المهمتين معاً
|
||||
await Future.wait([logicFuture, minTimeFuture]);
|
||||
|
||||
// بعد انتهاء الانتظار، سيتم الانتقال تلقائياً من داخل a_performNavigationLogic
|
||||
// Wait for all tasks to complete.
|
||||
await Future.wait([logicFuture, backgroundServicesFuture, minTimeFuture]);
|
||||
}
|
||||
|
||||
/// تشغيل حركة شريط التقدم بشكل مرئي ومنفصل عن منطق التحميل
|
||||
void _startProgressAnimation() {
|
||||
const totalTime = 2800; // مدة ملء الشريط
|
||||
const interval = 50;
|
||||
// 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();
|
||||
}
|
||||
if (elapsed >= totalTime) timer.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
/// تنفيذ منطق التحميل الفعلي وتسجيل الدخول وتحديد وجهة الانتقال
|
||||
/// Initializes all heavy background services while the splash animation is running.
|
||||
Future<void> _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<NotificationController>();
|
||||
await notificationController.initNotifications();
|
||||
|
||||
// The same happens for FirebaseMessagesController.
|
||||
final fcm = Get.find<FirebaseMessagesController>();
|
||||
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<void> _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') {
|
||||
// -- النقطة الأهم --
|
||||
// هنا ننتظر انتهاء عملية تسجيل الدخول قبل الانتقال
|
||||
await Get.put(LoginController()).loginUsingCredentials(
|
||||
// `Get.find()` creates the LoginController instance here.
|
||||
final loginController = Get.find<LoginController>();
|
||||
// The loginController itself will handle navigation via Get.offAll() upon success.
|
||||
await loginController.loginUsingCredentials(
|
||||
box.read(BoxName.passengerID).toString(),
|
||||
box.read(BoxName.email).toString(),
|
||||
);
|
||||
// بعد هذه العملية، سيتولى LoginController بنفسه الانتقال للصفحة الرئيسية أو صفحة الدخول
|
||||
} else {
|
||||
Get.off(() => LoginPage());
|
||||
}
|
||||
}
|
||||
|
||||
/// جلب معلومات الحزمة لعرض إصدار التطبيق
|
||||
Future<void> _getPackageInfo() async {
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
box.write(BoxName.packagInfo, info.version);
|
||||
update();
|
||||
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<String> 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>[
|
||||
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
|
||||
@@ -144,40 +194,3 @@ class SplashScreenController extends GetxController
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
// يمكن الإبقاء على هذه الفئة لواجهة المستخدم المتعلقة بالأمان كما في الملف الأصلي
|
||||
class SecurityPage extends StatelessWidget {
|
||||
const SecurityPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MyScafolld(
|
||||
title: "security_warning".tr,
|
||||
body: [
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"security_message".tr,
|
||||
style: AppStyle.headTitle2,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
// await SecurityHelper.clearAllData();
|
||||
},
|
||||
child: Text(
|
||||
"security_warning".tr,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
isleading: false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user