feat: add local-first private AI digest workflow
Migrate app code into canonical feature slices, add phone-only AI digest scheduling and review, wire local notification/background task support, and cover the flow with tests.
This commit is contained in:
@@ -1,107 +1,2 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:relationship_saver/core/config/app_config.dart';
|
||||
import 'package:relationship_saver/core/network/reachability/network_reachability.dart';
|
||||
import 'package:relationship_saver/core/network/reachability/network_reachability_provider.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_auto_trigger_controller.dart';
|
||||
import 'package:relationship_saver/features/sync/sync_coordinator.dart';
|
||||
|
||||
/// Runs lightweight background sync triggers while authenticated.
|
||||
class SyncBackgroundRunner extends ConsumerStatefulWidget {
|
||||
const SyncBackgroundRunner({required this.child, super.key});
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
ConsumerState<SyncBackgroundRunner> createState() =>
|
||||
_SyncBackgroundRunnerState();
|
||||
}
|
||||
|
||||
class _SyncBackgroundRunnerState extends ConsumerState<SyncBackgroundRunner>
|
||||
with WidgetsBindingObserver {
|
||||
late final SyncAutoTriggerController _controller;
|
||||
Timer? _periodicTimer;
|
||||
StreamSubscription<bool>? _reachabilitySubscription;
|
||||
bool? _lastReachable;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final reachability = ref.read(networkReachabilityProvider);
|
||||
_controller = SyncAutoTriggerController(
|
||||
syncNow: () => ref.read(syncCoordinatorProvider).syncNow(),
|
||||
now: DateTime.now,
|
||||
minimumInterval: Duration(
|
||||
seconds: AppConfig.backgroundSyncIntervalSeconds,
|
||||
),
|
||||
canTrigger: () async {
|
||||
if (AppConfig.useFakeBackend) {
|
||||
return true;
|
||||
}
|
||||
return reachability.isReachable();
|
||||
},
|
||||
);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_configurePeriodicRunner();
|
||||
_configureReachabilityRunner(reachability);
|
||||
if (AppConfig.enableBackgroundSync) {
|
||||
unawaited(_controller.trigger(ignoreCooldown: true));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (!AppConfig.enableBackgroundSync) {
|
||||
return;
|
||||
}
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
unawaited(_controller.trigger(ignoreCooldown: true));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
_periodicTimer?.cancel();
|
||||
_reachabilitySubscription?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => widget.child;
|
||||
|
||||
void _configurePeriodicRunner() {
|
||||
if (!AppConfig.enableBackgroundSync) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int seconds = AppConfig.backgroundSyncIntervalSeconds;
|
||||
if (seconds <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_periodicTimer = Timer.periodic(Duration(seconds: seconds), (_) {
|
||||
unawaited(_controller.trigger());
|
||||
});
|
||||
}
|
||||
|
||||
void _configureReachabilityRunner(NetworkReachability reachability) {
|
||||
if (!AppConfig.enableBackgroundSync) {
|
||||
return;
|
||||
}
|
||||
_reachabilitySubscription = reachability.watch().listen((bool reachable) {
|
||||
final bool? previous = _lastReachable;
|
||||
_lastReachable = reachable;
|
||||
if (reachable && previous == false) {
|
||||
unawaited(_controller.trigger(ignoreCooldown: true));
|
||||
}
|
||||
});
|
||||
unawaited(_primeReachabilityState(reachability));
|
||||
}
|
||||
|
||||
Future<void> _primeReachabilityState(NetworkReachability reachability) async {
|
||||
_lastReachable = await reachability.isReachable();
|
||||
}
|
||||
}
|
||||
// Legacy compatibility export for the sync background runner.
|
||||
export 'package:relationship_saver/features/sync/application/sync_background_runner.dart';
|
||||
|
||||
Reference in New Issue
Block a user