import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:sefer_driver/views/home/Captin/orderCaptin/order_request_page.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart' as tz; import '../../constant/box_name.dart'; import '../../main.dart'; import '../../print.dart'; import '../../views/notification/notification_captain.dart'; import '../home/captin/home_captain_controller.dart'; class NotificationController extends GetxController { final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); Future initNotifications() async { const AndroidInitializationSettings android = AndroidInitializationSettings('@mipmap/launcher_icon'); DarwinInitializationSettings ios = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, // onDidReceiveLocalNotification: // (int id, String? title, String? body, String? payload) async {}, ); InitializationSettings initializationSettings = InitializationSettings(android: android, iOS: ios); tz.initializeTimeZones(); print('Notifications initialized'); await _flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: onDidReceiveNotificationResponse, onDidReceiveBackgroundNotificationResponse: notificationTapBackground, ); // Create a notification channel const AndroidNotificationChannel channel = AndroidNotificationChannel( 'high_importance_channel', // Use the same ID as in strings.xml 'High Importance Notifications', description: 'This channel is used for important notifications.', importance: Importance.high, ); // Register the channel with the system await _flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel); } // Displays a notification with the given title and message void showNotification( String title, String message, String tone, String payLoad) async { BigTextStyleInformation bigTextStyleInformation = BigTextStyleInformation( message, contentTitle: title.tr, htmlFormatContent: true, htmlFormatContentTitle: true, ); AndroidNotificationDetails android = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, sound: RawResourceAndroidNotificationSound(tone), ); DarwinNotificationDetails ios = const DarwinNotificationDetails( sound: 'default', presentAlert: true, presentBadge: true, presentSound: true, ); NotificationDetails details = NotificationDetails(android: android, iOS: ios); await _flutterLocalNotificationsPlugin.show(0, title, message, details, payload: jsonEncode({'title': title, 'data': payLoad})); } void scheduleNotificationAtSpecificTime( String title, String message, String tone, int hour, int minute) async { // Initialize and set Cairo time zone tz.initializeTimeZones(); var cairoLocation; if (box.read(BoxName.countryCode).toString() == 'Egypt') { cairoLocation = tz.getLocation('Africa/Cairo'); } else {} // todo get for location country final AndroidNotificationDetails android = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, showWhen: false, sound: RawResourceAndroidNotificationSound(tone), ); const DarwinNotificationDetails ios = DarwinNotificationDetails( sound: 'default', presentAlert: true, presentBadge: true, presentSound: true, ); final NotificationDetails details = NotificationDetails(android: android, iOS: ios); final now = tz.TZDateTime.now(cairoLocation); // Use Cairo timezone for current time tz.TZDateTime scheduledTime = tz.TZDateTime( cairoLocation, now.year, now.month, now.day, hour, minute); // If the scheduled time has already passed for today, schedule it for the next day if (scheduledTime.isBefore(now)) { scheduledTime = scheduledTime.add(const Duration(days: 1)); } if (Platform.isAndroid) { if (await Permission.scheduleExactAlarm.isDenied) { if (await Permission.scheduleExactAlarm.request().isGranted) { print('SCHEDULE_EXACT_ALARM permission granted'); } else { print('SCHEDULE_EXACT_ALARM permission denied'); return; } } } print('Current time: $now'); print('Scheduling notification for: $scheduledTime'); await _flutterLocalNotificationsPlugin.zonedSchedule( 0, title, message, scheduledTime, details, // androidAllowWhileIdle: true, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: DateTimeComponents.time, androidScheduleMode: AndroidScheduleMode.alarmClock, // Triggers daily at the same time ); print('Notification scheduled successfully'); } void scheduleNotificationAfter1Minute( String title, String message, String tone) async { final AndroidNotificationDetails android = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, showWhen: false, sound: RawResourceAndroidNotificationSound(tone), ); const DarwinNotificationDetails ios = DarwinNotificationDetails( sound: 'default', presentAlert: true, presentBadge: true, presentSound: true, ); final NotificationDetails details = NotificationDetails(android: android, iOS: ios); // Schedule the notification to be shown after 1 minute Timer.periodic(const Duration(seconds: 15), (timer) async { final now = tz.TZDateTime.now(tz.local); final scheduledTime = now.add(const Duration(seconds: 10)); Log.print('scheduledTime: ${scheduledTime}'); if (Platform.isAndroid) { if (await Permission.scheduleExactAlarm.isDenied) { if (await Permission.scheduleExactAlarm.request().isGranted) { print('SCHEDULE_EXACT_ALARM permission granted'); } else { print('SCHEDULE_EXACT_ALARM permission denied'); return; } } } print('Scheduling notification for: $scheduledTime'); await _flutterLocalNotificationsPlugin.zonedSchedule( 0, title, message, scheduledTime, details, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: DateTimeComponents.time, androidScheduleMode: AndroidScheduleMode.alarmClock, ); print('Notification scheduled successfully'); }); } void scheduleNotificationsForSevenDays( String title, String message, String tone) async { final AndroidNotificationDetails android = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, sound: RawResourceAndroidNotificationSound(tone), ); const DarwinNotificationDetails ios = DarwinNotificationDetails( sound: 'default', presentAlert: true, presentBadge: true, presentSound: true, ); final NotificationDetails details = NotificationDetails(android: android, iOS: ios); // Check for the exact alarm permission on Android 12 and above if (Platform.isAndroid) { if (await Permission.scheduleExactAlarm.isDenied) { if (await Permission.scheduleExactAlarm.request().isGranted) { print('SCHEDULE_EXACT_ALARM permission granted'); } else { print('SCHEDULE_EXACT_ALARM permission denied'); return; } } } // Schedule notifications for the next 7 days for (int day = 0; day < 7; day++) { // List of notification times final notificationTimes = [ {'hour': 8, 'minute': 0, 'id': day * 1000 + 1}, // 8:00 AM {'hour': 15, 'minute': 0, 'id': day * 1000 + 2}, // 3:00 PM {'hour': 20, 'minute': 0, 'id': day * 1000 + 3}, // 8:00 PM ]; for (var time in notificationTimes) { final notificationId = time['id'] as int; // Check if this notification ID is already stored bool isScheduled = box.read('notification_$notificationId') ?? false; if (!isScheduled) { // Schedule the notification if not already scheduled await _scheduleNotificationForTime( day, time['hour'] as int, time['minute'] as int, title, message, details, notificationId, ); // Mark this notification ID as scheduled in GetStorage box.write('notification_$notificationId', true); } else { print('Notification with ID $notificationId is already scheduled.'); } } } print('Notifications scheduled successfully for the next 7 days'); } Future _scheduleNotificationForTime( int dayOffset, int hour, int minute, String title, String message, NotificationDetails details, int notificationId, ) async { // Initialize and set Cairo timezone tz.initializeTimeZones(); var cairoLocation = tz.getLocation('Africa/Cairo'); final now = tz.TZDateTime.now(cairoLocation); tz.TZDateTime scheduledDate = tz.TZDateTime( cairoLocation, now.year, now.month, now.day + dayOffset, // Add offset to schedule for the next days hour, minute, ); // If the scheduled time is in the past, move it to the next day if (scheduledDate.isBefore(now)) { scheduledDate = scheduledDate.add(Duration(days: 1)); } print('Current time (Cairo): $now'); print('Scheduling notification for: $scheduledDate'); await _flutterLocalNotificationsPlugin.zonedSchedule( notificationId, // Unique ID for each notification title, message, scheduledDate, details, androidScheduleMode: AndroidScheduleMode.exact, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: null, // Don't repeat automatically; we handle 7 days manually ); print('Notification scheduled successfully for: $scheduledDate'); } void scheduleNotificationEvery10Hours( String title, String message, String tone) async { final AndroidNotificationDetails android = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, showWhen: false, sound: RawResourceAndroidNotificationSound(tone), ); const DarwinNotificationDetails ios = DarwinNotificationDetails( sound: 'default', presentAlert: true, presentBadge: true, presentSound: true, ); final NotificationDetails details = NotificationDetails(android: android, iOS: ios); if (Platform.isAndroid) { if (await Permission.scheduleExactAlarm.isDenied) { if (await Permission.scheduleExactAlarm.request().isGranted) { print('SCHEDULE_EXACT_ALARM permission granted'); } else { print('SCHEDULE_EXACT_ALARM permission denied'); return; } } } Timer.periodic(const Duration(hours: 10), (timer) async { final now = tz.TZDateTime.now(tz.local); final scheduledTime = now.add(const Duration(minutes: 10)); print('Scheduling notification for: $scheduledTime'); await _flutterLocalNotificationsPlugin.zonedSchedule( 0, title.tr, message.tr, scheduledTime, details, // androidAllowWhileIdle: true, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: DateTimeComponents.time, androidScheduleMode: AndroidScheduleMode.alarmClock, ); }); print('Notifications scheduled every 5 seconds'); } void showTimerNotification(String title, String message, String tone) async { final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // Setup Android notification final AndroidNotificationDetails android = AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.max, priority: Priority.high, showWhen: false, sound: RawResourceAndroidNotificationSound( tone), // tone without the file extension ); // Setup iOS notification const DarwinNotificationDetails ios = DarwinNotificationDetails( sound: 'default', presentAlert: true, presentBadge: true, presentSound: true, ); final NotificationDetails details = NotificationDetails(android: android, iOS: ios); // Request permission on Android if (Platform.isAndroid) { if (await Permission.scheduleExactAlarm.isDenied) { if (await Permission.scheduleExactAlarm.request().isGranted) { print('SCHEDULE_EXACT_ALARM permission granted'); } else { print('SCHEDULE_EXACT_ALARM permission denied'); return; } } } // Timer duration (e.g., 120 seconds countdown) int countdown = 12; // Display the notification initially with the full countdown time // Timer to update the notification every second Timer.periodic(const Duration(seconds: 1), (timer) async { // if (countdown > 0) { // Update the existing notification with the updated countdown // Decrease the countdown by 1 countdown--; // } else { // // Cancel the timer when the countdown reaches zero // timer.cancel(); // } }); await flutterLocalNotificationsPlugin.show( 0, title, '$message Remaining: $countdown seconds', // Initial message details, ); print('Notification will update every second'); } // Callback when the notification is tapped void onDidReceiveNotificationResponse(NotificationResponse response) { handleNotificationResponse(response); } // Callback when the notification is tapped while the app is in the background void onDidReceiveBackgroundNotificationResponse( NotificationResponse response) { handleNotificationResponse(response); } // Handle notification response for both foreground and background void handleNotificationResponse(NotificationResponse response) { print('Notification tapped!'); Log.print('response.payload: ${response.payload}'); if (response.payload != null) { print('Notification payload: ${response.payload}'); var payloadData = jsonDecode(response.payload.toString()); if (payloadData is Map) { String title = payloadData['title']; var data = payloadData['data']; switch (title) { case 'Order': _handleOrderNotification(data); break; case 'OrderSpeed': _handleOrderSpeedNotification(data); break; case 'ADS': _handleADSNotification(); break; default: Log.print('Unknown notification type'); } } else { Log.print('Invalid payload format'); } } else { Log.print('Payload is null'); } } void _handleOrderNotification(dynamic data) { if (data is String) { var orderData = jsonDecode(data); if (orderData is List && orderData.length == 34) { //closeOverLay(); Get.put(HomeCaptainController()).changeRideId(); Get.to(() => OrderRequestPage(), arguments: {'myListString': data}); } else { Log.print('Invalid order data'); } } else { Log.print('Invalid order payload'); } } void _handleOrderSpeedNotification(dynamic data) { if (data is String) { var orderData = jsonDecode(data); if (orderData is List && orderData.length == 34) { //closeOverLay(); Get.put(HomeCaptainController()).changeRideId(); Get.to(() => OrderRequestPage(), arguments: {'myListString': data}); } else { Log.print('Invalid order data'); } } else { Log.print('Invalid order payload'); } } void _handleADSNotification() { // var orderData = jsonDecode(data); //closeOverLay(); Get.to( () => const NotificationCaptain(), ); } void onDidReceiveLocalNotification( int id, String? title, String? body, String? payload) async { // display a dialog with the notification details, tap ok to go to another page } } class NotificationController1 extends GetxController { final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // Initializes the local notifications plugin Future initNotifications() async { const AndroidInitializationSettings android = AndroidInitializationSettings('@mipmap/launcher_icon'); const InitializationSettings initializationSettings = InitializationSettings(android: android); await _flutterLocalNotificationsPlugin.initialize(initializationSettings); } // Displays a notification with the given title and message void showNotification( String title, String message, String tone, String payLoad) async { AndroidNotificationDetails android = AndroidNotificationDetails( 'your channel id', 'your channel name', importance: Importance.max, priority: Priority.high, showWhen: false, sound: RawResourceAndroidNotificationSound(tone)); NotificationDetails details = NotificationDetails(android: android); await _flutterLocalNotificationsPlugin.show(0, title, message, details); } }