201 lines
5.7 KiB
Dart
201 lines
5.7 KiB
Dart
import 'package:flisp_app/models/calendar.dart';
|
||
import 'package:flisp_app/models/todo.dart';
|
||
import 'package:flisp_app/service/calendar_service.dart';
|
||
import 'package:flisp_app/service/todo_service.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_common/utils/date_utils.dart';
|
||
import 'package:flutter_common/utils/log_utils.dart';
|
||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||
import 'package:timezone/data/latest_all.dart' as tz;
|
||
import 'package:timezone/timezone.dart' as tz;
|
||
|
||
class NotifyService {
|
||
static final NotifyService _instance = NotifyService._internal();
|
||
|
||
factory NotifyService() => _instance;
|
||
|
||
NotifyService._internal();
|
||
|
||
late FlutterLocalNotificationsPlugin _notifications;
|
||
|
||
// Android特殊模式,即使设备处于省电模式也能准时触发。
|
||
final scheduleMode = AndroidScheduleMode.exactAllowWhileIdle;
|
||
|
||
// 初始化通知服务
|
||
Future<void> initialize() async {
|
||
_notifications = FlutterLocalNotificationsPlugin();
|
||
|
||
// 初始化时区
|
||
tz.initializeTimeZones();
|
||
tz.setLocalLocation(tz.getLocation("Asia/Shanghai"));
|
||
|
||
// 设置Android平台的初始化配置 使用应用图标作为通知图标
|
||
const AndroidInitializationSettings androidSettings =
|
||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||
|
||
// 设置iOS平台的初始化配置
|
||
const DarwinInitializationSettings iosSettings =
|
||
DarwinInitializationSettings(
|
||
requestAlertPermission: true,
|
||
requestBadgePermission: true,
|
||
requestSoundPermission: true,
|
||
);
|
||
|
||
// 初始化设置
|
||
const InitializationSettings settings = InitializationSettings(
|
||
android: androidSettings,
|
||
iOS: iosSettings,
|
||
);
|
||
|
||
await _notifications.initialize(settings);
|
||
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
_refreshScheduled();
|
||
});
|
||
}
|
||
|
||
/// 重新刷新提醒 防止每次重启设备后提醒丢失的问题
|
||
void _refreshScheduled() async {
|
||
logger.i('开始刷新提醒');
|
||
await cancelAllNotifications();
|
||
|
||
TodoService todoService = TodoService();
|
||
final List<Todo> todoResult = todoService.getAllTodos(
|
||
TodoSortMode.priority,
|
||
);
|
||
final List<Todo> todayTodos =
|
||
todoResult
|
||
.where(
|
||
(todo) => !todo.isCompleted && isAfterToday(todo.scheduledTime),
|
||
)
|
||
.toList();
|
||
|
||
for (Todo todo in todayTodos) {
|
||
await scheduleNotification(
|
||
id: todo.id,
|
||
title: '待办提醒',
|
||
body: todo.title,
|
||
scheduledTime: todo.scheduledTime!,
|
||
);
|
||
}
|
||
|
||
logger.i('刷新 ${todayTodos.length}个 待办提醒');
|
||
|
||
CalendarService calendarService = CalendarService();
|
||
final List<Calendar> calendarResult = calendarService.getAllCalendars();
|
||
final List<Calendar> todayCalendars =
|
||
calendarResult
|
||
.where((item) => isAfterToday(item.scheduledTime))
|
||
.toList();
|
||
|
||
for (Calendar calendar in todayCalendars) {
|
||
await scheduleNotification(
|
||
id: calendar.id,
|
||
title: '日程提醒',
|
||
body: calendar.title,
|
||
scheduledTime: calendar.scheduledTime!,
|
||
);
|
||
}
|
||
|
||
logger.i('刷新 ${todayCalendars.length}个 日程提醒');
|
||
logger.i('结束刷新提醒');
|
||
}
|
||
|
||
// 创建Android通知详情
|
||
AndroidNotificationDetails _androidNotificationDetails() {
|
||
const channelId = 'com.cxx.flisp_app';
|
||
const channelName = '闪灵';
|
||
const channelDescription = '闪灵通知';
|
||
return const AndroidNotificationDetails(
|
||
channelId,
|
||
channelName,
|
||
channelDescription: channelDescription,
|
||
importance: Importance.high,
|
||
priority: Priority.high,
|
||
playSound: true,
|
||
enableVibration: true,
|
||
);
|
||
}
|
||
|
||
// 创建iOS通知详情
|
||
DarwinNotificationDetails _iosNotificationDetails() {
|
||
return const DarwinNotificationDetails(
|
||
presentAlert: true,
|
||
presentBadge: true,
|
||
presentSound: true,
|
||
);
|
||
}
|
||
|
||
NotificationDetails get _details {
|
||
return NotificationDetails(
|
||
android: _androidNotificationDetails(),
|
||
iOS: _iosNotificationDetails(),
|
||
);
|
||
}
|
||
|
||
// 立即显示通知
|
||
Future<void> showInstantNotification({
|
||
required String title,
|
||
required String body,
|
||
int id = 0,
|
||
}) async {
|
||
await _notifications.show(id, title, body, _details);
|
||
}
|
||
|
||
// 安排定时通知
|
||
Future<void> scheduleNotification({
|
||
required int id,
|
||
required String title,
|
||
required String body,
|
||
required DateTime scheduledTime,
|
||
}) async {
|
||
await _notifications.zonedSchedule(
|
||
id,
|
||
title,
|
||
body,
|
||
tz.TZDateTime.from(scheduledTime, tz.local),
|
||
_details,
|
||
androidScheduleMode: scheduleMode,
|
||
);
|
||
}
|
||
|
||
// 取消特定通知
|
||
Future<void> cancelNotification(int id) async {
|
||
try {
|
||
await _notifications.cancel(id);
|
||
} catch (e) {
|
||
logger.i('取消通知失败: $e');
|
||
}
|
||
}
|
||
|
||
// 取消所有通知
|
||
Future<void> cancelAllNotifications() async {
|
||
await _notifications.cancelAll();
|
||
}
|
||
|
||
// 检查通知权限
|
||
Future<bool> checkPermission() async {
|
||
final bool? result =
|
||
await _notifications
|
||
.resolvePlatformSpecificImplementation<
|
||
AndroidFlutterLocalNotificationsPlugin
|
||
>()
|
||
?.areNotificationsEnabled();
|
||
return result ?? false;
|
||
}
|
||
|
||
// 请求权限
|
||
Future<void> requestPermission() async {
|
||
await _notifications
|
||
.resolvePlatformSpecificImplementation<
|
||
IOSFlutterLocalNotificationsPlugin
|
||
>()
|
||
?.requestPermissions(alert: true, badge: true, sound: true);
|
||
}
|
||
|
||
// 获取所有待处理的通知
|
||
Future<List<PendingNotificationRequest>> getPendingNotifications() async {
|
||
return await _notifications.pendingNotificationRequests();
|
||
}
|
||
}
|