TF-475 Create custom toast
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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,22 +38,47 @@ class AppToast {
|
||||
gravity: ToastGravity.BOTTOM);
|
||||
}
|
||||
|
||||
void showToastWithAction(BuildContext context, String message, String actionName, Function onActionClick) {
|
||||
GFToast.showToast(
|
||||
message,
|
||||
void showToastWithAction(
|
||||
BuildContext context,
|
||||
String message,
|
||||
String actionName,
|
||||
Function onActionClick, {double? maxWidth}) {
|
||||
showToastMessage(
|
||||
context,
|
||||
toastPosition: GFToastPosition.BOTTOM,
|
||||
textStyle: TextStyle(fontSize: 16, color: Colors.white),
|
||||
backgroundColor: AppColor.toastWithActionBackgroundColor,
|
||||
trailing: PointerInterceptor(child: GFButton(
|
||||
message,
|
||||
maxWidth: maxWidth,
|
||||
trailing: TextButton(
|
||||
onPressed: () {
|
||||
ToastView.dismiss();
|
||||
onActionClick();
|
||||
onActionClick.call();
|
||||
},
|
||||
text: actionName,
|
||||
type: GFButtonType.transparent,
|
||||
color: AppColor.buttonActionToastWithActionColor,
|
||||
)),
|
||||
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,
|
||||
}
|
||||
@@ -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!)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user