feat(offline-first): persist hijri+unsplash cache and scale secondary times
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../local/models.dart';
|
||||
import 'hijri_service.dart';
|
||||
import 'myquran_service.dart';
|
||||
|
||||
class ScheduleCacheStatus {
|
||||
@@ -196,6 +199,71 @@ class SyncService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pruneHijriCache(DateTime referenceDate) async {
|
||||
if (!Hive.isBoxOpen(HiveBoxes.hijriCache)) return;
|
||||
final hijriBox = Hive.box<String>(HiveBoxes.hijriCache);
|
||||
final staleKeys = staleScheduleKeys(
|
||||
hijriBox.keys.cast<String>(),
|
||||
referenceDate,
|
||||
);
|
||||
if (staleKeys.isNotEmpty) {
|
||||
await hijriBox.deleteAll(staleKeys);
|
||||
await hijriBox.compact();
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> _priorityHijriWarmupKeys(
|
||||
Set<String> allDateKeys,
|
||||
DateTime referenceDate,
|
||||
) {
|
||||
final prioritized = <String>{};
|
||||
for (var offset = 0; offset <= 7; offset++) {
|
||||
final key = _canonicalDateKey(referenceDate.add(Duration(days: offset)));
|
||||
if (allDateKeys.contains(key)) prioritized.add(key);
|
||||
}
|
||||
return prioritized;
|
||||
}
|
||||
|
||||
Set<String> _collectRollingWindowScheduleDateKeys(
|
||||
Box<DailyPrayerSchedule> scheduleBox,
|
||||
DateTime referenceDate,
|
||||
) {
|
||||
final allowedMonths = rollingWindowMonths(referenceDate);
|
||||
final keys = <String>{};
|
||||
|
||||
for (final rawKey in scheduleBox.keys) {
|
||||
if (rawKey is! String) continue;
|
||||
final parsed = _parseScheduleDate(rawKey);
|
||||
if (parsed == null) continue;
|
||||
final monthKey = DateFormat('yyyy-MM').format(parsed);
|
||||
if (!allowedMonths.contains(monthKey)) continue;
|
||||
keys.add(_canonicalDateKey(parsed));
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
Future<void> _warmHijriCacheForScheduleRange(
|
||||
Box<DailyPrayerSchedule> scheduleBox,
|
||||
DateTime referenceDate,
|
||||
) async {
|
||||
final scheduleDateKeys = _collectRollingWindowScheduleDateKeys(
|
||||
scheduleBox,
|
||||
referenceDate,
|
||||
);
|
||||
if (scheduleDateKeys.isEmpty) return;
|
||||
|
||||
final priorityKeys = _priorityHijriWarmupKeys(scheduleDateKeys, referenceDate);
|
||||
if (priorityKeys.isNotEmpty) {
|
||||
await HijriCalendarService.instance.warmCacheForDateKeys(priorityKeys);
|
||||
}
|
||||
|
||||
final remainingKeys = scheduleDateKeys.difference(priorityKeys);
|
||||
if (remainingKeys.isNotEmpty) {
|
||||
unawaited(HijriCalendarService.instance.warmCacheForDateKeys(remainingKeys));
|
||||
}
|
||||
}
|
||||
|
||||
bool _shouldAttemptAutoRefresh({
|
||||
required ScheduleCacheStatus status,
|
||||
required bool hasTodayData,
|
||||
@@ -288,9 +356,11 @@ class SyncService {
|
||||
if (success) {
|
||||
if (hasCurrentMonth && hasNextMonth) {
|
||||
await _pruneScheduleCache(scheduleBox, now);
|
||||
await _pruneHijriCache(now);
|
||||
}
|
||||
settings.lastSyncDate = DateFormat('yyyy-MM-dd HH:mm').format(now);
|
||||
await settings.save();
|
||||
await _warmHijriCacheForScheduleRange(scheduleBox, now);
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -306,16 +376,20 @@ class SyncService {
|
||||
}
|
||||
|
||||
final now = referenceDate ?? DateTime.now();
|
||||
final scheduleBox =
|
||||
Hive.box<DailyPrayerSchedule>(HiveBoxes.prayerSchedule);
|
||||
final status = getCacheStatus(now);
|
||||
final hasTodayData = getTodaySchedule(now) != null;
|
||||
|
||||
if (!_shouldAttemptAutoRefresh(status: status, hasTodayData: hasTodayData)) {
|
||||
unawaited(_warmHijriCacheForScheduleRange(scheduleBox, now));
|
||||
return const AutoRefreshResult.skipped('cache-fresh');
|
||||
}
|
||||
|
||||
final lastAttempt = _parseAttemptTimestamp(settings.lastAutoSyncAttemptDate);
|
||||
if (lastAttempt != null &&
|
||||
now.difference(lastAttempt) < _autoRefreshCooldown) {
|
||||
unawaited(_warmHijriCacheForScheduleRange(scheduleBox, now));
|
||||
return const AutoRefreshResult.skipped('cooldown');
|
||||
}
|
||||
|
||||
@@ -323,6 +397,9 @@ class SyncService {
|
||||
await settings.save();
|
||||
|
||||
final synced = await syncMonthlyData(referenceDate: now);
|
||||
if (!synced) {
|
||||
unawaited(_warmHijriCacheForScheduleRange(scheduleBox, now));
|
||||
}
|
||||
return synced
|
||||
? const AutoRefreshResult.synced()
|
||||
: const AutoRefreshResult.failed('sync-failed');
|
||||
|
||||
Reference in New Issue
Block a user