Fix release notification resource and add multiple advance reminders

This commit is contained in:
Codex
2026-10-14 11:30:37 +08:00
parent caf7abe0c0
commit 4d86db3dd5
16 changed files with 350 additions and 58 deletions
@@ -56,47 +56,62 @@ class LocalNotificationService extends NotificationService {
) async {
if (!settings.remindersEnabled || settings.semester == null) {
await cancelOwned();
return const ReminderResult(ReminderStatus.off);
return ReminderResult(
ReminderStatus.off,
message: settings.remindersEnabled ? '请先设置学期开始日和周数,再安排提醒。' : '课前提醒已关闭。',
);
}
final access = await gateway.permissions(request: false);
if (!access.notifications) {
await cancelOwned();
return const ReminderResult(
ReminderStatus.permissionDenied,
message: '尚未允许通知权限,请在设置中开启。',
message: '请允许通知,并检查系统中的“课前提醒”通知类别。',
);
}
final upcoming =
occurrences
.where(
(e) =>
e.course.source != CourseSource.demo &&
e.start
.subtract(Duration(minutes: settings.reminderMinutes))
.isAfter(now),
)
.toList()
..sort((a, b) {
final order = a.start.compareTo(b.start);
return order == 0 ? a.key.compareTo(b.key) : order;
});
<({CourseOccurrence event, int minutes, tz.TZDateTime fireAt})>[
for (final event in occurrences)
if (event.course.source != CourseSource.demo)
for (final minutes in settings.reminderOffsets)
if (event.start
.subtract(Duration(minutes: minutes))
.isAfter(now))
(
event: event,
minutes: minutes,
fireAt: event.start.subtract(Duration(minutes: minutes)),
),
]..sort((a, b) {
final order = a.fireAt.compareTo(b.fireAt);
if (order != 0) return order;
final courseOrder = a.event.key.compareTo(b.event.key);
return courseOrder != 0
? courseOrder
: a.minutes.compareTo(b.minutes);
});
final limited = upcoming.length > 400;
final selected = upcoming.take(400).toList()
..sort((a, b) => a.key.compareTo(b.key));
final selected = upcoming.take(400);
final desired = <int, ReminderRequest>{};
for (final event in selected) {
var id = notificationId(event.key);
for (final reminder in selected) {
final event = reminder.event;
// Keep the original 15-minute ID; other times need independent IDs so
// Android cannot replace an earlier reminder for the same course.
var id = notificationId(
reminder.minutes == 15
? event.key
: '${event.key}/reminder/${reminder.minutes}',
);
while (desired.containsKey(id)) {
id = (id + 1) & 0x7FFFFFFF;
}
desired[id] = ReminderRequest(
id: id,
occurrenceKey: event.key,
fireAt: event.start.subtract(
Duration(minutes: settings.reminderMinutes),
),
fireAt: reminder.fireAt,
title: event.course.name,
body: '${event.course.room} · ${event.course.teacher}',
body:
'${reminder.minutes}分钟后上课 · ${event.course.room} · ${event.course.teacher}',
exact: access.exactAlarm,
);
}
@@ -118,6 +133,11 @@ class LocalNotificationService extends NotificationService {
_fingerprints[entry.key] = fingerprint;
}
final message = [
if (desired.isEmpty) '当前没有待提醒的课程,请核对学期日期和上课周次。',
if (desired.isNotEmpty) '已安排 ${desired.length} 次课前提醒。',
if (upcoming.isNotEmpty)
'最近一次:${upcoming.first.fireAt.month}月${upcoming.first.fireAt.day}日 '
'${upcoming.first.fireAt.hour.toString().padLeft(2, '0')}:${upcoming.first.fireAt.minute.toString().padLeft(2, '0')}。',
if (!access.exactAlarm) '未允许精确提醒,系统可能延迟送达。',
if (limited) '已安排最近 400 次提醒,后续提醒在再次打开时补充。',
].join(' ');
@@ -185,8 +205,17 @@ class PluginReminderGateway extends ReminderGateway {
await _android?.requestNotificationsPermission();
await _android?.requestExactAlarmsPermission();
}
final channels = await _android?.getNotificationChannels();
final courseChannelEnabled =
channels == null ||
!channels.any(
(channel) =>
channel.id == 'hepan_lessons' &&
channel.importance == Importance.none,
);
return ReminderPermissions(
await _android?.areNotificationsEnabled() ?? false,
(await _android?.areNotificationsEnabled() ?? false) &&
courseChannelEnabled,
await _android?.canScheduleExactNotifications() ?? false,
);
}