Files
Holzleitner-Lieferservice-App/lib/feature/authentication/presentation/login_enforcer.dart
Dennis Nemec f074d53f3d Phase B+1: Bootstrap-Splash + Logout im Drawer
- AuthBootstrapping als neuer Initial-State im AuthBloc. Beim Cold-Start
  bleibt die App im Splash, bis restoreSession entweder Authenticated
  oder Unauthenticated emittiert — kein sichtbarer LoginPage-Flash mehr
  für Nutzer mit gespeicherter Session.
- LoginEnforcer rendert für AuthBootstrapping ein eigenes Splash-Widget
  mit Logo + Spinner, für Unauthenticated weiterhin die LoginPage.
- AuthBloc._handleRestore emittiert Unauthenticated explizit, wenn
  restoreSession false liefert oder wirft — sonst bliebe der Bootstrap-
  State hängen.
- HomeAppDrawer zeigt jetzt displayName + Personalnummer aus dem
  Authenticated-State im Header und bekommt einen Abmelden-Eintrag
  unten (rot, Confirm-Dialog), der LogoutRequested feuert. Der
  Provider löscht den Refresh-Token aus der Secure Storage und der
  LoginEnforcer routet automatisch zurück auf die LoginPage.
2026-05-15 11:21:57 +02:00

62 lines
1.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/authentication/presentation/login_page.dart';
import '../bloc/auth_bloc.dart';
import '../bloc/auth_state.dart';
/// Routet die App zwischen Bootstrap-Splash, Login-Page und der
/// eigentlichen UI:
/// * `AuthBootstrapping` → Splash (verhindert Login-Page-Flash beim
/// Cold-Start, während der Refresh-Token gegen Keycloak gegengeprüft
/// wird).
/// * `Authenticated` → `child` (= reguläre App).
/// * sonst → LoginPage; `sessionExpired`-Banner wenn ein Refresh
/// serverseitig abgewiesen wurde.
class LoginEnforcer extends StatelessWidget {
final Widget child;
const LoginEnforcer({super.key, required this.child});
@override
Widget build(BuildContext context) {
return BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is Authenticated) {
return child;
}
if (state is AuthBootstrapping) {
return const _AuthBootstrapSplash();
}
final expired = state is Unauthenticated && state.sessionExpired;
return LoginPage(sessionExpired: expired);
},
);
}
}
class _AuthBootstrapSplash extends StatelessWidget {
const _AuthBootstrapSplash();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 60),
child: Image.asset(
'assets/holzleitner_Logo_2017_RZ_transparent.png',
),
),
const SizedBox(height: 32),
const CircularProgressIndicator(),
],
),
),
);
}
}