refactored lesson details, centralized logout logic, and added resume re-fetch
This commit is contained in:
@@ -8,10 +8,16 @@ import 'package:jiffy/jiffy.dart';
|
||||
import 'loadable_state_event.dart';
|
||||
import 'loadable_state_state.dart';
|
||||
|
||||
class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState> {
|
||||
class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState>
|
||||
with WidgetsBindingObserver {
|
||||
late StreamSubscription<List<ConnectivityResult>> _updateStream;
|
||||
void Function()? reFetch;
|
||||
|
||||
/// Last time [reFetch] was triggered by an [AppLifecycleState.resumed]
|
||||
/// event. Used to coalesce rapid foreground/background flips so we don't
|
||||
/// spam the network when the user briefly checks notifications.
|
||||
DateTime _lastResumeRefetch = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
|
||||
LoadableStateBloc() : super(const LoadableStateState(connections: null)) {
|
||||
on<ConnectivityChanged>((event, emit) {
|
||||
emit(event.state);
|
||||
@@ -25,6 +31,23 @@ class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState> {
|
||||
|
||||
Connectivity().checkConnectivity().then(emitConnectivity);
|
||||
_updateStream = Connectivity().onConnectivityChanged.listen(emitConnectivity);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state != AppLifecycleState.resumed) return;
|
||||
final now = DateTime.now();
|
||||
if (now.difference(_lastResumeRefetch) < const Duration(seconds: 10)) return;
|
||||
_lastResumeRefetch = now;
|
||||
// Re-check connectivity. The resulting [ConnectivityChanged] event takes
|
||||
// it from there: its handler updates the offline/online indicator and
|
||||
// triggers [reFetch] when the device is connected, so a stale
|
||||
// "Verbindung fehlgeschlagen" bar from a suspend-time fetch clears as
|
||||
// soon as the network is reachable again.
|
||||
unawaited(Connectivity().checkConnectivity().then(
|
||||
(result) => add(ConnectivityChanged(LoadableStateState(connections: result))),
|
||||
));
|
||||
}
|
||||
|
||||
bool connectivityStatusKnown() => state.connections != null;
|
||||
@@ -55,6 +78,7 @@ class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState> {
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
_updateStream.cancel();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
+17
@@ -60,10 +60,27 @@ abstract class LoadableHydratedBloc<
|
||||
error: event.error
|
||||
)));
|
||||
|
||||
on<Reset<TState>>((event, emit) => emit(const LoadableState(
|
||||
isLoading: false,
|
||||
data: null,
|
||||
lastFetch: null,
|
||||
reFetch: null,
|
||||
error: null,
|
||||
)));
|
||||
|
||||
_repository = repository();
|
||||
fetch();
|
||||
}
|
||||
|
||||
/// Wipes this bloc's persisted state and resets the in-memory state to an
|
||||
/// empty, non-loading shell. Intended for logout: callers must trigger a
|
||||
/// fresh [fetch] (e.g. via [retry] or page-specific refresh) once the user
|
||||
/// is authenticated again, otherwise the UI would stay blank.
|
||||
Future<void> reset() async {
|
||||
await clear();
|
||||
add(Reset<TState>());
|
||||
}
|
||||
|
||||
TState? get innerState => state.data;
|
||||
TRepository get repo => _repository;
|
||||
|
||||
|
||||
+1
@@ -14,3 +14,4 @@ class Error<TState> extends LoadableHydratedBlocEvent<TState> {
|
||||
Error(this.error);
|
||||
}
|
||||
class RefetchStarted<TState> extends LoadableHydratedBlocEvent<TState> {}
|
||||
class Reset<TState> extends LoadableHydratedBlocEvent<TState> {}
|
||||
|
||||
Reference in New Issue
Block a user