diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index d7a3169..7c08f25 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
+
)
+#import
+#else
+@import firebase_core;
+#endif
+
+#if __has_include()
+#import
+#else
+@import firebase_messaging;
+#endif
+
#if __has_include()
#import
#else
@@ -78,11 +90,19 @@
@import url_launcher_ios;
#endif
+#if __has_include()
+#import
+#else
+@import workmanager_apple;
+#endif
+
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject*)registry {
[AudioServicePlugin registerWithRegistrar:[registry registrarForPlugin:@"AudioServicePlugin"]];
[AudioSessionPlugin registerWithRegistrar:[registry registrarForPlugin:@"AudioSessionPlugin"]];
+ [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]];
+ [FLTFirebaseMessagingPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseMessagingPlugin"]];
[FlutterCompassPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterCompassPlugin"]];
[FlutterLocalNotificationsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterLocalNotificationsPlugin"]];
[FlutterQiblahPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterQiblahPlugin"]];
@@ -93,6 +113,7 @@
[FPPSharePlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPSharePlusPlugin"]];
[SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]];
[URLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"URLLauncherPlugin"]];
+ [WorkmanagerPlugin registerWithRegistrar:[registry registrarForPlugin:@"WorkmanagerPlugin"]];
}
@end
diff --git a/lib/data/local/models/app_settings.dart b/lib/data/local/models/app_settings.dart
index 43bae76..c2b3e2f 100644
--- a/lib/data/local/models/app_settings.dart
+++ b/lib/data/local/models/app_settings.dart
@@ -104,6 +104,21 @@ class AppSettings extends HiveObject {
@HiveField(32)
bool mirrorAdzanToInbox;
+ @HiveField(33)
+ bool tilawahAutoContinueNextSurah;
+
+ @HiveField(34)
+ bool shalatReportReminderEnabled;
+
+ @HiveField(35)
+ int shalatReportReminderDelayMinutes;
+
+ @HiveField(36)
+ int shalatReportReminderRepeatCount;
+
+ @HiveField(37)
+ int shalatReportReminderRepeatIntervalMinutes;
+
AppSettings({
this.userName = 'User',
this.userEmail = '',
@@ -138,6 +153,11 @@ class AppSettings extends HiveObject {
this.quietHoursEnd = '05:00',
this.maxNonPrayerPushPerDay = 2,
this.mirrorAdzanToInbox = false,
+ this.tilawahAutoContinueNextSurah = true,
+ this.shalatReportReminderEnabled = true,
+ this.shalatReportReminderDelayMinutes = 30,
+ this.shalatReportReminderRepeatCount = 1,
+ this.shalatReportReminderRepeatIntervalMinutes = 15,
}) : adhanEnabled = adhanEnabled ??
{
'fajr': true,
diff --git a/lib/data/local/models/app_settings.g.dart b/lib/data/local/models/app_settings.g.dart
index a64f890..336f9f5 100644
--- a/lib/data/local/models/app_settings.g.dart
+++ b/lib/data/local/models/app_settings.g.dart
@@ -72,13 +72,23 @@ class AppSettingsAdapter extends TypeAdapter {
fields.containsKey(31) ? fields[31] as int? ?? 2 : 2,
mirrorAdzanToInbox:
fields.containsKey(32) ? fields[32] as bool? ?? false : false,
+ tilawahAutoContinueNextSurah:
+ fields.containsKey(33) ? fields[33] as bool? ?? true : true,
+ shalatReportReminderEnabled:
+ fields.containsKey(34) ? fields[34] as bool? ?? true : true,
+ shalatReportReminderDelayMinutes:
+ fields.containsKey(35) ? fields[35] as int? ?? 30 : 30,
+ shalatReportReminderRepeatCount:
+ fields.containsKey(36) ? fields[36] as int? ?? 1 : 1,
+ shalatReportReminderRepeatIntervalMinutes:
+ fields.containsKey(37) ? fields[37] as int? ?? 15 : 15,
);
}
@override
void write(BinaryWriter writer, AppSettings obj) {
writer
- ..writeByte(33)
+ ..writeByte(38)
..writeByte(0)
..write(obj.userName)
..writeByte(1)
@@ -144,7 +154,17 @@ class AppSettingsAdapter extends TypeAdapter {
..writeByte(31)
..write(obj.maxNonPrayerPushPerDay)
..writeByte(32)
- ..write(obj.mirrorAdzanToInbox);
+ ..write(obj.mirrorAdzanToInbox)
+ ..writeByte(33)
+ ..write(obj.tilawahAutoContinueNextSurah)
+ ..writeByte(34)
+ ..write(obj.shalatReportReminderEnabled)
+ ..writeByte(35)
+ ..write(obj.shalatReportReminderDelayMinutes)
+ ..writeByte(36)
+ ..write(obj.shalatReportReminderRepeatCount)
+ ..writeByte(37)
+ ..write(obj.shalatReportReminderRepeatIntervalMinutes);
}
@override
diff --git a/lib/data/services/background_sync_service.dart b/lib/data/services/background_sync_service.dart
new file mode 100644
index 0000000..c459100
--- /dev/null
+++ b/lib/data/services/background_sync_service.dart
@@ -0,0 +1,117 @@
+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