refactor(calendar): remove deprecated reminder components

This commit is contained in:
qzl
2026-03-20 18:42:58 +08:00
parent 9ece726de0
commit 6e35fff9a4
20 changed files with 47 additions and 1143 deletions
@@ -4,7 +4,6 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:timezone/data/latest.dart' as tz_data;
import 'package:timezone/timezone.dart' as tz;
@@ -12,8 +11,6 @@ import 'reminder_notification_callbacks.dart';
import '../../features/calendar/data/models/schedule_item_model.dart';
import '../../features/calendar/reminders/models/reminder_action.dart';
import '../../features/calendar/reminders/models/reminder_payload.dart';
import '../../features/calendar/reminders/reminder_action_dedupe_store.dart';
import '../../features/calendar/reminders/reminder_overlap_policy.dart';
typedef ReminderNotificationActionHandler =
Future<void> Function({
@@ -38,9 +35,7 @@ class LocalNotificationService {
static const String _actionSnooze = 'snooze10m';
final FlutterLocalNotificationsPlugin _plugin;
final ReminderOverlapPolicy _overlapPolicy;
final ReminderPermissionFallbackTracker? _permissionFallbackTracker;
ReminderActionDedupeStore? _dedupeStore;
bool _initialized = false;
bool _canDeliverSystemNotification = true;
ReminderNotificationActionHandler? _actionHandler;
@@ -50,12 +45,8 @@ class LocalNotificationService {
LocalNotificationService({
FlutterLocalNotificationsPlugin? plugin,
ReminderOverlapPolicy? overlapPolicy,
ReminderActionDedupeStore? dedupeStore,
ReminderPermissionFallbackTracker? permissionFallbackTracker,
}) : _plugin = plugin ?? FlutterLocalNotificationsPlugin(),
_overlapPolicy = overlapPolicy ?? const ReminderOverlapPolicy(),
_dedupeStore = dedupeStore,
_permissionFallbackTracker = permissionFallbackTracker;
void bindActionHandler(ReminderNotificationActionHandler handler) {
@@ -128,19 +119,9 @@ class LocalNotificationService {
>();
await iosImpl?.requestPermissions(alert: true, badge: true, sound: true);
await _ensureDedupeStore();
_initialized = true;
}
Future<void> _ensureDedupeStore() async {
if (_dedupeStore != null) {
return;
}
final prefs = await SharedPreferences.getInstance();
_dedupeStore = ReminderActionDedupeStore(prefs);
}
Future<void> _refreshAndroidNotificationAvailability() async {
if (defaultTargetPlatform != TargetPlatform.android) {
return;
@@ -166,8 +147,9 @@ class LocalNotificationService {
}
final now = DateTime.now();
final fireAt = _overlapPolicy.resolveFirstFireAt(event, now: now);
if (fireAt == null) {
final reminderMinutes = event.metadata?.reminderMinutes ?? 0;
final fireAt = event.startAt.subtract(Duration(minutes: reminderMinutes));
if (fireAt.isBefore(now)) {
await cancelEventReminder(event.id);
return;
}
@@ -225,31 +207,21 @@ class LocalNotificationService {
) async {
await initialize();
await _refreshAndroidNotificationAvailability();
if (!_canDeliverSystemNotification) {
_clearAllInAppFallbackTimers();
final now = DateTime.now();
final groups = _overlapPolicy.groupByMinute(events, now: now);
for (final group in groups) {
if (group.isAggregate) {
await _scheduleInAppAggregateFallback(group.events, group.fireAt);
continue;
}
await _scheduleInAppFallbackRemindersFrom(
event: group.events.first,
firstFireAt: group.fireAt,
for (final event in events) {
if (!_canDeliverSystemNotification) {
final reminderMinutes = event.metadata?.reminderMinutes ?? 0;
final fireAt = event.startAt.subtract(
Duration(minutes: reminderMinutes),
);
}
return;
}
final now = DateTime.now();
final groups = _overlapPolicy.groupByMinute(events, now: now);
for (final group in groups) {
if (group.isAggregate) {
await _scheduleAggregateReminder(group.events, group.fireAt);
if (fireAt.isAfter(DateTime.now())) {
await _scheduleInAppFallbackRemindersFrom(
event: event,
firstFireAt: fireAt,
);
}
continue;
}
await upsertEventReminder(group.events.first);
await upsertEventReminder(event);
}
}
@@ -693,21 +665,6 @@ class LocalNotificationService {
return;
}
final dedupeStore = _dedupeStore;
if (dedupeStore != null) {
final notificationId = response.id?.toString() ?? payload.eventId;
final fireTimeBucket =
payload.fireTimeBucket ??
(payload.startAt.millisecondsSinceEpoch ~/
const Duration(minutes: 1).inMilliseconds);
final actionExecutionId =
'$notificationId|${action.value}|$fireTimeBucket';
final isNew = await dedupeStore.markIfNew(actionExecutionId);
if (!isNew) {
return;
}
}
await handler(action: action, payload: payload);
}
}
@@ -5,8 +5,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../features/calendar/reminders/reminder_cold_start_queue.dart';
typedef ReminderNotificationResponseHandler =
Future<void> Function(NotificationResponse response);
@@ -15,8 +13,6 @@ class ReminderNotificationCallbacks {
'calendar_reminder_pending_notification_responses_v1';
static ReminderNotificationResponseHandler? _responseHandler;
static Future<void> _pendingStorageLock = Future<void>.value();
static final ReminderColdStartQueue _coldStartQueue =
ReminderColdStartQueue();
@visibleForTesting
static Future<void> resetForTest() async {
@@ -106,38 +102,35 @@ class ReminderNotificationCallbacks {
final remaining = <String>[];
for (final raw in pending) {
_coldStartQueue.enqueue(() async {
Map<String, dynamic> parsed;
try {
parsed = Map<String, dynamic>.from(jsonDecode(raw) as Map);
} catch (_) {
return;
}
Map<String, dynamic> parsed;
try {
parsed = Map<String, dynamic>.from(jsonDecode(raw) as Map);
} catch (_) {
continue;
}
final id = parsed['id'] as int?;
final actionId = parsed['actionId'] as String?;
final payload = parsed['payload'] as String?;
final typeIndex = (parsed['type'] as int?) ?? 0;
final input = parsed['input'] as String?;
final type = NotificationResponseType.values[typeIndex.clamp(0, 1)];
final id = parsed['id'] as int?;
final actionId = parsed['actionId'] as String?;
final payload = parsed['payload'] as String?;
final typeIndex = (parsed['type'] as int?) ?? 0;
final input = parsed['input'] as String?;
final type = NotificationResponseType.values[typeIndex.clamp(0, 1)];
try {
await handler(
NotificationResponse(
id: id,
actionId: actionId,
payload: payload,
input: input,
notificationResponseType: type,
),
);
} catch (_) {
remaining.add(raw);
}
});
try {
await handler(
NotificationResponse(
id: id,
actionId: actionId,
payload: payload,
input: input,
notificationResponseType: type,
),
);
} catch (_) {
remaining.add(raw);
}
}
await _coldStartQueue.replay();
if (remaining.isEmpty) {
await prefs.remove(_pendingKey);
return;