fix(ux): show all global messages in front overlay for consistency

This commit is contained in:
Lukas Müllner 2026-03-05 18:37:47 +01:00
parent a2a8917506
commit fded06c85a

View file

@ -51,40 +51,25 @@ final supabase = Supabase.instance.client;
/// Global keys so dialogs & snackbars survive widget-tree rebuilds. /// Global keys so dialogs & snackbars survive widget-tree rebuilds.
final navigatorKey = GlobalKey<NavigatorState>(); final navigatorKey = GlobalKey<NavigatorState>();
final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>(); final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
OverlayEntry? _activeErrorOverlay; OverlayEntry? _activeMessageOverlay;
Timer? _activeErrorOverlayTimer; Timer? _activeMessageOverlayTimer;
/// Show a snackbar safely through the global key. /// Show a snackbar safely through the global key.
void showGlobalSnackBar(String message, {bool isError = false}) { void showGlobalSnackBar(String message, {bool isError = false}) {
if (isError) { _showGlobalMessageOverlay(message, isError: isError);
_showGlobalErrorOverlay(message);
return;
}
final messenger = scaffoldMessengerKey.currentState;
if (messenger == null) return;
messenger
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: isError ? Colors.red : null,
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.fromLTRB(16, 0, 16, 96),
duration: const Duration(seconds: 3),
),
);
} }
void _showGlobalErrorOverlay(String message) { void _showGlobalMessageOverlay(String message, {required bool isError}) {
final overlay = navigatorKey.currentState?.overlay; final overlay = navigatorKey.currentState?.overlay;
if (overlay == null) return; if (overlay == null) return;
_activeErrorOverlayTimer?.cancel(); _activeMessageOverlayTimer?.cancel();
_activeErrorOverlay?.remove(); _activeMessageOverlay?.remove();
_activeErrorOverlay = OverlayEntry( final backgroundColor = isError ? Colors.red : const Color(0xFF1F2937);
final leadingIcon = isError ? Icons.error_outline : Icons.info_outline;
_activeMessageOverlay = OverlayEntry(
builder: (context) { builder: (context) {
final topPadding = MediaQuery.of(context).padding.top; final topPadding = MediaQuery.of(context).padding.top;
return Positioned( return Positioned(
@ -98,7 +83,7 @@ void _showGlobalErrorOverlay(String message) {
child: Container( child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.red, color: backgroundColor,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
boxShadow: const [ boxShadow: const [
BoxShadow( BoxShadow(
@ -110,7 +95,7 @@ void _showGlobalErrorOverlay(String message) {
), ),
child: Row( child: Row(
children: [ children: [
const Icon(Icons.error_outline, color: Colors.white, size: 20), Icon(leadingIcon, color: Colors.white, size: 20),
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
@ -129,12 +114,12 @@ void _showGlobalErrorOverlay(String message) {
}, },
); );
overlay.insert(_activeErrorOverlay!); overlay.insert(_activeMessageOverlay!);
_activeErrorOverlayTimer = Timer(const Duration(seconds: 4), () { _activeMessageOverlayTimer = Timer(const Duration(seconds: 4), () {
_activeErrorOverlay?.remove(); _activeMessageOverlay?.remove();
_activeErrorOverlay = null; _activeMessageOverlay = null;
_activeErrorOverlayTimer = null; _activeMessageOverlayTimer = null;
}); });
} }