import 'dart:developer'; import 'package:wanisdriver/models/Ride.dart'; // Adjust path if needed import 'package:flutter/foundation.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:get_it/get_it.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart' as tz; import 'package:device_info_plus/device_info_plus.dart'; /// A unified service to manage all local ride notifications. /// This class is registered as a singleton in GetIt. class RideNotificationService with ChangeNotifier { // ✅ Get the singleton instance of the plugin from GetIt final FlutterLocalNotificationsPlugin _localNotificationsPlugin = GetIt.I(); final Set _scheduledNotificationIds = {}; Set get scheduledNotificationIds => _scheduledNotificationIds; Future initialize() async { tz.initializeTimeZones(); try { tz.setLocalLocation(tz.getLocation('Africa/Tunis')); } catch (e) { log('❌ Could not set timezone "Africa/Tunis". Defaulting to local. Error: $e'); } const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); const DarwinInitializationSettings initializationSettingsIOS = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true); const InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsIOS); await _localNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: _onNotificationTap, onDidReceiveBackgroundNotificationResponse: _onBackgroundNotificationTap, ); log('✅ RideNotificationService initialized successfully.'); } /// Request necessary permissions for modern Android versions. Future requestPermissions() async { final deviceInfo = await DeviceInfoPlugin().androidInfo; if (deviceInfo.version.sdkInt >= 31) { // Android 12+ final androidPlugin = _localNotificationsPlugin.resolvePlatformSpecificImplementation(); await androidPlugin?.requestExactAlarmsPermission(); await androidPlugin?.requestNotificationsPermission(); } } void _onNotificationTap(NotificationResponse response) { log('🔎 User tapped notification. Payload: ${response.payload}'); } Future scheduleRideNotification({ required int rideId, required String title, required String body, required DateTime scheduledTime, }) async { final notificationTime = scheduledTime.subtract(const Duration(minutes: 1)); if (notificationTime.isBefore(DateTime.now())) { log('⚠️ Ride #$rideId is in the past. Skipping schedule scheduledTime. $scheduledTime'); return; } try { await _localNotificationsPlugin.zonedSchedule( rideId, title, body, tz.TZDateTime.from(notificationTime, tz.local), const NotificationDetails( android: AndroidNotificationDetails( 'ride_schedule_channel', 'Ride Schedule Notifications', channelDescription: 'Notifications for upcoming scheduled rides.', importance: Importance.max, priority: Priority.high), iOS: DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true), ), androidAllowWhileIdle: true, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime); _scheduledNotificationIds.add(rideId); log('✅ Notification scheduled for Ride #$rideId at $notificationTime.'); notifyListeners(); } catch (e) { log('❌ Failed to schedule for Ride #$rideId: $e'); } } Future cancelRideNotification(int rideId) async { await _localNotificationsPlugin.cancel(rideId); _scheduledNotificationIds.remove(rideId); notifyListeners(); } Future cancelAllRideNotifications() async { await _localNotificationsPlugin.cancelAll(); _scheduledNotificationIds.clear(); notifyListeners(); } Future rescheduleAllNotifications(List activeScheduledRides) async { await cancelAllRideNotifications(); log('🔄 Rescheduling notifications for ${activeScheduledRides.length} rides.'); for (final ride in activeScheduledRides) { if (ride.rideStartTime != null && ride.rideStatus != "CANCELLED") { await scheduleRideNotification( rideId: ride.id, title: 'Upcoming Ride Reminder', body: 'Your ride with ${ride.ridername ?? "a client"} is in 5 minutes.', scheduledTime: ride.rideStartTime!, ); } } } } @pragma('vm:entry-point') void _onBackgroundNotificationTap(NotificationResponse response) { log('🔎 User tapped notification from background. Payload: ${response.payload}'); }