Skip to content

Commit 9f76151

Browse files
committed
feat(service): implement AppStatusService for lifecycle-based status checks
- Add AppStatusService to monitor app lifecycle and trigger status checks - Integrate with AppBloc for fetching app configuration - Implement periodic checks using Timer for real-time status updates - Register as WidgetsBindingObserver to listen for app resume events - Include cleanup method to dispose resources properly
1 parent 749a452 commit 9f76151

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import 'dart:async';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_bloc/flutter_bloc.dart';
5+
import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart';
6+
7+
/// {@template app_status_service}
8+
/// A service dedicated to monitoring the application's lifecycle and
9+
/// proactively triggering status checks.
10+
///
11+
/// This service ensures that the application can react to server-side
12+
/// status changes (like maintenance mode or forced updates) in real-time,
13+
/// both when the app is resumed from the background and during extended
14+
/// foreground sessions.
15+
///
16+
/// It works by:
17+
/// 1. Implementing [WidgetsBindingObserver] to listen for app lifecycle events.
18+
/// 2. Triggering a remote configuration fetch via the [AppBloc] whenever the
19+
/// app is resumed (`AppLifecycleState.resumed`).
20+
/// 3. Using a periodic [Timer] to trigger fetches at a regular interval,
21+
/// catching status changes even if the app remains in the foreground.
22+
/// {@endtemplate}
23+
class AppStatusService with WidgetsBindingObserver {
24+
/// {@macro app_status_service}
25+
///
26+
/// Requires a [BuildContext] to access the [AppBloc] and a [Duration]
27+
/// for the periodic check interval.
28+
AppStatusService({
29+
required BuildContext context,
30+
required Duration checkInterval,
31+
}) : _context = context,
32+
_checkInterval = checkInterval {
33+
// Immediately register this service as a lifecycle observer.
34+
WidgetsBinding.instance.addObserver(this);
35+
// Start the periodic checks.
36+
_startPeriodicChecks();
37+
}
38+
39+
/// The build context used to look up the AppBloc.
40+
final BuildContext _context;
41+
42+
/// The interval at which to perform periodic status checks.
43+
final Duration _checkInterval;
44+
45+
/// The timer responsible for periodic checks.
46+
Timer? _timer;
47+
48+
/// Starts the periodic timer to trigger config fetches.
49+
///
50+
/// This ensures that even if the app stays in the foreground, it will
51+
/// eventually learn about new server-side status changes.
52+
void _startPeriodicChecks() {
53+
// Cancel any existing timer to prevent duplicates.
54+
_timer?.cancel();
55+
// Create a new periodic timer.
56+
_timer = Timer.periodic(_checkInterval, (_) {
57+
print(
58+
'[AppStatusService] Periodic check triggered. Requesting AppConfig fetch.',
59+
);
60+
// Add the event to the AppBloc to fetch the latest config.
61+
_context.read<AppBloc>().add(const AppConfigFetchRequested());
62+
});
63+
}
64+
65+
/// Overridden from [WidgetsBindingObserver].
66+
///
67+
/// This method is called whenever the application's lifecycle state changes.
68+
@override
69+
void didChangeAppLifecycleState(AppLifecycleState state) {
70+
// We are only interested in the 'resumed' state.
71+
if (state == AppLifecycleState.resumed) {
72+
print(
73+
'[AppStatusService] App resumed. Requesting AppConfig fetch.',
74+
);
75+
// When the app comes to the foreground, immediately trigger a check.
76+
// This is crucial for catching maintenance mode that was enabled
77+
// while the app was in the background.
78+
_context.read<AppBloc>().add(const AppConfigFetchRequested());
79+
}
80+
}
81+
82+
/// Cleans up resources used by the service.
83+
///
84+
/// This must be called when the service is no longer needed (e.g., when
85+
/// the main app widget is disposed) to prevent memory leaks from the
86+
/// timer and the observer registration.
87+
void dispose() {
88+
print('[AppStatusService] Disposing service.');
89+
// Stop the periodic timer.
90+
_timer?.cancel();
91+
// Remove this object from the list of lifecycle observers.
92+
WidgetsBinding.instance.removeObserver(this);
93+
}
94+
}

0 commit comments

Comments
 (0)