feat: 实现日历提醒 in-app fallback 机制及通知服务重构

This commit is contained in:
zl-q
2026-03-20 01:30:34 +08:00
parent 7fd536e976
commit d574128815
55 changed files with 4565 additions and 647 deletions
@@ -9,11 +9,13 @@ import '../../../../shared/widgets/app_loading_indicator.dart';
import '../../../../shared/widgets/back_title_page_header.dart';
import '../../../../shared/widgets/detail_header_action_menu.dart';
import '../../../../shared/widgets/destructive_action_sheet.dart';
import '../../../../shared/widgets/toast/toast.dart';
import '../../../../shared/widgets/toast/toast_type.dart';
import '../../data/services/calendar_service.dart';
import '../../data/models/schedule_item_model.dart';
import '../utils/event_color_resolver.dart';
enum _CalendarHeaderAction { edit, delete, share }
enum _CalendarHeaderAction { edit, delete, share, archive }
class CalendarEventDetailScreen extends StatefulWidget {
final String eventId;
@@ -190,6 +192,17 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
),
);
}
if (event.status != ScheduleStatus.archived && event.canEdit) {
final isExpired = _isEventExpired(event);
items.add(
DetailHeaderActionItem<_CalendarHeaderAction>(
value: _CalendarHeaderAction.archive,
label: '归档',
icon: LucideIcons.archive,
enabled: !isExpired,
),
);
}
return DetailHeaderActionMenu<_CalendarHeaderAction>(
items: items,
@@ -197,6 +210,14 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
);
}
bool _isEventExpired(ScheduleItemModel event) {
final now = DateTime.now();
if (event.endAt != null) {
return event.endAt!.isBefore(now);
}
return event.startAt.isBefore(now);
}
void _handleHeaderAction(
_CalendarHeaderAction action,
ScheduleItemModel event,
@@ -213,6 +234,9 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
case _CalendarHeaderAction.share:
context.push(AppRoutes.calendarEventShare(event.id));
return;
case _CalendarHeaderAction.archive:
_archiveEvent();
return;
}
}
@@ -460,6 +484,29 @@ class _CalendarEventDetailScreenState extends State<CalendarEventDetailScreen> {
context.pop();
}
Future<void> _archiveEvent() async {
final confirmed = await showDestructiveActionSheet(
context,
title: '归档日程',
message: '归档后此日程将标记为过期,确定要归档吗?',
confirmText: '确认归档',
);
if (!confirmed) {
return;
}
try {
await sl<CalendarService>().archiveEvent(widget.eventId);
await _loadEvent();
if (mounted) {
Toast.show(context, '已归档', type: ToastType.success);
}
} catch (e) {
if (mounted) {
Toast.show(context, '归档失败', type: ToastType.error);
}
}
}
String _formatRangeLabel(DateTime startAt, DateTime? endAt) {
final dateLabel =
'${startAt.month}${startAt.day}${_getWeekday(startAt.weekday)}';