TF-1594 Use only one class TmailToast to display the message.

(cherry picked from commit 379c34b32b2e5c4dad141e6a98bdb92597fa6908)
This commit is contained in:
dab246
2023-03-16 18:23:47 +07:00
committed by Dat Vu
parent fe05df3477
commit 4e17813e1a
34 changed files with 752 additions and 930 deletions
@@ -57,9 +57,8 @@ extension AppColor on Color {
static const enableSendEmailButtonColor = Color(0xFF007AFF);
static const disableSendEmailButtonColor = Color(0xFFA9B4C2);
static const borderLeftEmailContentColor = Color(0xFFEFEFEF);
static const toastBackgroundColor = Color(0xFFACAFFF);
static const toastSuccessBackgroundColor = Color(0xFF4BB34B);
static const toastErrorBackgroundColor = Color(0xFFFF5858);
static const toastErrorBackgroundColor = Color(0xFFE64646);
static const toastWithActionBackgroundColor = Color(0xFF3F3F3F);
static const buttonActionToastWithActionColor = Color(0xFF7ADCF8);
static const backgroundCountAttachment = Color(0x681C1C1C);
@@ -49,6 +49,7 @@ class ImagePaths {
String get icFilterMessageAttachments => _getImagePath('ic_filter_message_attachments.svg');
String get icLogoTMail => _getImagePath('logo_tmail.png');
String get icSendToast => _getImagePath('ic_send_toast.svg');
String get icSendSuccessToast => _getImagePath('ic_send_success_toast.svg');
String get icClearTextSearch => _getImagePath('ic_clear_text_search.svg');
String get icRenameMailbox => _getImagePath('ic_rename_mailbox.svg');
String get icDeleteToast => _getImagePath('ic_delete_toast.svg');
@@ -175,6 +176,7 @@ class ImagePaths {
String get icHideMailbox => _getImagePath('ic_hide_mailbox.svg');
String get icShowMailbox => _getImagePath('ic_show_mailbox.svg');
String get icMailboxVisibility => _getImagePath('ic_mailbox_visibility.svg');
String get icToastSuccessMessage => _getImagePath('ic_toast_success_message.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
+122 -164
View File
@@ -1,79 +1,97 @@
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/toast/tmail_toast.dart';
import 'package:core/presentation/views/toast/toast_position.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
class AppToast {
final fToast = Get.find<FToast>();
void showToast(String message) {
Fluttertoast.showToast(
msg: message,
fontSize: 16,
textColor: Colors.white,
backgroundColor: AppColor.toastBackgroundColor,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM);
}
void showSuccessToast(String message, {bool isToastLengthLong = false}) {
Fluttertoast.showToast(
msg: message,
fontSize: 16,
textColor: Colors.white,
backgroundColor: AppColor.toastSuccessBackgroundColor,
toastLength: isToastLengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM);
}
void showErrorToast(String message, {bool isToastLengthLong = false}) {
Fluttertoast.showToast(
msg: message,
fontSize: 16,
textColor: Colors.white,
backgroundColor: AppColor.toastErrorBackgroundColor,
toastLength: isToastLengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM);
}
void showBottomToast(
BuildContext context,
String message,
{
String? actionName,
Function? onActionClick,
Widget? actionIcon,
Widget? leadingIcon,
double? maxWidth,
bool infinityToast = false,
Color? backgroundColor,
Color? textColor,
Color? textActionColor,
}
void showToastErrorMessage(
BuildContext context,
String message,
{
Color? leadingSVGIconColor,
String? leadingSVGIcon
}
) {
Widget? trailingAction;
final imagePaths = Get.find<ImagePaths>();
showToastMessage(
context,
message,
backgroundColor: AppColor.toastErrorBackgroundColor,
textColor: Colors.white,
leadingSVGIconColor: leadingSVGIconColor ?? (leadingSVGIcon == null ? Colors.white : null),
leadingSVGIcon: leadingSVGIcon ?? imagePaths.icNotConnection
);
}
void showToastSuccessMessage(
BuildContext context,
String message,
{
Color? leadingSVGIconColor,
String? leadingSVGIcon,
}
) {
final imagePaths = Get.find<ImagePaths>();
showToastMessage(
context,
message,
backgroundColor: AppColor.toastSuccessBackgroundColor,
textColor: Colors.white,
leadingSVGIconColor: leadingSVGIconColor ?? (leadingSVGIcon == null ? Colors.white : null),
leadingSVGIcon: leadingSVGIcon ?? imagePaths.icToastSuccessMessage
);
}
void showToastMessage(
BuildContext context,
String message,
{
String? actionName,
Function? onActionClick,
Widget? actionIcon,
Widget? leadingIcon,
String? leadingSVGIcon,
Color? leadingSVGIconColor,
double? maxWidth,
bool infinityToast = false,
Color? backgroundColor,
Color? textColor,
Color? textActionColor,
TextStyle? textStyle,
EdgeInsets? padding,
}
) {
final responsiveUtils = Get.find<ResponsiveUtils>();
Widget? trailingWidget;
if (actionName != null) {
if (actionIcon == null) {
trailingAction = TextButton(
onPressed: () {
ToastView.dismiss();
onActionClick?.call();
},
child: Text(
actionName,
style: TextStyle(
trailingWidget = PointerInterceptor(
child: TextButton(
onPressed: () {
ToastView.dismiss();
onActionClick?.call();
},
child: Text(
actionName,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
color: textActionColor ?? AppColor.buttonActionToastWithActionColor),
color: textActionColor ?? Colors.white
),
),
),
);
} else {
trailingAction = Material(
color: Colors.transparent,
child: InkWell(
trailingWidget = PointerInterceptor(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
ToastView.dismiss();
onActionClick?.call();
@@ -82,118 +100,58 @@ class AppToast {
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
actionIcon,
Text(
actionName,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
color: textActionColor ?? Colors.white),
)
]
mainAxisSize: MainAxisSize.min,
children: [
actionIcon,
Text(
actionName,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
color: textActionColor ?? Colors.white
),
)
]
),
)),
)
),
),
);
}
}
showToastMessage(
context,
message,
maxWidth: maxWidth,
backgroundColor: backgroundColor,
infinityToast: infinityToast,
textColor: textColor,
leading: leadingIcon,
trailing: trailingAction);
}
Widget? leadingWidget;
if (leadingIcon != null) {
leadingWidget = PointerInterceptor(child: leadingIcon);
} else {
if (leadingSVGIcon != null) {
leadingWidget = PointerInterceptor(
child: SvgPicture.asset(
leadingSVGIcon,
width: 24,
height: 24,
fit: BoxFit.fill,
colorFilter: leadingSVGIconColor?.asFilter(),
)
);
}
}
void showToastMessage(
BuildContext context,
String message, {
Color? textColor,
Widget? leading,
bool infinityToast = false,
Widget? trailing,
double? maxWidth,
Color? backgroundColor
}) {
TMailToast.showToast(
message,
context,
width: maxWidth,
toastPosition: ToastPosition.BOTTOM,
textStyle: TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
color: textColor ?? Colors.white),
backgroundColor: 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: 10.0,
toastDuration: infinityToast ? null : 3,
);
}
void showToastWithIcon(
BuildContext context, {
String? message,
String? icon,
Color? bgColor,
Color? iconColor,
Color? textColor,
double? radius,
EdgeInsets? padding,
TextStyle? textStyle,
double? widthToast,
Duration? toastLength
}) async {
double sizeWidth = context.width > 360 ? 360 : context.width - 40;
final toast = Material(
color: bgColor ?? Colors.white,
elevation: 10,
shadowColor: Colors.black54,
borderRadius: BorderRadius.all(Radius.circular(radius ?? 10)),
child: Container(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 12.0, vertical: 14),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(radius ?? 10.0),
color: bgColor ?? Colors.white,
),
width: widthToast ?? sizeWidth,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null)
SvgPicture.asset(icon,
width: 24,
height: 24,
fit: BoxFit.fill,
colorFilter: iconColor.asFilter()),
if (icon != null)
const SizedBox(width: 10.0),
Expanded(child: Text(
message ?? '',
style: textStyle ?? TextStyle(fontSize: 15, color: textColor ?? Colors.black))),
],
),
message,
context,
width: maxWidth ?? responsiveUtils.getMaxWidthToast(context),
toastPosition: ToastPosition.BOTTOM,
textStyle: textStyle ?? TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
color: textColor ?? AppColor.primaryColor
),
);
fToast.init(context);
fToast.showToast(
child: toast,
gravity: ToastGravity.BOTTOM,
toastDuration: toastLength ?? const Duration(seconds: 3),
backgroundColor: backgroundColor ?? Colors.white,
trailing: trailingWidget,
leading: leadingWidget,
padding: padding,
toastDuration: infinityToast ? null : 3,
);
}
}
@@ -77,7 +77,7 @@ class ResponsiveUtils {
if (isPortraitMobile(context)) {
return widthScreen;
} else {
return widthScreen < 444 ? widthScreen : 444;
return widthScreen < 424 ? widthScreen : 424;
}
}
@@ -18,13 +18,13 @@ class ButtonBuilder {
bool? _isVertical;
Key? _key;
Color? _iconColor;
Color? _colorButton;
TextStyle? _textStyle;
BoxDecoration? _decoration;
Widget? _iconAction;
double? _radiusSplash;
double? _maxWidth;
EdgeInsets? _padding;
EdgeInsets? _margin;
String? _tooltip;
BoxConstraints? _constraints;
@@ -48,10 +48,6 @@ class ButtonBuilder {
_iconColor = color;
}
void colorButton(Color color) {
_colorButton = color;
}
void decoration(BoxDecoration decoration) {
_decoration = decoration;
}
@@ -68,6 +64,10 @@ class ButtonBuilder {
_padding = padding;
}
void margin(EdgeInsets? margin) {
_margin = margin;
}
void textStyle(TextStyle style) {
_textStyle = style;
}
@@ -100,38 +100,40 @@ class ButtonBuilder {
}
Widget build() {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _onPressActionClick != null ? _onPressActionClick!.call() : null,
onTapDown: (detail) {
if (_onPressActionWithPositionClick != null && _context != null) {
final screenSize = MediaQuery.of(_context!).size;
final offset = detail.globalPosition;
final position = RelativeRect.fromLTRB(
offset.dx,
offset.dy,
screenSize.width - offset.dx,
screenSize.height - offset.dy,
);
_onPressActionWithPositionClick?.call(position);
}
},
customBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(_radiusSplash ?? 20)),
child: Tooltip(
message: _tooltip ?? '',
child: Container(
key: _key,
alignment: Alignment.center,
color: _decoration == null ? _colorButton : null,
decoration: _decoration,
width: _maxWidth,
constraints: _constraints,
padding: _padding ?? EdgeInsets.zero,
child: _buildBody()
),
)
return Padding(
padding: _margin ?? EdgeInsets.zero,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: _onPressActionClick,
onTapDown: (detail) {
if (_onPressActionWithPositionClick != null && _context != null) {
final screenSize = MediaQuery.of(_context!).size;
final offset = detail.globalPosition;
final position = RelativeRect.fromLTRB(
offset.dx,
offset.dy,
screenSize.width - offset.dx,
screenSize.height - offset.dy,
);
_onPressActionWithPositionClick?.call(position);
}
},
borderRadius: BorderRadius.circular(_radiusSplash ?? 20),
child: Tooltip(
message: _tooltip ?? '',
child: Container(
key: _key,
alignment: Alignment.center,
color: _decoration == null ? Colors.transparent : null,
decoration: _decoration,
width: _maxWidth,
constraints: _constraints,
padding: _padding ?? EdgeInsets.zero,
child: _buildBody()
),
)
),
),
);
}
@@ -163,11 +165,12 @@ class ButtonBuilder {
Widget _buildIcon() => Padding(
padding: _paddingIcon ?? const EdgeInsets.all(10),
child: SvgPicture.asset(
_icon ?? '',
width: _size ?? 24,
height: _size ?? 24,
fit: BoxFit.fill,
colorFilter: _iconColor.asFilter()));
_icon ?? '',
width: _size ?? 24,
height: _size ?? 24,
fit: BoxFit.fill,
colorFilter: _iconColor.asFilter()
));
Widget _buildText() {
return Text(
@@ -176,8 +179,9 @@ class ButtonBuilder {
softWrap: CommonTextStyle.defaultSoftWrap,
overflow: CommonTextStyle.defaultTextOverFlow,
style: _textStyle ?? const TextStyle(
fontSize: 12,
color: AppColor.colorTextButton),
fontSize: 12,
color: AppColor.colorTextButton
),
);
}
}
@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/views/toast/toast_position.dart';
import 'package:flutter/material.dart';
@@ -34,52 +35,68 @@ class TMailToast {
/// defines the size width widget of the toast
double? width;
// ignore: type_annotate_public_apis, always_declare_return_types
/// defines the padding widget of the toast
EdgeInsets? padding;
static showToast(
text,
BuildContext context, {
toastDuration,
toastPosition,
backgroundColor = const Color(0xAA000000),
textStyle = const TextStyle(fontSize: 15, color: Colors.white),
toastBorderRadius = 20.0,
backgroundColor,
textStyle = const TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.normal
),
toastBorderRadius = 10.0,
border,
trailing,
leading,
width,
padding,
}) {
assert(text != null);
ToastView.dismiss();
ToastView.createView(text, context, toastPosition,
backgroundColor, textStyle, toastBorderRadius, border, trailing,
leading, width, toastDuration: toastDuration,);
ToastView.createView(
text,
context,
toastPosition,
backgroundColor,
textStyle,
toastBorderRadius,
border,
trailing,
leading,
width,
padding,
toastDuration: toastDuration,
);
}
}
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,
ToastPosition? toastPosition,
Color backgroundColor,
TextStyle textStyle,
Color? backgroundColor,
TextStyle? textStyle,
double toastBorderRadius,
Border? border,
Widget? trailing,
Widget? leading,
double? width,
{int? toastDuration = 2}
EdgeInsets? padding,
{int? toastDuration}
) async {
overlayState = Overlay.of(context, rootOverlay: false);
@@ -89,49 +106,72 @@ class ToastView {
child: Container(
width: width,
decoration: BoxDecoration(
color: backgroundColor,
color: backgroundColor ?? Colors.white,
borderRadius: BorderRadius.circular(toastBorderRadius),
border: border,
boxShadow: const [
BoxShadow(
color: AppColor.colorShadowLayerBottom,
blurRadius: 24,
offset: Offset.zero),
BoxShadow(
color: AppColor.colorShadowBgContentEmail,
blurRadius: 2,
offset: Offset.zero),
]
),
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
],
),
padding: padding ?? const EdgeInsets.all(12),
child: trailing == null && leading == null
? Text(
text,
softWrap: true,
style: textStyle ?? const TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.normal
)
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (leading != null) leading,
Expanded(child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
text,
style: textStyle ?? const TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.normal
)
)
)),
if (trailing != null) trailing
],
),
),
),
);
_overlayEntry = OverlayEntry(
builder: (BuildContext context) =>
_showWidgetBasedOnPosition(
toastDuration != null ?
ToastCard(
child,
Duration(seconds: toastDuration),
fadeDuration: 500,
)
: child, toastPosition,
));
_overlayEntry = OverlayEntry(builder: (context) =>
_showWidgetBasedOnPosition(
toastDuration != null
? ToastCard(child, Duration(seconds: toastDuration))
: child,
toastPosition,
)
);
_isVisible = true;
overlayState!.insert(_overlayEntry!);
if (toastDuration != null) {
await Future.delayed(Duration(seconds: toastDuration));
await dismiss();
}
}
static Positioned _showWidgetBasedOnPosition(
Widget child, ToastPosition? toastPosition) {
Widget child,
ToastPosition? toastPosition
) {
switch (toastPosition) {
case ToastPosition.BOTTOM:
return Positioned(bottom: 60, left: 18, right: 18, child: child);
@@ -140,8 +180,7 @@ class ToastView {
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);
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:
@@ -165,9 +204,14 @@ class ToastView {
}
class ToastCard extends StatefulWidget {
const ToastCard(this.child, this.duration,
{Key? key, this.fadeDuration = 500})
: super(key: key);
const ToastCard(
this.child,
this.duration,
{
Key? key,
this.fadeDuration = 300
}
) : super(key: key);
final Widget child;
final Duration duration;
@@ -199,8 +243,7 @@ class ToastStateFulState extends State<ToastCard>
vsync: this,
duration: Duration(milliseconds: widget.fadeDuration),
);
_fadeAnimation =
CurvedAnimation(parent: _animationController!, curve: Curves.easeIn);
_fadeAnimation = CurvedAnimation(parent: _animationController!, curve: Curves.easeIn);
super.initState();
showAnimation();
@@ -226,4 +269,4 @@ class ToastStateFulState extends State<ToastCard>
opacity: _fadeAnimation as Animation<double>,
child: widget.child,
);
}
}