Files
social-app/apps/lib/features/calendar/reminders/reminder_overlap_policy.dart
T
qzl 00f37d7e19 feat: 实现日历提醒完整功能(操作执行、通知服务重构、归档)
- 新增 ReminderActionExecutor 处理取消/稍后提醒操作
- 新增 ReminderOutboxStore 本地存储待处理操作
- 重构 LocalNotificationService 支持聚合提醒和交互操作
- 新增 event_color_resolver 工具类统一颜色解析
- 新增 CalendarService.archiveEvent 归档方法
- 增强 ModelTracking 支持缓存命中、推理token和成本追踪
- 添加 qwen3.5-35b-a3b 模型配置
- 更新 AndroidManifest 全屏intent权限
- 补充相关单元测试和文档
2026-03-18 19:12:47 +08:00

81 lines
2.0 KiB
Dart

import '../data/models/schedule_item_model.dart';
class ReminderOverlapGroup {
final DateTime fireAt;
final List<ScheduleItemModel> events;
const ReminderOverlapGroup({required this.fireAt, required this.events});
bool get isAggregate => events.length > 1;
}
class ReminderOverlapPolicy {
const ReminderOverlapPolicy();
List<ReminderOverlapGroup> groupByMinute(
Iterable<ScheduleItemModel> events, {
required DateTime now,
}) {
final buckets = <String, List<ScheduleItemModel>>{};
final minuteToFireAt = <String, DateTime>{};
for (final event in events) {
final fireAt = resolveFirstFireAt(event, now: now);
if (fireAt == null) {
continue;
}
final minute = DateTime(
fireAt.year,
fireAt.month,
fireAt.day,
fireAt.hour,
fireAt.minute,
);
final key = minute.toIso8601String();
buckets.putIfAbsent(key, () => <ScheduleItemModel>[]).add(event);
minuteToFireAt[key] = minuteToFireAt[key] ?? fireAt;
}
final groups = buckets.entries
.map(
(entry) => ReminderOverlapGroup(
fireAt: minuteToFireAt[entry.key]!,
events: entry.value,
),
)
.toList();
groups.sort((left, right) => left.fireAt.compareTo(right.fireAt));
return groups;
}
DateTime? resolveFirstFireAt(
ScheduleItemModel event, {
required DateTime now,
}) {
if (event.status != ScheduleStatus.active) {
return null;
}
final reminderMinutes = event.metadata?.reminderMinutes;
if (reminderMinutes == null) {
return null;
}
final remindAt = event.startAt.subtract(Duration(minutes: reminderMinutes));
final endAt = event.endAt;
if (endAt != null && !now.isBefore(endAt)) {
return null;
}
if (now.isBefore(remindAt)) {
return remindAt;
}
if (endAt != null && now.isBefore(endAt)) {
return now.add(const Duration(seconds: 5));
}
return null;
}
}