108 lines
3.2 KiB
Dart
108 lines
3.2 KiB
Dart
import 'dart:math';
|
|
|
|
import '../data/services/calendar_service.dart';
|
|
import '../../../core/notifications/local_notification_service.dart';
|
|
import 'models/reminder_action.dart';
|
|
import 'models/reminder_payload.dart';
|
|
import 'reminder_outbox_store.dart';
|
|
|
|
class ReminderActionExecutor {
|
|
final CalendarService _calendarService;
|
|
final LocalNotificationService _notificationService;
|
|
final ReminderOutboxStore _outboxStore;
|
|
final Random _random;
|
|
|
|
ReminderActionExecutor({
|
|
required CalendarService calendarService,
|
|
required LocalNotificationService notificationService,
|
|
required ReminderOutboxStore outboxStore,
|
|
Random? random,
|
|
}) : _calendarService = calendarService,
|
|
_notificationService = notificationService,
|
|
_outboxStore = outboxStore,
|
|
_random = random ?? Random();
|
|
|
|
Future<void> handleAction({
|
|
required ReminderAction action,
|
|
required ReminderPayload payload,
|
|
}) async {
|
|
final ids = payload.mode == ReminderPayloadMode.aggregate
|
|
? (payload.aggregateIds.isNotEmpty
|
|
? payload.aggregateIds
|
|
: <String>[payload.eventId])
|
|
: <String>[payload.eventId];
|
|
|
|
if (action == ReminderAction.archive) {
|
|
for (final id in ids) {
|
|
await _notificationService.cancelEventReminder(id);
|
|
await _archiveEvent(id, ReminderAction.archive);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (action == ReminderAction.snooze10m) {
|
|
for (final id in ids) {
|
|
await _snoozeEvent(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> replayPendingActions() async {
|
|
final pending = await _outboxStore.listPending();
|
|
for (final item in pending) {
|
|
if (item.targetStatus != 'archived') {
|
|
continue;
|
|
}
|
|
try {
|
|
await _calendarService.archiveEvent(item.eventId);
|
|
await _outboxStore.markDone(item.opId);
|
|
} catch (error) {
|
|
await _outboxStore.markRetry(item.opId, error.toString());
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _snoozeEvent(String eventId) async {
|
|
final event = await _calendarService.getEventById(eventId);
|
|
if (event == null) {
|
|
return;
|
|
}
|
|
final now = DateTime.now();
|
|
final endAt = event.endAt;
|
|
if (endAt != null && !now.isBefore(endAt)) {
|
|
await _notificationService.cancelEventReminder(eventId);
|
|
await _archiveEvent(eventId, ReminderAction.archive);
|
|
return;
|
|
}
|
|
|
|
final nextAt = now.add(const Duration(minutes: 10));
|
|
if (endAt != null && !nextAt.isBefore(endAt)) {
|
|
await _notificationService.cancelEventReminder(eventId);
|
|
await _archiveEvent(eventId, ReminderAction.archive);
|
|
return;
|
|
}
|
|
|
|
await _notificationService.scheduleReminderAt(event, nextAt);
|
|
}
|
|
|
|
Future<void> _archiveEvent(String eventId, ReminderAction action) async {
|
|
try {
|
|
await _calendarService.archiveEvent(eventId);
|
|
return;
|
|
} catch (_) {
|
|
// fall through to enqueue local outbox for retry
|
|
}
|
|
|
|
final opId =
|
|
'${DateTime.now().millisecondsSinceEpoch}-${_random.nextInt(1 << 32)}';
|
|
final outboxItem = ReminderOutboxItem(
|
|
opId: opId,
|
|
eventId: eventId,
|
|
action: action,
|
|
targetStatus: 'archived',
|
|
occurredAt: DateTime.now(),
|
|
);
|
|
await _outboxStore.enqueue(outboxItem);
|
|
}
|
|
}
|