You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

198 lines
5.0 KiB

import 'dart:async';
import 'package:flutter/material.dart';
enum Toast {
short,
long,
}
enum ToastGravity {
top,
bottom,
center,
topLeft,
topRight,
bottomLeft,
bottomRight,
centerLEft,
centerRight,
snackBar,
}
typedef PositionedToastBuilder = Widget Function(BuildContext context, Widget child);
class FToast {
late BuildContext context;
static final FToast _instance = FToast._internal();
factory FToast() {
return _instance;
}
FToast init(BuildContext context) {
_instance.context = context;
return _instance;
}
FToast._internal();
OverlayEntry? _entry;
final List<_ToastEntry> _overlayQueue = [];
Timer? _timer;
void _showOverlay() {
if (_overlayQueue.isEmpty) {
_entry = null;
return;
}
_ToastEntry toastEntry = _overlayQueue.removeAt(0);
_entry = toastEntry.entry;
Overlay.of(context).insert(_entry!);
_timer = Timer(toastEntry.duration, () {
Future.delayed(const Duration(milliseconds: 360), () {
removeCustomToast();
});
});
}
void removeCustomToast() {
_timer!.cancel();
_timer = null;
if (_entry != null) _entry!.remove();
_entry = null;
_showOverlay();
}
void removeQueuedCustomToasts() {
_timer?.cancel();
_timer = null;
_overlayQueue.clear();
if (_entry != null) _entry!.remove();
_entry = null;
}
void showToast({
required Widget child,
PositionedToastBuilder? positionedToastBuilder,
required Duration? toastDuration,
required ToastGravity gravity,
int fadeDuration = 350,
}) {
Widget newChild = _ToastStateFul(child, toastDuration ?? const Duration(seconds: 2), fadeDuration: fadeDuration);
if (gravity == ToastGravity.bottom) {
if (MediaQuery.of(context).viewInsets.bottom != 0) {
gravity = ToastGravity.center;
}
}
OverlayEntry newEntry = OverlayEntry(builder: (context) {
if (positionedToastBuilder != null) return positionedToastBuilder(context, newChild);
return _getPositionWidgetBasedOnGravity(newChild, gravity);
});
_overlayQueue.add(_ToastEntry(entry: newEntry, duration: toastDuration ?? const Duration(seconds: 2)));
if (_timer == null) _showOverlay();
}
Positioned _getPositionWidgetBasedOnGravity(Widget child, ToastGravity gravity) {
switch (gravity) {
case ToastGravity.top:
return Positioned(top: 100.0, left: 24.0, right: 24.0, child: child);
case ToastGravity.topLeft:
return Positioned(top: 100.0, left: 24.0, child: child);
case ToastGravity.topRight:
return Positioned(top: 100.0, right: 24.0, child: child);
case ToastGravity.center:
return Positioned(top: 50.0, bottom: 50.0, left: 24.0, right: 24.0, child: child);
case ToastGravity.centerLEft:
return Positioned(top: 50.0, bottom: 50.0, left: 24.0, child: child);
case ToastGravity.centerRight:
return Positioned(top: 50.0, bottom: 50.0, right: 24.0, child: child);
case ToastGravity.bottomLeft:
return Positioned(bottom: 50.0, left: 24.0, child: child);
case ToastGravity.bottomRight:
return Positioned(bottom: 50.0, right: 24.0, child: child);
case ToastGravity.snackBar:
return Positioned(bottom: MediaQuery.of(context).viewInsets.bottom, left: 0, right: 0, child: child);
case ToastGravity.bottom:
default:
return Positioned(bottom: 50.0, left: 24.0, right: 24.0, child: child);
}
}
}
class _ToastEntry {
final OverlayEntry entry;
final Duration duration;
_ToastEntry({required this.entry, required this.duration});
}
class _ToastStateFul extends StatefulWidget {
const _ToastStateFul(this.child, this.duration, {Key? key, this.fadeDuration = 350}) : super(key: key);
final Widget child;
final Duration duration;
final int fadeDuration;
@override
ToastStateFulState createState() => ToastStateFulState();
}
class ToastStateFulState extends State<_ToastStateFul> with SingleTickerProviderStateMixin {
void showIt() {
_animationController.forward();
}
void hideIt() {
_animationController.reverse();
_timer.cancel();
}
late AnimationController _animationController;
late Animation _fadeAnimation;
late Timer _timer;
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: widget.fadeDuration),
);
_fadeAnimation = CurvedAnimation(parent: _animationController, curve: Curves.easeIn);
super.initState();
showIt();
_timer = Timer(widget.duration, () {
hideIt();
});
}
@override
void deactivate() {
_timer.cancel();
_animationController.stop();
super.deactivate();
}
@override
void dispose() {
_timer.cancel();
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _fadeAnimation as Animation<double>,
child: Center(
child: Material(
color: Colors.transparent,
child: widget.child,
),
),
);
}
}