import 'package:flutter/material.dart'; import 'package:awesome_snackbar_content/awesome_snackbar_content.dart'; import 'package:flutter/foundation.dart'; /// A global messenger key used to show snackbars from contexts without a /// Scaffold (e.g. dialogs, background callbacks, or tests). final GlobalKey scaffoldMessengerKey = GlobalKey(); /// Helper wrappers around `awesome_snackbar_content` so that callers /// can show snackbars with a consistent look and only specify a message and /// semantic type. /// Enumeration used by callers; the mapping to the package’s /// [ContentType] is internal. enum SnackType { success, info, warning, error } ContentType _mapSnackType(SnackType t) { switch (t) { case SnackType.success: return ContentType.success; case SnackType.info: return ContentType.help; case SnackType.warning: return ContentType.warning; case SnackType.error: return ContentType.failure; } } /// Core function used by all of the convenience helpers below. void showAwesomeSnackBar( BuildContext context, { required String title, required String message, required SnackType snackType, bool retry = true, }) { // Add margin and padding so even very short messages feel substantial. final snackBar = SnackBar( elevation: 0, behavior: SnackBarBehavior.floating, // give floating snackbar some breathing room margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: EdgeInsets.zero, backgroundColor: Colors.transparent, content: Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: AwesomeSnackbarContent( title: title, message: message, contentType: _mapSnackType(snackType), ), ), ); // Prefer a local ScaffoldMessenger when available, but prefer the global // `scaffoldMessengerKey` if it's already ready. This increases reliability // when callers are inside dialogs or other overlays. final globalMessenger = scaffoldMessengerKey.currentState; final localMessenger = ScaffoldMessenger.maybeOf(context); final messenger = localMessenger ?? globalMessenger; if (messenger == null) { if (kDebugMode) { debugPrint( 'showAwesomeSnackBar: no messenger available; scheduling fallback', ); } // If the scaffold messenger is not available yet, schedule a post-frame // callback that uses the global messenger (if it becomes available). if (retry) { WidgetsBinding.instance.addPostFrameCallback((_) { final gm = scaffoldMessengerKey.currentState; if (gm != null) { try { gm ..hideCurrentSnackBar() ..showSnackBar(snackBar); if (kDebugMode) { debugPrint( 'showAwesomeSnackBar: shown via global messenger (post-frame)', ); } } catch (e) { if (kDebugMode) { debugPrint('showAwesomeSnackBar: post-frame show failed: $e'); } } } else if (kDebugMode) { debugPrint( 'showAwesomeSnackBar: global messenger still null after frame', ); } }); } return; } try { messenger ..hideCurrentSnackBar() ..showSnackBar(snackBar); if (kDebugMode) { debugPrint( 'showAwesomeSnackBar: shown via ${identical(messenger, globalMessenger) ? 'global' : 'local'} messenger', ); } } catch (e) { if (kDebugMode) debugPrint('showAwesomeSnackBar: show failed: $e'); } } void showSuccessSnackBar(BuildContext context, String message) { showAwesomeSnackBar( context, title: 'Success', message: message, snackType: SnackType.success, ); } void showErrorSnackBar(BuildContext context, String message) { showAwesomeSnackBar( context, title: 'Error', message: message, snackType: SnackType.error, ); } void showInfoSnackBar(BuildContext context, String message) { showAwesomeSnackBar( context, title: 'Info', message: message, snackType: SnackType.info, ); } void showWarningSnackBar(BuildContext context, String message) { showAwesomeSnackBar( context, title: 'Warning', message: message, snackType: SnackType.warning, ); } /// Global helpers that use the app-level `scaffoldMessengerKey` directly. /// Use these from places where a valid `BuildContext` with a Scaffold may /// not be available (e.g. dialog builders or background callbacks). void showAwesomeSnackBarGlobal({ required String title, required String message, required SnackType snackType, }) { final gm = scaffoldMessengerKey.currentState; if (gm == null) { if (kDebugMode) { debugPrint('showAwesomeSnackBarGlobal: global messenger null'); } return; } final snackBar = SnackBar( elevation: 0, behavior: SnackBarBehavior.floating, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: EdgeInsets.zero, backgroundColor: Colors.transparent, content: Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: AwesomeSnackbarContent( title: title, message: message, contentType: _mapSnackType(snackType), ), ), ); try { gm ..hideCurrentSnackBar() ..showSnackBar(snackBar); if (kDebugMode) { debugPrint('showAwesomeSnackBarGlobal: shown'); } } catch (e) { if (kDebugMode) { debugPrint('showAwesomeSnackBarGlobal: show failed: $e'); } } } void showSuccessSnackBarGlobal(String message) => showAwesomeSnackBarGlobal( title: 'Success', message: message, snackType: SnackType.success, ); void showErrorSnackBarGlobal(String message) => showAwesomeSnackBarGlobal( title: 'Error', message: message, snackType: SnackType.error, ); void showInfoSnackBarGlobal(String message) => showAwesomeSnackBarGlobal( title: 'Info', message: message, snackType: SnackType.info, ); void showWarningSnackBarGlobal(String message) => showAwesomeSnackBarGlobal( title: 'Warning', message: message, snackType: SnackType.warning, );