refactored lesson details, centralized logout logic, and added resume re-fetch

This commit is contained in:
2026-05-06 16:27:45 +02:00
parent 71506aab2d
commit 50d2941e52
11 changed files with 309 additions and 68 deletions
+61 -1
View File
@@ -15,6 +15,7 @@ import 'package:jiffy/jiffy.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:path_provider/path_provider.dart';
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'api/mhsl/breaker/get_breakers/get_breakers_response.dart';
import 'app.dart';
@@ -33,6 +34,7 @@ import 'theming/light_app_theme.dart';
import 'view/login/login.dart';
import 'widget/app_progress_indicator.dart';
import 'widget/breaker/breaker.dart';
import 'widget/debug/cache_view.dart';
Future<void> main() async {
log('MarianumMobile started');
@@ -160,7 +162,40 @@ class _MainState extends State<Main> {
home: LoaderOverlay(
child: Breaker(
breaker: BreakerArea.global,
child: BlocBuilder<AccountBloc, AccountState>(
child: BlocConsumer<AccountBloc, AccountState>(
listenWhen: (previous, current) => previous.status != current.status,
listener: (context, accountState) {
if (accountState.status != AccountStatus.loggedOut) return;
// Routes pushed via AppRoutes (e.g. Settings) live on the
// root navigator and survive the home swap below, so they
// would still cover the Login screen after logout. Pop
// them here so the user immediately sees Login.
final navigator = Navigator.of(context);
if (navigator.canPop()) {
navigator.popUntil((route) => route.isFirst);
}
// Capture bloc references before the post-frame callback
// — by the time it runs the dialog/Settings context is
// gone but this listener context is still valid.
final settingsCubit = context.read<SettingsCubit>();
final timetableBloc = context.read<TimetableBloc>();
final chatListBloc = context.read<ChatListBloc>();
final chatBloc = context.read<ChatBloc>();
final breakerBloc = context.read<BreakerBloc>();
// Defer the actual wipe until after this frame so the
// App tree (TimetableBloc/ChatListBloc watchers etc.)
// is already torn down. Resetting blocs while App is
// still in front caused a black-frame race.
WidgetsBinding.instance.addPostFrameCallback((_) {
unawaited(_wipeUserState(
settingsCubit: settingsCubit,
timetableBloc: timetableBloc,
chatListBloc: chatListBloc,
chatBloc: chatBloc,
breakerBloc: breakerBloc,
));
});
},
builder: (context, accountState) {
switch (accountState.status) {
case AccountStatus.loggedIn:
@@ -190,3 +225,28 @@ class _MainState extends State<Main> {
),
);
}
Future<void> _wipeUserState({
required SettingsCubit settingsCubit,
required TimetableBloc timetableBloc,
required ChatListBloc chatListBloc,
required ChatBloc chatBloc,
required BreakerBloc breakerBloc,
}) async {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
PaintingBinding.instance.imageCache.clear();
await settingsCubit.reset();
await Future.wait([
timetableBloc.reset(),
chatListBloc.reset(),
chatBloc.reset(),
breakerBloc.reset(),
]);
await HydratedBloc.storage.clear();
await const CacheView().clear();
} catch (e, s) {
log('User state wipe failed: $e', stackTrace: s);
}
}