import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:timezone/timezone.dart' as tz; import '../models/models.dart'; class NotificationService { static final NotificationService _instance = NotificationService._internal(); factory NotificationService() => _instance; NotificationService._internal(); final FlutterLocalNotificationsPlugin _notifications = FlutterLocalNotificationsPlugin(); bool _initialized = false; Future initialize() async { if (_initialized) return; const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const iosSettings = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, ); const initSettings = InitializationSettings( android: androidSettings, iOS: iosSettings, ); await _notifications.initialize( initSettings, onDidReceiveNotificationResponse: _onNotificationTap, ); _initialized = true; } void _onNotificationTap(NotificationResponse response) { // Handle notification tap - mark routine as complete final payload = response.payload; if (payload != null) { // Navigate to routine or mark complete } } Future scheduleRoutineReminder(Routine routine) async { if (routine.reminders.isEmpty) return; final scheduledTime = _parseTime(routine.schedule.time); if (scheduledTime == null) return; for (final reminder in routine.reminders) { final reminderTime = scheduledTime.subtract( Duration(minutes: reminder.minutesBefore), ); await _notifications.zonedSchedule( '${routine.id}_${reminder.id}'.hashCode, 'LifeFlow Reminder', 'Time for: ${routine.name}', tz.TZDateTime.from(reminderTime, tz.local), NotificationDetails( android: AndroidNotificationDetails( 'routine_reminders', 'Routine Reminders', channelDescription: 'Reminders for your daily routines', importance: Importance.high, priority: Priority.high, showWhen: true, enableVibration: true, playSound: true, actions: [ const AndroidNotificationAction( 'complete', 'Complete', showsUserInterface: false, ), const AndroidNotificationAction( 'snooze', 'Snooze 10min', showsUserInterface: false, ), ], ), iOS: const DarwinNotificationDetails( presentAlert: true, presentBadge: true, presentSound: true, ), ), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, payload: routine.id, matchDateTimeComponents: DateTimeComponents.time, ); } } DateTime? _parseTime(String timeStr) { try { final parts = timeStr.split(':'); if (parts.length != 2) return null; final hour = int.parse(parts[0]); final minute = int.parse(parts[1]); final now = DateTime.now(); var scheduled = DateTime(now.year, now.month, now.day, hour, minute); if (scheduled.isBefore(now)) { scheduled = scheduled.add(const Duration(days: 1)); } return scheduled; } catch (e) { return null; } } Future cancelRoutineReminders(String routineId) async { // Cancel all notifications for this routine // Note: In production, track notification IDs } Future showImmediateNotification({ required String title, required String body, String? payload, }) async { await _notifications.show( DateTime.now().millisecond, title, body, const NotificationDetails( android: AndroidNotificationDetails( 'immediate', 'Immediate Notifications', importance: Importance.high, priority: Priority.high, ), iOS: DarwinNotificationDetails(), ), payload: payload, ); } }