Polish navigation, Quran flows, and sharing UX
This commit is contained in:
86
lib/data/services/notification_runtime_service.dart
Normal file
86
lib/data/services/notification_runtime_service.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../local/hive_boxes.dart';
|
||||
import '../local/models/app_settings.dart';
|
||||
|
||||
/// Runtime persistence for notification counters and cursors.
|
||||
class NotificationRuntimeService {
|
||||
NotificationRuntimeService._();
|
||||
static final NotificationRuntimeService instance =
|
||||
NotificationRuntimeService._();
|
||||
|
||||
static const _nonPrayerCountPrefix = 'non_prayer_push_count.';
|
||||
static const _lastRemoteSyncKey = 'remote.last_sync_at';
|
||||
static const _lastWeeklySummaryKey = 'summary.last_week_key';
|
||||
|
||||
Box get _box => Hive.box(HiveBoxes.notificationRuntime);
|
||||
|
||||
String _todayKey() => DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||||
|
||||
int nonPrayerPushCountToday() {
|
||||
return (_box.get('$_nonPrayerCountPrefix${_todayKey()}') as int?) ?? 0;
|
||||
}
|
||||
|
||||
Future<void> incrementNonPrayerPushCount() async {
|
||||
final key = '$_nonPrayerCountPrefix${_todayKey()}';
|
||||
final next = ((_box.get(key) as int?) ?? 0) + 1;
|
||||
await _box.put(key, next);
|
||||
}
|
||||
|
||||
bool isWithinQuietHours(AppSettings settings, {DateTime? now}) {
|
||||
final current = now ?? DateTime.now();
|
||||
final startParts = _parseHourMinute(settings.quietHoursStart);
|
||||
final endParts = _parseHourMinute(settings.quietHoursEnd);
|
||||
if (startParts == null || endParts == null) return false;
|
||||
|
||||
final currentMinutes = current.hour * 60 + current.minute;
|
||||
final startMinutes = startParts.$1 * 60 + startParts.$2;
|
||||
final endMinutes = endParts.$1 * 60 + endParts.$2;
|
||||
|
||||
if (startMinutes == endMinutes) {
|
||||
// Same value means quiet-hours disabled.
|
||||
return false;
|
||||
}
|
||||
if (startMinutes < endMinutes) {
|
||||
return currentMinutes >= startMinutes && currentMinutes < endMinutes;
|
||||
}
|
||||
// Overnight interval (e.g. 22:00 -> 05:00).
|
||||
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
||||
}
|
||||
|
||||
bool canSendNonPrayerPush(AppSettings settings, {DateTime? now}) {
|
||||
if (!settings.alertsEnabled) return false;
|
||||
if (isWithinQuietHours(settings, now: now)) return false;
|
||||
return nonPrayerPushCountToday() < settings.maxNonPrayerPushPerDay;
|
||||
}
|
||||
|
||||
DateTime? lastRemoteSyncAt() {
|
||||
final raw = (_box.get(_lastRemoteSyncKey) ?? '').toString();
|
||||
if (raw.isEmpty) return null;
|
||||
return DateTime.tryParse(raw);
|
||||
}
|
||||
|
||||
Future<void> setLastRemoteSyncAt(DateTime value) async {
|
||||
await _box.put(_lastRemoteSyncKey, value.toIso8601String());
|
||||
}
|
||||
|
||||
String? lastWeeklySummaryWeekKey() {
|
||||
final raw = (_box.get(_lastWeeklySummaryKey) ?? '').toString();
|
||||
return raw.isEmpty ? null : raw;
|
||||
}
|
||||
|
||||
Future<void> setLastWeeklySummaryWeekKey(String key) async {
|
||||
await _box.put(_lastWeeklySummaryKey, key);
|
||||
}
|
||||
|
||||
(int, int)? _parseHourMinute(String value) {
|
||||
final match = RegExp(r'^(\d{1,2}):(\d{2})$').firstMatch(value.trim());
|
||||
if (match == null) return null;
|
||||
final hour = int.tryParse(match.group(1) ?? '');
|
||||
final minute = int.tryParse(match.group(2) ?? '');
|
||||
if (hour == null || minute == null) return null;
|
||||
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
|
||||
return (hour, minute);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user