import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:intl/intl.dart'; import 'package:workmanager/workmanager.dart'; import '../local/hive_boxes.dart'; import '../local/models/app_settings.dart'; import 'myquran_sholat_service.dart'; import 'notification_orchestrator_service.dart'; import 'notification_service.dart'; class BackgroundSyncService { BackgroundSyncService._(); static final BackgroundSyncService instance = BackgroundSyncService._(); static const String periodicTaskName = 'jamshalat_periodic_sync'; static const String periodicUniqueName = 'jamshalat_periodic_sync_unique'; Future init() async { await Workmanager().initialize(_workmanagerCallbackDispatcher); } Future registerPeriodicSync() async { await Workmanager().registerPeriodicTask( periodicUniqueName, periodicTaskName, existingWorkPolicy: ExistingPeriodicWorkPolicy.update, frequency: const Duration(hours: 6), initialDelay: const Duration(minutes: 15), constraints: Constraints( networkType: NetworkType.connected, ), backoffPolicy: BackoffPolicy.exponential, backoffPolicyDelay: const Duration(minutes: 10), ); } static Future runSyncPass() async { WidgetsFlutterBinding.ensureInitialized(); await initHive(); final settingsBox = Hive.box(HiveBoxes.settings); final settings = settingsBox.get('default') ?? AppSettings(); final cityId = _resolveCityId(settings); final schedulesByDate = await _buildWindowSchedules(cityId); if (schedulesByDate.isNotEmpty) { await NotificationService.instance.syncPrayerNotifications( cityId: cityId, adhanEnabled: settings.adhanEnabled, iqamahOffset: settings.iqamahOffset, schedulesByDate: schedulesByDate, reportReminderEnabled: settings.shalatReportReminderEnabled, reportReminderDelayMinutes: settings.shalatReportReminderDelayMinutes, reportReminderRepeatCount: settings.shalatReportReminderRepeatCount, reportReminderRepeatIntervalMinutes: settings.shalatReportReminderRepeatIntervalMinutes, ); } await NotificationService.instance.syncHabitNotifications( settings: settings, ); await NotificationOrchestratorService.instance.runPassivePass( settings: settings, ); } static Future>> _buildWindowSchedules( String cityId) async { final now = DateTime.now(); final startDate = DateTime(now.year, now.month, now.day); final endDate = startDate.add(const Duration(days: 35)); final monthKeys = { DateFormat('yyyy-MM').format(startDate), DateFormat('yyyy-MM').format(endDate), }; final schedulesByDate = >{}; for (final monthKey in monthKeys) { final monthly = await MyQuranSholatService.instance .getMonthlySchedule(cityId, monthKey); for (final entry in monthly.entries) { final date = DateTime.tryParse(entry.key); if (date == null) continue; final normalized = DateTime(date.year, date.month, date.day); if (normalized.isBefore(startDate) || normalized.isAfter(endDate)) { continue; } schedulesByDate[entry.key] = entry.value; } } return schedulesByDate; } static String _resolveCityId(AppSettings settings) { final stored = settings.lastCityName ?? ''; if (stored.contains('|')) { return stored.split('|').last; } return '58a2fc6ed39fd083f55d4182bf88826d'; } } @pragma('vm:entry-point') void _workmanagerCallbackDispatcher() { Workmanager().executeTask((task, inputData) async { if (task == BackgroundSyncService.periodicTaskName) { await BackgroundSyncService.runSyncPass(); return true; } return true; }); }