feat: align shared app foundations
This commit is contained in:
1 parent
bd6bb0ffce
commit
c5653a3699
21 files changed
+894
-66
No files matched your search
@@ -0,0 +1,84 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
typedef RefreshCallback = FutureOr<void> Function();
|
||||
|
||||
/// Coordinates safe refresh points without owning any feature data.
|
||||
///
|
||||
/// A screen registers its callback while it is visible. Registered callbacks
|
||||
/// run when the app returns to the foreground; callers can also request a
|
||||
/// manual refresh through the returned handle.
|
||||
class RefreshCoordinator with WidgetsBindingObserver {
|
||||
RefreshCoordinator() {
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
final Set<_RefreshRegistration> _registrations = {};
|
||||
AppLifecycleState _lifecycleState = AppLifecycleState.resumed;
|
||||
|
||||
bool get isForeground => _lifecycleState == AppLifecycleState.resumed;
|
||||
|
||||
RefreshRegistration register({
|
||||
required RefreshCallback onRefresh,
|
||||
bool active = true,
|
||||
}) {
|
||||
final registration = _RefreshRegistration(onRefresh, active);
|
||||
_registrations.add(registration);
|
||||
return RefreshRegistration._(this, registration);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
_lifecycleState = state;
|
||||
if (state == AppLifecycleState.resumed) refreshVisible();
|
||||
}
|
||||
|
||||
void refreshVisible() {
|
||||
for (final registration in _registrations) {
|
||||
if (registration.active) unawaited(_run(registration));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _run(_RefreshRegistration registration) async {
|
||||
try {
|
||||
await registration.onRefresh();
|
||||
} catch (_) {
|
||||
// Refresh failures belong to the owning feature's state/UI.
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
_registrations.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class RefreshRegistration {
|
||||
RefreshRegistration._(this._coordinator, this._registration);
|
||||
|
||||
final RefreshCoordinator _coordinator;
|
||||
final _RefreshRegistration _registration;
|
||||
|
||||
bool get active => _registration.active;
|
||||
|
||||
set active(bool value) => _registration.active = value;
|
||||
|
||||
void refreshNow() => _coordinator._run(_registration);
|
||||
|
||||
void dispose() => _coordinator._registrations.remove(_registration);
|
||||
}
|
||||
|
||||
class _RefreshRegistration {
|
||||
_RefreshRegistration(this.onRefresh, this.active);
|
||||
|
||||
final RefreshCallback onRefresh;
|
||||
bool active;
|
||||
}
|
||||
|
||||
final refreshCoordinatorProvider = Provider<RefreshCoordinator>((ref) {
|
||||
final coordinator = RefreshCoordinator();
|
||||
ref.onDispose(coordinator.dispose);
|
||||
return coordinator;
|
||||
});
|
||||
Reference in new issue
Block a user