LifeFlow/android/lib/services/notification_service.dart

147 lines
4.3 KiB
Dart

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<void> 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<void> 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<void> cancelRoutineReminders(String routineId) async {
// Cancel all notifications for this routine
// Note: In production, track notification IDs
}
Future<void> 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,
);
}
}