Improve notifications, tilawah flow, and dzikir structure
This commit is contained in:
@@ -211,21 +211,33 @@ class NotificationService {
|
||||
required Map<String, bool> adhanEnabled,
|
||||
required Map<String, int> iqamahOffset,
|
||||
required Map<String, Map<String, String>> schedulesByDate,
|
||||
required bool reportReminderEnabled,
|
||||
required int reportReminderDelayMinutes,
|
||||
required int reportReminderRepeatCount,
|
||||
required int reportReminderRepeatIntervalMinutes,
|
||||
}) async {
|
||||
await init();
|
||||
|
||||
final hasAnyEnabled = adhanEnabled.values.any((v) => v);
|
||||
if (!hasAnyEnabled) {
|
||||
await cancelAllPending();
|
||||
await _cancelPrayerPending();
|
||||
_lastSyncSignature = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final signature = _buildSyncSignature(
|
||||
cityId, adhanEnabled, iqamahOffset, schedulesByDate);
|
||||
cityId,
|
||||
adhanEnabled,
|
||||
iqamahOffset,
|
||||
schedulesByDate,
|
||||
reportReminderEnabled: reportReminderEnabled,
|
||||
reportReminderDelayMinutes: reportReminderDelayMinutes,
|
||||
reportReminderRepeatCount: reportReminderRepeatCount,
|
||||
reportReminderRepeatIntervalMinutes: reportReminderRepeatIntervalMinutes,
|
||||
);
|
||||
if (_lastSyncSignature == signature) return;
|
||||
|
||||
await cancelAllPending();
|
||||
await _cancelPrayerPending();
|
||||
|
||||
final now = DateTime.now();
|
||||
final dateEntries = schedulesByDate.entries.toList()
|
||||
@@ -278,6 +290,30 @@ class NotificationService {
|
||||
iqamahTime: iqamahTime,
|
||||
offsetMinutes: offsetMinutes,
|
||||
);
|
||||
|
||||
if (!reportReminderEnabled || reportReminderDelayMinutes <= 0) continue;
|
||||
final repeats =
|
||||
reportReminderRepeatCount < 0 ? 0 : reportReminderRepeatCount;
|
||||
final repeatGap = reportReminderRepeatIntervalMinutes <= 0
|
||||
? 15
|
||||
: reportReminderRepeatIntervalMinutes;
|
||||
for (int index = 0; index <= repeats; index++) {
|
||||
final reminderAt = prayerTime.add(
|
||||
Duration(minutes: reportReminderDelayMinutes + (index * repeatGap)),
|
||||
);
|
||||
if (!reminderAt.isAfter(now)) continue;
|
||||
await _scheduleShalatReportReminder(
|
||||
id: _reportReminderId(
|
||||
cityId: cityId,
|
||||
dateKey: dateEntry.key,
|
||||
prayerKey: canonicalPrayer,
|
||||
reminderIndex: index,
|
||||
),
|
||||
prayerName: _localizedPrayerName(canonicalPrayer),
|
||||
reminderTime: reminderAt,
|
||||
reminderIndex: index,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,12 +431,30 @@ class NotificationService {
|
||||
return isIqamah ? bounded + 800000 : bounded + 100000;
|
||||
}
|
||||
|
||||
int _reportReminderId({
|
||||
required String cityId,
|
||||
required String dateKey,
|
||||
required String prayerKey,
|
||||
required int reminderIndex,
|
||||
}) {
|
||||
final seed = '$cityId|$dateKey|$prayerKey|report|$reminderIndex';
|
||||
var hash = 23;
|
||||
for (final rune in seed.runes) {
|
||||
hash = 43 * hash + rune;
|
||||
}
|
||||
return 700000 + (hash.abs() % 90000);
|
||||
}
|
||||
|
||||
String _buildSyncSignature(
|
||||
String cityId,
|
||||
Map<String, bool> adhanEnabled,
|
||||
Map<String, int> iqamahOffset,
|
||||
Map<String, Map<String, String>> schedulesByDate,
|
||||
) {
|
||||
Map<String, Map<String, String>> schedulesByDate, {
|
||||
required bool reportReminderEnabled,
|
||||
required int reportReminderDelayMinutes,
|
||||
required int reportReminderRepeatCount,
|
||||
required int reportReminderRepeatIntervalMinutes,
|
||||
}) {
|
||||
final sortedAdhan = adhanEnabled.entries.toList()
|
||||
..sort((a, b) => a.key.compareTo(b.key));
|
||||
final sortedIqamah = iqamahOffset.entries.toList()
|
||||
@@ -415,6 +469,9 @@ class NotificationService {
|
||||
for (final e in sortedIqamah) {
|
||||
buffer.write('|${e.key}:${e.value}');
|
||||
}
|
||||
buffer.write(
|
||||
'|report:${reportReminderEnabled ? 1 : 0}:$reportReminderDelayMinutes:$reportReminderRepeatCount:$reportReminderRepeatIntervalMinutes',
|
||||
);
|
||||
for (final dateEntry in sortedDates) {
|
||||
buffer.write('|${dateEntry.key}');
|
||||
final times = dateEntry.value.entries.toList()
|
||||
@@ -426,6 +483,43 @@ class NotificationService {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
Future<void> _scheduleShalatReportReminder({
|
||||
required int id,
|
||||
required String prayerName,
|
||||
required DateTime reminderTime,
|
||||
required int reminderIndex,
|
||||
}) async {
|
||||
final attemptLabel = reminderIndex == 0 ? '' : ' (#${reminderIndex + 1})';
|
||||
await _plugin.zonedSchedule(
|
||||
id: id,
|
||||
title: 'Lapor Shalat • $prayerName$attemptLabel',
|
||||
body: 'Sudah shalat $prayerName? Yuk tandai di checklist sekarang.',
|
||||
scheduledDate: tz.TZDateTime.from(reminderTime, tz.local),
|
||||
notificationDetails: _habitDetails,
|
||||
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
|
||||
payload: 'report|$prayerName|${reminderTime.toIso8601String()}',
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> cancelShalatReportReminders({
|
||||
required String cityId,
|
||||
required String dateKey,
|
||||
required String canonicalPrayer,
|
||||
required int repeatCount,
|
||||
}) async {
|
||||
final repeats = repeatCount < 0 ? 0 : repeatCount;
|
||||
for (int index = 0; index <= repeats; index++) {
|
||||
await _plugin.cancel(
|
||||
id: _reportReminderId(
|
||||
cityId: cityId,
|
||||
dateKey: dateKey,
|
||||
prayerKey: canonicalPrayer,
|
||||
reminderIndex: index,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cancelAllPending() async {
|
||||
try {
|
||||
await _plugin.cancelAllPendingNotifications();
|
||||
@@ -434,6 +528,17 @@ class NotificationService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _cancelPrayerPending() async {
|
||||
final pending = await _plugin.pendingNotificationRequests();
|
||||
for (final request in pending) {
|
||||
final id = request.id;
|
||||
final isPrayerSchedule = id >= 100000 && id < 900000;
|
||||
if (isPrayerSchedule) {
|
||||
await _plugin.cancel(id: id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> pendingCount() async {
|
||||
final pending = await _plugin.pendingNotificationRequests();
|
||||
return pending.length;
|
||||
|
||||
Reference in New Issue
Block a user