TF-475 Create custom toast

This commit is contained in:
dab246
2022-05-30 16:23:33 +07:00
committed by Dat H. Pham
parent 38bc7d9118
commit c5aa9f7d69
9 changed files with 312 additions and 28 deletions
+2
View File
@@ -63,6 +63,8 @@ export 'presentation/views/search/search_bar_view.dart';
export 'presentation/views/popup_menu/popup_menu_item_widget.dart';
export 'presentation/views/tab_bar/custom_tab_indicator.dart';
export 'presentation/views/quick_search/quick_search_input_form.dart';
export 'presentation/views/toast/toast_position.dart';
export 'presentation/views/toast/tmail_toast.dart';
// Resources
export 'presentation/resources/assets_paths.dart';
+43 -20
View File
@@ -1,9 +1,7 @@
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:getwidget/getwidget.dart';
import 'package:get/get.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
@@ -40,24 +38,49 @@ class AppToast {
gravity: ToastGravity.BOTTOM);
}
void showToastWithAction(BuildContext context, String message, String actionName, Function onActionClick) {
GFToast.showToast(
message,
context,
toastPosition: GFToastPosition.BOTTOM,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
backgroundColor: AppColor.toastWithActionBackgroundColor,
trailing: PointerInterceptor(child: GFButton(
onPressed: () {
ToastView.dismiss();
onActionClick();
},
text: actionName,
type: GFButtonType.transparent,
color: AppColor.buttonActionToastWithActionColor,
)),
toastBorderRadius: 5.0,
toastDuration: 3
void showToastWithAction(
BuildContext context,
String message,
String actionName,
Function onActionClick, {double? maxWidth}) {
showToastMessage(
context,
message,
maxWidth: maxWidth,
trailing: TextButton(
onPressed: () {
ToastView.dismiss();
onActionClick.call();
},
child: Text(
actionName,
style: const TextStyle(fontSize: 16, color: AppColor.buttonActionToastWithActionColor),
),
));
}
void showToastMessage(BuildContext context, String message, {
Widget? leading, Widget? trailing, double? maxWidth
}) {
TMailToast.showToast(
message,
context,
width: maxWidth,
toastPosition: ToastPosition.BOTTOM,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
backgroundColor: AppColor.toastWithActionBackgroundColor,
trailing: trailing != null
? Padding(
padding: const EdgeInsets.only(left: 8),
child: PointerInterceptor(child: trailing))
: null,
leading: leading != null
? Padding(
padding: const EdgeInsets.only(right: 8),
child: PointerInterceptor(child: leading))
: null,
toastBorderRadius: 5.0,
toastDuration: 3
);
}
@@ -57,4 +57,13 @@ class ResponsiveUtils {
bool isHeightShortest(BuildContext context) {
return MediaQuery.of(context).size.shortestSide < heightShortest;
}
double getMaxWidthToast(BuildContext context) {
final widthScreen = getSizeScreenWidth(context);
if (isPortraitMobile(context)) {
return widthScreen;
} else {
return widthScreen < 444 ? widthScreen : 444;
}
}
}
@@ -0,0 +1,219 @@
import 'dart:async';
import 'package:core/presentation/views/toast/toast_position.dart';
import 'package:flutter/material.dart';
class TMailToast {
/// text of type [String] display on toast
String? text;
/// defines the duration of time toast display over screen
int? toastDuration;
/// defines the position of toast over the screen
ToastPosition? toastPosition;
/// defines the background color of the toast
Color? backgroundColor;
/// defines the test style of the toast text
TextStyle? textStyle;
/// defines the border radius of the toast
double? toastBorderRadius;
/// defines the border of the toast
Border? border;
/// defines the trailing widget of the toast
Widget? trailing;
/// defines the leading widget of the toast
Widget? leading;
/// defines the size width widget of the toast
double? width;
// ignore: type_annotate_public_apis, always_declare_return_types
static showToast(
text,
BuildContext context, {
toastDuration,
toastPosition,
backgroundColor = const Color(0xAA000000),
textStyle = const TextStyle(fontSize: 15, color: Colors.white),
toastBorderRadius = 20.0,
border,
trailing,
leading,
width,
}) {
assert(text != null);
ToastView.dismiss();
ToastView.createView(text, context, toastDuration, toastPosition,
backgroundColor, textStyle, toastBorderRadius, border, trailing,
leading, width);
}
}
class ToastView {
static final ToastView _instance = ToastView._internal();
// ignore: sort_constructors_first
factory ToastView() => _instance;
// ignore: sort_constructors_first
ToastView._internal();
static OverlayState? overlayState;
static OverlayEntry? _overlayEntry;
static bool _isVisible = false;
// ignore: avoid_void_async
static void createView(
String text,
BuildContext context,
int? toastDuration,
ToastPosition? toastPosition,
Color backgroundColor,
TextStyle textStyle,
double toastBorderRadius,
Border? border,
Widget? trailing,
Widget? leading,
double? width) async {
overlayState = Overlay.of(context, rootOverlay: false);
final Widget toastChild = ToastCard(
Container(
width: width,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(toastBorderRadius),
border: border,
),
margin: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: trailing == null && leading == null
? Text(text, softWrap: true, style: textStyle)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (leading != null) leading,
Expanded(child: Text(text, style: textStyle)),
if (trailing != null) trailing
],
),
),
Duration(seconds: toastDuration ?? 2), fadeDuration: 500);
_overlayEntry = OverlayEntry(
builder: (BuildContext context) =>
_showWidgetBasedOnPosition(toastChild, toastPosition));
_isVisible = true;
overlayState!.insert(_overlayEntry!);
await Future.delayed(Duration(seconds: toastDuration ?? 2));
await dismiss();
}
static Positioned _showWidgetBasedOnPosition(
Widget child, ToastPosition? toastPosition) {
switch (toastPosition) {
case ToastPosition.BOTTOM:
return Positioned(bottom: 60, left: 18, right: 18, child: child);
case ToastPosition.BOTTOM_LEFT:
return Positioned(bottom: 60, left: 18, child: child);
case ToastPosition.BOTTOM_RIGHT:
return Positioned(bottom: 60, right: 18, child: child);
case ToastPosition.CENTER:
return Positioned(
top: 60, bottom: 60, left: 18, right: 18, child: child);
case ToastPosition.CENTER_LEFT:
return Positioned(top: 60, bottom: 60, left: 18, child: child);
case ToastPosition.CENTER_RIGHT:
return Positioned(top: 60, bottom: 60, right: 18, child: child);
case ToastPosition.TOP_LEFT:
return Positioned(top: 110, left: 18, child: child);
case ToastPosition.TOP_RIGHT:
return Positioned(top: 110, right: 18, child: child);
default:
return Positioned(top: 110, left: 18, right: 18, child: child);
}
}
static Future<void> dismiss() async {
if (!_isVisible) {
return;
}
_isVisible = false;
_overlayEntry?.remove();
}
}
class ToastCard extends StatefulWidget {
const ToastCard(this.child, this.duration,
{Key? key, this.fadeDuration = 500})
: super(key: key);
final Widget child;
final Duration duration;
final int fadeDuration;
@override
ToastStateFulState createState() => ToastStateFulState();
}
class ToastStateFulState extends State<ToastCard>
with SingleTickerProviderStateMixin {
void showAnimation() {
_animationController!.forward();
}
void hideAnimation() {
_animationController!.reverse();
_timer?.cancel();
}
AnimationController? _animationController;
late Animation _fadeAnimation;
Timer? _timer;
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: widget.fadeDuration),
);
_fadeAnimation =
CurvedAnimation(parent: _animationController!, curve: Curves.easeIn);
super.initState();
showAnimation();
_timer = Timer(widget.duration, hideAnimation);
}
@override
void deactivate() {
_timer?.cancel();
_animationController!.stop();
super.deactivate();
}
@override
void dispose() {
_timer?.cancel();
_animationController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => FadeTransition(
opacity: _fadeAnimation as Animation<double>,
child: Center(
child: Material(
color: Colors.transparent,
child: widget.child,
),
),
);
}
@@ -0,0 +1,29 @@
enum ToastPosition {
/// [ToastPosition.TOP] is used to show toast top of the screen
TOP,
/// [ToastPosition.BOTTOM] is used to show toast bottom of the screen
BOTTOM,
/// [ToastPosition.CENTER] is used to show toast center of the screen
CENTER,
/// [ToastPosition.TOP_LEFT] is used to show toast top left of the screen
TOP_LEFT,
/// [ToastPosition.TOP_RIGHT] is used to show toast top right of the screen
TOP_RIGHT,
/// [ToastPosition.BOTTOM_LEFT] is used to show toast bottom left of the screen
BOTTOM_LEFT,
/// [ToastPosition.BOTTOM_RIGHT] is used to show toast bottom right of the screen
BOTTOM_RIGHT,
/// [ToastPosition.CENTER_LEFT] is used to show toast center left of the screen
CENTER_LEFT,
/// [ToastPosition.CENTER_RIGHT] is used to show toast center right of the screen
CENTER_RIGHT,
}
-3
View File
@@ -58,9 +58,6 @@ dependencies:
# device_info_plus
device_info_plus: 3.2.2
# getwidget
getwidget: 2.0.4
# webview_flutter
webview_flutter: 3.0.0
@@ -392,7 +392,8 @@ class EmailController extends BaseController {
success.currentMailboxId,
MoveAction.undo,
success.emailActionType));
}
},
maxWidth: responsiveUtils.getMaxWidthToast(currentContext!)
);
}
}
@@ -328,7 +328,8 @@ class MailboxDashBoardController extends ReloadableController {
currentOverlayContext!,
AppLocalizations.of(currentContext!).drafts_saved,
AppLocalizations.of(currentContext!).discard,
() => _discardEmail(success.emailAsDrafts)
() => _discardEmail(success.emailAsDrafts),
maxWidth: _responsiveUtils.getMaxWidthToast(currentContext!)
);
}
}
@@ -349,7 +350,8 @@ class MailboxDashBoardController extends ReloadableController {
success.currentMailboxId,
MoveAction.undo,
success.emailActionType));
}
},
maxWidth: _responsiveUtils.getMaxWidthToast(currentContext!)
);
}
}
@@ -669,7 +669,8 @@ class ThreadController extends BaseController {
emailActionType!,
destinationPath: destinationPath));
}
}
},
maxWidth: _responsiveUtils.getMaxWidthToast(currentContext!)
);
}
@@ -1043,7 +1044,8 @@ class ThreadController extends BaseController {
success.currentMailboxId,
MoveAction.undo,
success.emailActionType));
}
},
maxWidth: _responsiveUtils.getMaxWidthToast(currentContext!)
);
}
}