feat: add app lifecycle refresh coordinator

This commit is contained in:
qzl
2026-03-20 15:39:44 +08:00
parent e64b9c670c
commit f4c07287bc
3 changed files with 80 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
import 'package:flutter/widgets.dart';
class CacheRefreshCoordinator with WidgetsBindingObserver {
final Duration minInterval;
final void Function() onRefresh;
final DateTime Function() now;
DateTime? _lastRefreshedAt;
CacheRefreshCoordinator({
required this.minInterval,
required this.onRefresh,
DateTime Function()? now,
}) : now = now ?? DateTime.now;
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state != AppLifecycleState.resumed) {
return;
}
final current = now();
final last = _lastRefreshedAt;
if (last != null && current.difference(last) < minInterval) {
return;
}
_lastRefreshedAt = current;
onRefresh();
}
}
+24
View File
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'core/constants/app_constants.dart';
import 'core/cache/cache_refresh_coordinator.dart';
import 'core/di/injection.dart';
import 'core/notifications/local_notification_service.dart';
import 'core/notifications/reminder_notification_callbacks.dart';
@@ -14,9 +15,13 @@ import 'features/auth/presentation/bloc/auth_bloc.dart';
import 'features/auth/presentation/bloc/auth_event.dart';
import 'features/auth/presentation/bloc/auth_state.dart';
import 'features/calendar/data/services/calendar_service.dart';
import 'features/calendar/data/services/calendar_repository.dart';
import 'features/calendar/reminders/reminder_action_executor.dart';
import 'features/calendar/reminders/ui/reminder_foreground_presenter.dart';
import 'features/calendar/ui/calendar_state_manager.dart';
import 'features/chat/presentation/bloc/chat_bloc.dart';
import 'features/settings/data/services/settings_user_cache.dart';
import 'features/todo/data/todo_repository.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -44,6 +49,25 @@ void main() async {
final authBloc = sl<AuthBloc>();
authBloc.add(AuthStarted());
final cacheRefreshCoordinator = CacheRefreshCoordinator(
minInterval: const Duration(minutes: 5),
onRefresh: () {
final selected = sl<CalendarStateManager>().selectedDate;
unawaited(
sl<CalendarRepository>().getDayEvents(selected, forceRefresh: true),
);
unawaited(
sl<CalendarRepository>().getMonthEvents(
DateTime(selected.year, selected.month, 1),
forceRefresh: true,
),
);
unawaited(sl<TodoRepository>().getPendingTodos(forceRefresh: true));
unawaited(sl<SettingsUserCache>().getProfile(forceRefresh: true));
},
);
WidgetsBinding.instance.addObserver(cacheRefreshCoordinator);
runApp(
LinksyApp(
authBloc: authBloc,
@@ -0,0 +1,27 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/core/cache/cache_refresh_coordinator.dart';
void main() {
test('resume should trigger refresh only when min interval elapsed', () {
var calls = 0;
var now = DateTime(2026, 3, 20, 10, 0);
final coordinator = CacheRefreshCoordinator(
minInterval: const Duration(minutes: 5),
onRefresh: () => calls += 1,
now: () => now,
);
coordinator.didChangeAppLifecycleState(AppLifecycleState.resumed);
expect(calls, 1);
now = DateTime(2026, 3, 20, 10, 3);
coordinator.didChangeAppLifecycleState(AppLifecycleState.resumed);
expect(calls, 1);
now = DateTime(2026, 3, 20, 10, 6);
coordinator.didChangeAppLifecycleState(AppLifecycleState.resumed);
expect(calls, 2);
});
}