Created
July 13, 2023 14:06
-
-
Save Meghatronics/b74a023faecbad54f0ab220cc9253312 to your computer and use it in GitHub Desktop.
Toasts for app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| import '../../router/app_navigator.dart'; | |
| import '../../utilities/constants.dart/constants.dart'; | |
| import '../../utilities/theming/app_styles.dart'; | |
| class AppToast { | |
| final String message; | |
| final bool userCanDismiss; | |
| final Duration duration; | |
| final Alignment alignment; | |
| final AppToastType type; | |
| @protected | |
| late AnimationController animationController; | |
| OverlayEntry? _overlayEntry; | |
| AppToast.error( | |
| this.message, { | |
| Key? key, | |
| this.userCanDismiss = false, | |
| this.alignment = Alignment.topCenter, | |
| this.duration = Constants.toastDefaultDuration, | |
| BuildContext? context, | |
| }) : type = AppToastType.error; | |
| AppToast.success( | |
| this.message, { | |
| Key? key, | |
| this.userCanDismiss = true, | |
| this.alignment = Alignment.topCenter, | |
| this.duration = Constants.toastDefaultDuration, | |
| BuildContext? context, | |
| }) : type = AppToastType.success; | |
| AppToast.info( | |
| this.message, { | |
| Key? key, | |
| this.userCanDismiss = true, | |
| this.alignment = Alignment.topCenter, | |
| this.duration = Constants.toastDefaultDuration, | |
| BuildContext? context, | |
| }) : type = AppToastType.information; | |
| /// Shows the toast message on the screen. | |
| /// | |
| /// If the toast is already shown, nothing happens. | |
| /// Otherwise, it creates the toast widget using the given parameters and displays it in the | |
| /// nearest `Navigator`'s `Overlay`. | |
| /// It then removes the widget after the specified [duration] has passed. | |
| void show([BuildContext? context, Key? key]) { | |
| if (_overlayEntry?.mounted ?? false) return; | |
| final toastWidget = AppToastWidget(this, key: key); | |
| _overlayEntry = OverlayEntry(builder: (_) => toastWidget); | |
| Navigator.of(context ?? AppNavigator.currentContext) | |
| .overlay! | |
| .insert(_overlayEntry!); | |
| Future.delayed(duration).then((_) => remove()); | |
| } | |
| /// Removes the toast message from the screen. | |
| /// | |
| /// If the toast is not showing, nothing happens | |
| /// Otherwise, it uses the animation controller to reverse the animation | |
| /// and then removes the overlay entry. | |
| void remove() { | |
| if (_overlayEntry?.mounted ?? false) { | |
| animationController.reverse().then((_) { | |
| _overlayEntry!.remove(); | |
| }); | |
| } | |
| } | |
| void dispose() { | |
| animationController.dispose(); | |
| } | |
| } | |
| class AppToastWidget extends StatefulWidget { | |
| final AppToast toast; | |
| /// A widget that displays a toast notification. | |
| /// | |
| /// Args: | |
| /// toast (AppToast): The toast to display. | |
| const AppToastWidget( | |
| this.toast, { | |
| super.key, | |
| }); | |
| @override | |
| AppToastWidgetState createState() => AppToastWidgetState(); | |
| } | |
| class AppToastWidgetState extends State<AppToastWidget> | |
| with SingleTickerProviderStateMixin { | |
| late AppToast _toast; | |
| @override | |
| void initState() { | |
| super.initState(); | |
| _toast = widget.toast; | |
| _toast.animationController = AnimationController( | |
| vsync: this, | |
| duration: Constants.toastAnimationDuration, | |
| ); | |
| _toast.animationController.forward(); | |
| } | |
| @override | |
| void dispose() { | |
| _toast.dispose(); | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| final screenSize = MediaQuery.of(context).size; | |
| final rectOfPosition = _toast.alignment.inscribe( | |
| Size(screenSize.width - 32, 56), | |
| Rect.fromLTRB( | |
| 24, | |
| kToolbarHeight + 24, | |
| screenSize.width - 24, | |
| screenSize.height - (kToolbarHeight + 24), | |
| ), | |
| ); | |
| return Positioned.fromRect( | |
| rect: rectOfPosition, | |
| child: FadeTransition( | |
| opacity: | |
| _toast.animationController.drive(CurveTween(curve: Curves.easeOut)), | |
| child: ScaleTransition( | |
| scale: _toast.animationController | |
| .drive(CurveTween(curve: Curves.fastLinearToSlowEaseIn)), | |
| child: Material( | |
| type: MaterialType.transparency, | |
| child: GestureDetector( | |
| onTap: _toast.userCanDismiss ? _toast.remove : null, | |
| child: Container( | |
| padding: const EdgeInsets.symmetric( | |
| vertical: 8, | |
| horizontal: 16, | |
| ), | |
| decoration: BoxDecoration( | |
| borderRadius: BorderRadius.circular(8), | |
| color: _toast.type.bgColor, | |
| ), | |
| alignment: Alignment.centerLeft, | |
| child: Text( | |
| _toast.message, | |
| style: TextStyle( | |
| color: _toast.type.textColor, | |
| fontFamily: AppStyles.satoshiFontFamily, | |
| fontSize: 16, | |
| fontWeight: FontWeight.w500, | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| enum AppToastType { | |
| success(Color(0xFF0A7214), Colors.white), | |
| error(Color(0xFF990A0A), Colors.white), | |
| information(Color(0xFF606060), Colors.white); | |
| const AppToastType(this.bgColor, this.textColor); | |
| final Color bgColor; | |
| final Color textColor; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment