import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:timezone/timezone.dart' as tz; import 'package:timezone/data/latest.dart' as tz; import 'package:flutter/foundation.dart'; // For kIsWeb class NotificationService { static final NotificationService _instance = NotificationService._internal(); factory NotificationService() { return _instance; } NotificationService._internal(); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); bool _isInitialized = false; Future initialize() async { if (_isInitialized) return; // Timezone initialization if (!kIsWeb) { tz.initializeTimeZones(); } const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); final DarwinInitializationSettings initializationSettingsDarwin = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, ); // Linux initialization (optional, but good for completeness) final LinuxInitializationSettings initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification'); final InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsDarwin, macOS: initializationSettingsDarwin, linux: initializationSettingsLinux, ); await flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: (NotificationResponse details) async { // Handle notification tap }, ); _isInitialized = true; } Future scheduleNotification({ required int id, required String title, required String body, required DateTime scheduledDate, }) async { if (kIsWeb) { // Web platform limitation: Background scheduling is complex. // For this demo/web preview, we'll just log it or rely on the UI confirmation. print('Web Notification Scheduled: $title - $body at $scheduledDate'); return; } await flutterLocalNotificationsPlugin.zonedSchedule( id, title, body, tz.TZDateTime.from(scheduledDate, tz.local), const NotificationDetails( android: AndroidNotificationDetails( 'pad_tracker_channel', 'Pad Tracker Reminders', channelDescription: 'Reminders to change pad/tampon', importance: Importance.max, priority: Priority.high, ), iOS: DarwinNotificationDetails(), ), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, ); } // New method for specific notification types Future showLocalNotification({ required int id, required String title, required String body, String? channelId, String? channelName, }) async { if (kIsWeb) { print('Web Local Notification: $title - $body'); return; } const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( 'tracker_general', 'General Notifications', channelDescription: 'General app notifications', importance: Importance.max, priority: Priority.high, ticker: 'ticker'); const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails); await flutterLocalNotificationsPlugin.show( id, title, body, notificationDetails, payload: 'item x'); } Future cancelNotification(int id) async { await flutterLocalNotificationsPlugin.cancel(id); } }