421 lines
12 KiB
Dart
421 lines
12 KiB
Dart
/// ============================================================
|
||
/// 闲言APP — 通知调度器
|
||
/// 创建时间: 2026-05-02
|
||
/// 更新时间: 2026-05-22
|
||
/// 作用: 统一管理本地通知调度 (每日推荐/签到/节气/番茄钟/运势/学习进度)
|
||
/// 上次更新: @Deprecated 已合并至NotificationCenter,请使用NotificationCenter替代
|
||
/// ============================================================
|
||
|
||
import 'local_notification_service.dart';
|
||
import '../../storage/kv_storage.dart';
|
||
import '../../utils/logger.dart';
|
||
|
||
@Deprecated('已合并至NotificationCenter,请使用NotificationCenter替代')
|
||
class NotificationScheduler {
|
||
NotificationScheduler._();
|
||
|
||
static const _keyNotificationsEnabled = 'notifications_enabled';
|
||
static const _keyDailySentenceEnabled = 'daily_sentence_enabled';
|
||
static const _keySigninReminderEnabled = 'signin_reminder_enabled';
|
||
static const _keySolarTermEnabled = 'solar_term_enabled';
|
||
static const _keyDailySentenceHour = 'daily_sentence_hour';
|
||
static const _keyDailySentenceMinute = 'daily_sentence_minute';
|
||
static const _keySigninReminderHour = 'signin_reminder_hour';
|
||
static const _keySigninReminderMinute = 'signin_reminder_minute';
|
||
static const _keyFortuneEnabled = 'fortune_enabled';
|
||
static const _keyFortuneHour = 'fortune_hour';
|
||
static const _keyFortuneMinute = 'fortune_minute';
|
||
static const _keyStudyProgressEnabled = 'study_progress_enabled';
|
||
|
||
static Future<void> _cancelAllManaged() async {
|
||
await LocalNotificationService.cancel(1001);
|
||
await LocalNotificationService.cancel(1002);
|
||
await LocalNotificationService.cancel(1003);
|
||
await LocalNotificationService.cancel(1004);
|
||
await LocalNotificationService.cancel(2001);
|
||
}
|
||
|
||
static Future<void> configureAll() async {
|
||
final enabled = KvStorage.getBool(_keyNotificationsEnabled) ?? false;
|
||
if (!enabled) {
|
||
await _cancelAllManaged();
|
||
Log.i('通知调度: 通知已关闭,取消所有调度');
|
||
return;
|
||
}
|
||
|
||
await _cancelAllManaged();
|
||
|
||
final dailySentence = KvStorage.getBool(_keyDailySentenceEnabled) ?? true;
|
||
if (dailySentence) {
|
||
final hour = KvStorage.getInt(_keyDailySentenceHour) ?? 8;
|
||
final minute = KvStorage.getInt(_keyDailySentenceMinute) ?? 0;
|
||
await LocalNotificationService.scheduleDaily(
|
||
id: 1001,
|
||
title: '闲言每日一句',
|
||
body: '今天的句子已准备好,来看看吧 ✨',
|
||
hour: hour,
|
||
minute: minute,
|
||
payload: 'daily_sentence',
|
||
);
|
||
}
|
||
|
||
final signinReminder =
|
||
KvStorage.getBool(_keySigninReminderEnabled) ?? true;
|
||
if (signinReminder) {
|
||
final hour = KvStorage.getInt(_keySigninReminderHour) ?? 20;
|
||
final minute = KvStorage.getInt(_keySigninReminderMinute) ?? 0;
|
||
await LocalNotificationService.scheduleDaily(
|
||
id: 1002,
|
||
title: '闲言 · 签到提醒',
|
||
body: '别忘了今日签到哦 📝',
|
||
hour: hour,
|
||
minute: minute,
|
||
payload: 'signin_reminder',
|
||
);
|
||
}
|
||
|
||
final solarTerm = KvStorage.getBool(_keySolarTermEnabled) ?? true;
|
||
if (solarTerm) {
|
||
await _scheduleNextSolarTerm();
|
||
}
|
||
|
||
final fortune = KvStorage.getBool(_keyFortuneEnabled) ?? false;
|
||
if (fortune) {
|
||
final hour = KvStorage.getInt(_keyFortuneHour) ?? 8;
|
||
final minute = KvStorage.getInt(_keyFortuneMinute) ?? 0;
|
||
await LocalNotificationService.scheduleDaily(
|
||
id: 1003,
|
||
title: '闲言 · 🔮 每日运势',
|
||
body: '今日运势已生成,快来看看你的运势吧 ✨',
|
||
hour: hour,
|
||
minute: minute,
|
||
payload: 'daily_fortune',
|
||
);
|
||
}
|
||
|
||
final studyProgress = KvStorage.getBool(_keyStudyProgressEnabled) ?? false;
|
||
if (studyProgress) {
|
||
await LocalNotificationService.scheduleDaily(
|
||
id: 1004,
|
||
title: '闲言 · 学习进度',
|
||
body: '该复习今天的学习内容了 📊',
|
||
hour: 20,
|
||
payload: 'study_progress',
|
||
);
|
||
}
|
||
|
||
Log.i('通知调度: 所有通知已配置');
|
||
}
|
||
|
||
static Future<void> _scheduleNextSolarTerm() async {
|
||
final nextTerm = _getNextSolarTerm();
|
||
if (nextTerm == null) return;
|
||
|
||
final scheduledTime = DateTime(
|
||
nextTerm['year'] as int,
|
||
nextTerm['month'] as int,
|
||
nextTerm['day'] as int,
|
||
8,
|
||
);
|
||
|
||
await LocalNotificationService.scheduleOnce(
|
||
id: 2001,
|
||
title: '闲言 · ${nextTerm['emoji']} ${nextTerm['name']}',
|
||
body: '今日${nextTerm['name']},${nextTerm['poem']}',
|
||
scheduledTime: scheduledTime,
|
||
payload: 'solar_term',
|
||
);
|
||
}
|
||
|
||
static Map<String, dynamic>? _getNextSolarTerm() {
|
||
final now = DateTime.now();
|
||
final terms = _solarTerms2026;
|
||
for (final term in terms) {
|
||
final date = DateTime(
|
||
term['year'] as int,
|
||
term['month'] as int,
|
||
term['day'] as int,
|
||
);
|
||
if (date.isAfter(now)) return term;
|
||
}
|
||
return terms.isNotEmpty ? terms.first : null;
|
||
}
|
||
|
||
static bool get isNotificationsEnabled =>
|
||
KvStorage.getBool(_keyNotificationsEnabled) ?? false;
|
||
|
||
static bool get isDailySentenceEnabled =>
|
||
KvStorage.getBool(_keyDailySentenceEnabled) ?? true;
|
||
|
||
static bool get isSigninReminderEnabled =>
|
||
KvStorage.getBool(_keySigninReminderEnabled) ?? true;
|
||
|
||
static bool get isSolarTermEnabled =>
|
||
KvStorage.getBool(_keySolarTermEnabled) ?? true;
|
||
|
||
static int get dailySentenceHour =>
|
||
KvStorage.getInt(_keyDailySentenceHour) ?? 8;
|
||
|
||
static int get dailySentenceMinute =>
|
||
KvStorage.getInt(_keyDailySentenceMinute) ?? 0;
|
||
|
||
static int get signinReminderHour =>
|
||
KvStorage.getInt(_keySigninReminderHour) ?? 20;
|
||
|
||
static int get signinReminderMinute =>
|
||
KvStorage.getInt(_keySigninReminderMinute) ?? 0;
|
||
|
||
static bool get isFortuneEnabled =>
|
||
KvStorage.getBool(_keyFortuneEnabled) ?? false;
|
||
|
||
static int get fortuneHour => KvStorage.getInt(_keyFortuneHour) ?? 8;
|
||
|
||
static int get fortuneMinute => KvStorage.getInt(_keyFortuneMinute) ?? 0;
|
||
|
||
static bool get isStudyProgressEnabled =>
|
||
KvStorage.getBool(_keyStudyProgressEnabled) ?? false;
|
||
|
||
static Future<void> setNotificationsEnabled(bool v) async {
|
||
await KvStorage.setBool(_keyNotificationsEnabled, v);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setDailySentenceEnabled(bool v) async {
|
||
await KvStorage.setBool(_keyDailySentenceEnabled, v);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setSigninReminderEnabled(bool v) async {
|
||
await KvStorage.setBool(_keySigninReminderEnabled, v);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setSolarTermEnabled(bool v) async {
|
||
await KvStorage.setBool(_keySolarTermEnabled, v);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setDailySentenceTime(int hour, int minute) async {
|
||
await KvStorage.setInt(_keyDailySentenceHour, hour);
|
||
await KvStorage.setInt(_keyDailySentenceMinute, minute);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setSigninReminderTime(int hour, int minute) async {
|
||
await KvStorage.setInt(_keySigninReminderHour, hour);
|
||
await KvStorage.setInt(_keySigninReminderMinute, minute);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setFortuneEnabled(bool v) async {
|
||
await KvStorage.setBool(_keyFortuneEnabled, v);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setFortuneTime(int hour, int minute) async {
|
||
await KvStorage.setInt(_keyFortuneHour, hour);
|
||
await KvStorage.setInt(_keyFortuneMinute, minute);
|
||
await configureAll();
|
||
}
|
||
|
||
static Future<void> setStudyProgressEnabled(bool v) async {
|
||
await KvStorage.setBool(_keyStudyProgressEnabled, v);
|
||
await configureAll();
|
||
}
|
||
|
||
static final List<Map<String, dynamic>> _solarTerms2026 = [
|
||
{
|
||
'year': 2026,
|
||
'month': 1,
|
||
'day': 5,
|
||
'name': '小寒',
|
||
'emoji': '❄️',
|
||
'poem': '小寒连大吕,欢鹊垒新巢',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 1,
|
||
'day': 20,
|
||
'name': '大寒',
|
||
'emoji': '🧊',
|
||
'poem': '大寒须守火,无事不出门',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 2,
|
||
'day': 4,
|
||
'name': '立春',
|
||
'emoji': '🌱',
|
||
'poem': '春风如贵客,一到便繁华',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 2,
|
||
'day': 18,
|
||
'name': '雨水',
|
||
'emoji': '🌧️',
|
||
'poem': '好雨知时节,当春乃发生',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 3,
|
||
'day': 5,
|
||
'name': '惊蛰',
|
||
'emoji': '⚡',
|
||
'poem': '微雨众卉新,一雷惊蛰始',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 3,
|
||
'day': 20,
|
||
'name': '春分',
|
||
'emoji': '🌸',
|
||
'poem': '雪入春分省见稀,半开桃李不胜威',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 4,
|
||
'day': 5,
|
||
'name': '清明',
|
||
'emoji': '🍃',
|
||
'poem': '清明时节雨纷纷,路上行人欲断魂',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 4,
|
||
'day': 20,
|
||
'name': '谷雨',
|
||
'emoji': '🌾',
|
||
'poem': '谷雨如丝复似尘,煮瓶浮蜡正尝新',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 5,
|
||
'day': 5,
|
||
'name': '立夏',
|
||
'emoji': '☀️',
|
||
'poem': '绿树阴浓夏日长,楼台倒影入池塘',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 5,
|
||
'day': 21,
|
||
'name': '小满',
|
||
'emoji': '🌿',
|
||
'poem': '夜莺啼绿柳,皓月醒长空',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 6,
|
||
'day': 5,
|
||
'name': '芒种',
|
||
'emoji': '🌻',
|
||
'poem': '时雨及芒种,四野皆插秧',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 6,
|
||
'day': 21,
|
||
'name': '夏至',
|
||
'emoji': '🌞',
|
||
'poem': '昼晷已云极,宵漏自此长',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 7,
|
||
'day': 7,
|
||
'name': '小暑',
|
||
'emoji': '🌡️',
|
||
'poem': '倏忽温风至,因循小暑来',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 7,
|
||
'day': 22,
|
||
'name': '大暑',
|
||
'emoji': '🔥',
|
||
'poem': '大暑三秋近,林钟九夏移',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 8,
|
||
'day': 7,
|
||
'name': '立秋',
|
||
'emoji': '🍂',
|
||
'poem': '乳鸦啼散玉屏空,一枕新凉一扇风',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 8,
|
||
'day': 23,
|
||
'name': '处暑',
|
||
'emoji': '🎐',
|
||
'poem': '处暑无三日,新凉直万金',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 9,
|
||
'day': 7,
|
||
'name': '白露',
|
||
'emoji': '💎',
|
||
'poem': '露从今夜白,月是故乡明',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 9,
|
||
'day': 23,
|
||
'name': '秋分',
|
||
'emoji': '🍁',
|
||
'poem': '金气秋分,风清露冷秋期半',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 10,
|
||
'day': 8,
|
||
'name': '寒露',
|
||
'emoji': '💧',
|
||
'poem': '袅袅凉风动,凄凄寒露零',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 10,
|
||
'day': 23,
|
||
'name': '霜降',
|
||
'emoji': '🧊',
|
||
'poem': '霜降碧天静,秋事促西风',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 11,
|
||
'day': 7,
|
||
'name': '立冬',
|
||
'emoji': '🧣',
|
||
'poem': '冻笔新诗懒写,寒炉美酒时温',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 11,
|
||
'day': 22,
|
||
'name': '小雪',
|
||
'emoji': '🌨️',
|
||
'poem': '片片互玲珑,飞扬玉漏终',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 12,
|
||
'day': 7,
|
||
'name': '大雪',
|
||
'emoji': '❄️',
|
||
'poem': '大雪江南见未曾,今年方始是严凝',
|
||
},
|
||
{
|
||
'year': 2026,
|
||
'month': 12,
|
||
'day': 21,
|
||
'name': '冬至',
|
||
'emoji': '🥟',
|
||
'poem': '天时人事日相催,冬至阳生春又来',
|
||
},
|
||
];
|
||
}
|