feat: 重构 Reminder Notification 系统并更新应用包名

This commit is contained in:
qzl
2026-03-30 18:36:57 +08:00
parent 9fb2a6857b
commit 91bf3c3f96
90 changed files with 5133 additions and 3017 deletions
@@ -0,0 +1,32 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/core/notification/models/reminder_alarm.dart';
void main() {
test('ReminderAlarm JSON roundtrip keeps key fields', () {
final alarm = ReminderAlarm(
eventId: 'evt_1',
title: 'Standup',
startAt: DateTime(2026, 3, 30, 10, 0),
endAt: DateTime(2026, 3, 30, 10, 30),
timezone: 'Asia/Shanghai',
reminderMinutes: 15,
fireAt: DateTime(2026, 3, 30, 9, 45),
fireTimeBucket: 29112645,
version: 2,
location: 'Meeting Room A',
notes: 'Daily sync',
);
final decoded = ReminderAlarm.fromJson(alarm.toJson());
expect(decoded.eventId, alarm.eventId);
expect(decoded.title, alarm.title);
expect(decoded.startAt, alarm.startAt);
expect(decoded.endAt, alarm.endAt);
expect(decoded.timezone, alarm.timezone);
expect(decoded.reminderMinutes, alarm.reminderMinutes);
expect(decoded.fireAt, alarm.fireAt);
expect(decoded.fireTimeBucket, alarm.fireTimeBucket);
expect(decoded.version, alarm.version);
});
}
@@ -0,0 +1,66 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/core/notification/models/reminder_alarm.dart';
import 'package:social_app/core/notification/services/reminder_scheduler_service.dart';
void main() {
test('buildAlarms uses remindAt cadence until endAt', () {
final event = ReminderEventSnapshot(
eventId: 'evt_2',
title: 'Planning',
startAt: DateTime(2026, 3, 30, 10, 0),
endAt: DateTime(2026, 3, 30, 10, 40),
timezone: 'Asia/Shanghai',
reminderMinutes: 15,
);
final alarms = ReminderSchedulerService.buildAlarmsForEvent(
event,
now: DateTime(2026, 3, 30, 9, 0),
);
expect(alarms.length, 6);
expect(alarms.first.fireAt, DateTime(2026, 3, 30, 9, 45));
expect(alarms.last.fireAt, DateTime(2026, 3, 30, 10, 35));
});
test(
'buildAlarms compensates by scheduling near-now when remindAt passed',
() {
final event = ReminderEventSnapshot(
eventId: 'evt_3',
title: 'Review',
startAt: DateTime(2026, 3, 30, 10, 0),
endAt: DateTime(2026, 3, 30, 10, 20),
timezone: 'Asia/Shanghai',
reminderMinutes: 30,
);
final now = DateTime(2026, 3, 30, 10, 5, 0);
final alarms = ReminderSchedulerService.buildAlarmsForEvent(
event,
now: now,
);
expect(alarms, isNotEmpty);
expect(alarms.first.fireAt, now.add(const Duration(seconds: 5)));
},
);
test('buildAlarms returns empty when event already ended', () {
final event = ReminderEventSnapshot(
eventId: 'evt_4',
title: 'Expired',
startAt: DateTime(2026, 3, 30, 10, 0),
endAt: DateTime(2026, 3, 30, 10, 10),
timezone: 'Asia/Shanghai',
reminderMinutes: 5,
);
final alarms = ReminderSchedulerService.buildAlarmsForEvent(
event,
now: DateTime(2026, 3, 30, 10, 11),
);
expect(alarms, isEmpty);
});
}