.
\ No newline at end of file
diff --git a/app/3rd_party/cherry_toast/README.md b/app/3rd_party/cherry_toast/README.md
new file mode 100755
index 0000000..02d2aef
--- /dev/null
+++ b/app/3rd_party/cherry_toast/README.md
@@ -0,0 +1,202 @@
+
+
+
+
+
+# Cherry Toast
+
+
+
+
+A new way to display toasts in Flutter in an elegant design and animations
+
+
+
+|  |  |  |
+|--|--|--|
+|  |  |  |
+
+
+
+
+
+## Cherry Toast v1.0.2
+
+
+- Support all platforms
+- Top and Bottom display position
+- Multiple built-in themes
+- Built-in animations
+- Support null safety
+- Elegant design
+- Full customizable
+- Heartbeat animation on icons
+- Customizable icon size and color and display
+
+
+
+
+## Installation
+
+
+To add cherry toast to your project add this line to your `pubspec.yaml` file
+
+```yaml
+dependencies:
+ cherry_toast: ^1.0.2
+```
+
+
+
+
+
+## Parameters
+
+
+| Name | Description | Required | Default Value |
+|--|--|--|--|
+| title | The toast title `String` | true | N/A |
+| description | the toast description text (nullable) | false | null |
+| action | the toast action text (clickable text) | false | null |
+| titleStyle | the title text style | false | `TextStyle(color: Colors.black, fontWeight: FontWeight.bold)` |
+| descriptionStyle | the description text style | false | `TextStyle(color: Colors.black)` |
+| actionStyle | the action text style | false | `TextStyle(color: Colors.black, fontWeight: FontWeight.bold)` |
+| displayTitle | indicates whether the title will be rendered or not | false | true |
+| icon | the toast displayed icon (IconData) | required when using the default constructor otherwise it's not required | N/A |
+| toastPosition | the position of the toast (Top/Bottom) | false | `POSITION.TOP` |
+| themeColor | the color that will be applied on the icon back circle (for built-in themes it will match the action text color | required when using the default constructor otherwise it's not required | N/A |
+| actionHandler | Function that will be invoked when clicking on the action text | false | null |
+| animationDuration | the duration of the animation display and hide | false | `Duration(milliseconds: 1500)` |
+| animationCurve | the display animation curve | false | `Curves.ease` |
+| animationType | the type of the animation that will be applied on the toast (From left, From right, From top) | false | `ANIMATION_TYPE.FROM_LEFT` |
+| autoDismiss | indicates whether the toast will be dismissed automatically or not | false | false |
+| toastDuration | the duration of the toast when `autoDismiss` is true | false | `Duration(milliseconds: 3000)` |
+| layout | the taost's layout rendering (LTR, RTL) | false | `TOAST_LAYOUT.LTR` |
+| displayCloseButton | indicates whether display or not the close button | false | true |
+| borderRadius| define the toast border radius | false | 20 |
+| iconColor| define the icon color | false | `Colors.black`|
+| displayIcon| hide or show the icon on the toast | false | true |
+| enableIconAnimation | define wether apply an animation on the icon or not | false | true |
+| iconSize | define the icon size | false | 20 |
+
+
+
+## Usage
+
+- Simple cherry toast with only title
+
+```dart
+
+CherryToast.success(
+ title: "The simplest cherry toast"
+).show(context);
+
+```
+
+
+
+
+
+- Simple cherry toast with action button
+
+```dart
+
+CherryToast.info(
+ title: "User added",
+ action: "Display information",
+ actionHandler: (){
+ print("Action button pressed");
+ },
+).show(context);
+
+```
+
+
+
+
+A new way to display toasts in Flutter in an elegant design and animations
+
+
+
+
+- Toast with description without title
+
+```dart
+
+CherryToast.warning(
+ title: "",
+ displayTitle: false,
+ description: "All information may be deleted after this action",
+ animationType: ANIMATION_TYPE.FROM_TOP,
+ action: "Backup data",
+ actionHandler: (){
+ print("Hello World!!");
+ },
+).show(context);
+
+```
+
+
+
+
+
+- Toast with nothing but description with different animation type and auto dismiss
+
+```dart
+CherryToast.error(
+ title: "",
+ displayTitle: false,
+ description: "Invalid account information",
+ animationType: ANIMATION_TYPE.FROM_RIGHT,
+ animationDuration: Duration(milliseconds: 1000),
+ autoDismiss: true)
+.show(context);
+
+```
+
+- Bottom displayed cherry toast
+
+```dart
+CherryToast(
+ icon: Icons.alarm_add,
+ themeColor: Colors.pink,
+ title: "",
+ displayTitle: false,
+ description: "A bottom cherry toast example",
+ toastPosition: POSITION.BOTTOM,
+ animationDuration: Duration(milliseconds: 1000),
+ autoDismiss: true)
+.show(context);
+
+
+
+```
+
+
+- Right layout rendered cherry toast
+
+```dart
+CherryToast(
+ icon: Icon(Icons.car_repair),
+ themeColor: Colors.green,
+ title: "",
+ displayTitle: false,
+ description: "هذا مثال تصميم من اليمين",
+ toastPosition: POSITION.BOTTOM,
+ layout: TOAST_LAYOUT.RTL,
+ animationType: ANIMATION_TYPE.FROM_RIGHT,
+ action: "انقر هنا",
+ actionStyle: TextStyle(color: Colors.green),
+ animationDuration: Duration(milliseconds: 1000),
+ autoDismiss: true)
+.show(context);
+
+```
+
+## Contribution
+
+Of course the project is open source, and you can contribute to it [repository link](https://github.com/koukibadr/Cherry-Toast)
+
+- If you **found a bug**, open an issue.
+- If you **have a feature request**, open an issue.
+- If you **want to contribute**, submit a pull request.
\ No newline at end of file
diff --git a/app/3rd_party/cherry_toast/lib/cherry_toast.dart b/app/3rd_party/cherry_toast/lib/cherry_toast.dart
new file mode 100755
index 0000000..58e1d9f
--- /dev/null
+++ b/app/3rd_party/cherry_toast/lib/cherry_toast.dart
@@ -0,0 +1,515 @@
+import 'dart:async';
+import 'package:cherry_toast/cherry_toast_icon.dart';
+import 'package:cherry_toast/resources/arrays.dart';
+import 'package:cherry_toast/resources/colors.dart';
+import 'package:cherry_toast/resources/constants.dart';
+import 'package:flutter/material.dart';
+
+// ignore: must_be_immutable
+class CherryToast extends StatefulWidget {
+ CherryToast({
+ required this.title,
+ required this.icon,
+ required this.themeColor,
+ this.iconColor = Colors.black,
+ this.action,
+ this.actionHandler,
+ this.description,
+ this.descriptionStyle = DEFAULT_DESCRIPTION_STYLE,
+ this.titleStyle = DEFAULT_TITLTE_STYLE,
+ this.actionStyle = const TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
+ this.displayTitle = true,
+ this.toastPosition = POSITION.TOP,
+ this.animationDuration = DEFAULT_ANIMATION_DURATION,
+ this.animationCurve = DEFAULT_ANIMATION_CURVE,
+ this.animationType = ANIMATION_TYPE.FROM_LEFT,
+ this.autoDismiss = false,
+ this.toastDuration = DEFAULT_TOAST_DURATION,
+ this.layout = TOAST_LAYOUT.LTR,
+ this.displayCloseButton = true,
+ this.borderRadius = DEFAULT_RADIUS,
+ this.displayIcon = true,
+ this.enableIconAnimation = true,
+ this.iconSize = DEFAULT_ICON_SIZE,
+ this.backgroundColor,
+ });
+
+ CherryToast.success({
+ required this.title,
+ this.action,
+ this.actionHandler,
+ this.description,
+ this.descriptionStyle = DEFAULT_DESCRIPTION_STYLE,
+ this.titleStyle = DEFAULT_TITLTE_STYLE,
+ this.actionStyle = const TextStyle(color: SUCCESS_COLOR, fontWeight: FontWeight.bold),
+ this.displayTitle = true,
+ this.toastPosition = POSITION.TOP,
+ this.animationDuration = DEFAULT_ANIMATION_DURATION,
+ this.animationCurve = DEFAULT_ANIMATION_CURVE,
+ this.animationType = ANIMATION_TYPE.FROM_LEFT,
+ this.autoDismiss = false,
+ this.toastDuration = DEFAULT_TOAST_DURATION,
+ this.layout = TOAST_LAYOUT.LTR,
+ this.displayCloseButton = true,
+ this.borderRadius = DEFAULT_RADIUS,
+ this.displayIcon = true,
+ this.enableIconAnimation = true,
+ this.backgroundColor,
+ }) {
+ this.icon = Icons.check_circle;
+ this.themeColor = SUCCESS_COLOR;
+ this.iconColor = SUCCESS_COLOR;
+ this.iconSize = DEFAULT_ICON_SIZE;
+ }
+
+ CherryToast.error({
+ required this.title,
+ this.action,
+ this.actionHandler,
+ this.description,
+ this.descriptionStyle = DEFAULT_DESCRIPTION_STYLE,
+ this.titleStyle = DEFAULT_TITLTE_STYLE,
+ this.actionStyle = const TextStyle(color: ERROR_COLOR, fontWeight: FontWeight.bold),
+ this.displayTitle = true,
+ this.toastPosition = POSITION.TOP,
+ this.animationDuration = DEFAULT_ANIMATION_DURATION,
+ this.animationCurve = DEFAULT_ANIMATION_CURVE,
+ this.animationType = ANIMATION_TYPE.FROM_LEFT,
+ this.autoDismiss = false,
+ this.toastDuration = DEFAULT_TOAST_DURATION,
+ this.layout = TOAST_LAYOUT.LTR,
+ this.displayCloseButton = true,
+ this.borderRadius = DEFAULT_RADIUS,
+ this.displayIcon = true,
+ this.enableIconAnimation = true,
+ this.backgroundColor,
+ }) {
+ this.icon = Icons.error_rounded;
+ this.themeColor = ERROR_COLOR;
+ this.iconColor = ERROR_COLOR;
+ this.iconSize = DEFAULT_ICON_SIZE;
+ }
+
+ CherryToast.warning({
+ required this.title,
+ this.action,
+ this.actionHandler,
+ this.description,
+ this.descriptionStyle = DEFAULT_DESCRIPTION_STYLE,
+ this.titleStyle = DEFAULT_TITLTE_STYLE,
+ this.actionStyle = const TextStyle(color: WARINING_COLOR, fontWeight: FontWeight.bold),
+ this.displayTitle = true,
+ this.toastPosition = POSITION.TOP,
+ this.animationDuration = DEFAULT_ANIMATION_DURATION,
+ this.animationCurve = DEFAULT_ANIMATION_CURVE,
+ this.animationType = ANIMATION_TYPE.FROM_LEFT,
+ this.autoDismiss = false,
+ this.toastDuration = DEFAULT_TOAST_DURATION,
+ this.layout = TOAST_LAYOUT.LTR,
+ this.displayCloseButton = true,
+ this.borderRadius = DEFAULT_RADIUS,
+ this.displayIcon = true,
+ this.enableIconAnimation = true,
+ this.backgroundColor,
+ }) {
+ this.icon = Icons.warning_rounded;
+ this.themeColor = WARINING_COLOR;
+ this.iconColor = WARINING_COLOR;
+ this.iconSize = DEFAULT_ICON_SIZE;
+ }
+
+ CherryToast.info({
+ required this.title,
+ this.action,
+ this.actionHandler,
+ this.description,
+ this.descriptionStyle = DEFAULT_DESCRIPTION_STYLE,
+ this.titleStyle = DEFAULT_TITLTE_STYLE,
+ this.actionStyle = const TextStyle(color: INFO_COLOR, fontWeight: FontWeight.bold),
+ this.displayTitle = true,
+ this.toastPosition = POSITION.TOP,
+ this.animationDuration = DEFAULT_ANIMATION_DURATION,
+ this.animationCurve = DEFAULT_ANIMATION_CURVE,
+ this.animationType = ANIMATION_TYPE.FROM_LEFT,
+ this.autoDismiss = false,
+ this.toastDuration = DEFAULT_TOAST_DURATION,
+ this.layout = TOAST_LAYOUT.LTR,
+ this.displayCloseButton = true,
+ this.borderRadius = DEFAULT_RADIUS,
+ this.displayIcon = true,
+ this.enableIconAnimation = true,
+ this.backgroundColor,
+ }) {
+ this.icon = Icons.info_rounded;
+ this.themeColor = INFO_COLOR;
+ this.iconColor = INFO_COLOR;
+ this.iconSize = DEFAULT_ICON_SIZE;
+ }
+
+ ///the toast title string
+ ///
+ final String title;
+
+ ///The toast description text
+ ///
+ final String? description;
+
+ ///The toast action button text
+ ///
+ final String? action;
+
+ ///the text style that will be applied on the title
+ ///by default it's `TextStyle(color: Colors.black, fontWeight: FontWeight.bold)`
+ ///
+ final TextStyle titleStyle;
+
+ ///the text style that will be applied on the description
+ ///
+ final TextStyle descriptionStyle;
+
+ ///the action button text style
+ ///
+ final TextStyle actionStyle;
+
+ ///indicates whether display or not the title
+ ///
+ final bool displayTitle;
+
+ ///the toast icon, it's required when using the default constructor
+ ///
+ late IconData icon;
+
+ ///the Icon color
+ ///this parameter is only available on the default constructor
+ ///for the built-in themes the color will be set automatically
+ late Color iconColor;
+
+ ///the icon size
+ ///by default is 20
+ ///this parameter is available in default constructor
+ late double iconSize;
+
+ ///the toast display postion, possible values
+ ///```dart
+ ///{
+ ///TOP,
+ ///BOTTOM
+ ///}
+ ///```
+ final POSITION toastPosition;
+
+ ///The color that will be applied on the circle behind the icon
+ ///for better rendering the action button must have the same color
+ ///
+ late Color themeColor;
+
+ ///the function invoked when clicking on the action button
+ ///
+ final Function? actionHandler;
+
+ ///The duration of the animation by default it's 1.5 seconds
+ ///
+ final Duration animationDuration;
+
+ ///the animation curve by default it's set to `Curves.ease`
+ ///
+ final Cubic animationCurve;
+
+ ///The animation type applied on the toast
+ ///```dart
+ ///{
+ ///FROM_TOP,
+ ///FROM_LEFT,
+ ///FROM_RIGHT
+ ///}
+ ///```
+ final ANIMATION_TYPE animationType;
+
+ ///indicates whether the toast will be hidden automatically or not
+ ///
+ final bool autoDismiss;
+
+ ///the duration of the toast if [autoDismiss] is true
+ ///by default it's 3 seconds
+ ///
+ final Duration toastDuration;
+
+ ///the layout of the toast
+ ///```dart
+ ///{
+ ///LTR,
+ ///RTL
+ ///}
+ ///```
+ final TOAST_LAYOUT layout;
+
+ ///Display / Hide the close button icon
+ ///by default it's true
+ final bool displayCloseButton;
+
+ ///define the border radius applied on the toast
+ ///by default it's 20
+ ///
+ final double borderRadius;
+
+ ///Define whether the icon will be rendered or not
+ ///
+ final bool displayIcon;
+
+ ///Define wether the animation on the icon will be rendered or not
+ ///
+ final bool enableIconAnimation;
+
+ final Color? backgroundColor;
+
+ ///Display the created cherry toast
+ ///[context] the context of the application
+ ///
+ show(BuildContext context) {
+ Navigator.of(context).push(
+ PageRouteBuilder(
+ pageBuilder: (context, _, __) => AlertDialog(
+ backgroundColor: Colors.transparent,
+ contentPadding: EdgeInsets.all(0),
+ insetPadding: EdgeInsets.all(70),
+ elevation: 0,
+ content: this,
+ ),
+ opaque: false),
+ );
+ }
+
+ @override
+ _CherryToastState createState() => _CherryToastState();
+}
+
+class _CherryToastState extends State with TickerProviderStateMixin {
+ late Animation offsetAnimation;
+ late AnimationController slideController;
+ late BoxDecoration toastDecoration;
+
+ @override
+ void initState() {
+ super.initState();
+ _initAnimation();
+ var _shadowHSLColor = HSLColor.fromColor(widget.backgroundColor ?? Colors.white);
+ toastDecoration = BoxDecoration(
+ color: widget.backgroundColor ?? Colors.white,
+ borderRadius: BorderRadius.circular(this.widget.borderRadius),
+ boxShadow: [
+ BoxShadow(
+ color: _shadowHSLColor
+ .withLightness(_shadowHSLColor.lightness - 0.1 < 0 ? 0 : _shadowHSLColor.lightness - 0.1)
+ .toColor(),
+ spreadRadius: 2,
+ blurRadius: 3,
+ offset: Offset(0, 1), // changes position of shadow
+ ),
+ ],
+ );
+ if (this.widget.autoDismiss) {
+ Timer(this.widget.toastDuration, () {
+ slideController.reverse();
+ Timer(this.widget.animationDuration, () {
+ if (mounted) Navigator.pop(context);
+ });
+ });
+ }
+ }
+
+ ///Initialize animation parameters [slideController] and [offsetAnimation]
+ _initAnimation() {
+ slideController = AnimationController(
+ duration: this.widget.animationDuration,
+ vsync: this,
+ );
+ switch (this.widget.animationType) {
+ case ANIMATION_TYPE.FROM_LEFT:
+ offsetAnimation = Tween(
+ begin: const Offset(-2, 0),
+ end: const Offset(0, 0),
+ ).animate(CurvedAnimation(parent: slideController, curve: this.widget.animationCurve));
+ break;
+ case ANIMATION_TYPE.FROM_RIGHT:
+ offsetAnimation = Tween(
+ begin: const Offset(2, 0),
+ end: const Offset(0, 0),
+ ).animate(CurvedAnimation(parent: slideController, curve: this.widget.animationCurve));
+ break;
+ case ANIMATION_TYPE.FROM_TOP:
+ offsetAnimation = Tween(
+ begin: const Offset(0, -2),
+ end: const Offset(0, 0),
+ ).animate(CurvedAnimation(parent: slideController, curve: this.widget.animationCurve));
+ break;
+ default:
+ }
+ WidgetsBinding.instance!.addPostFrameCallback((_) {
+ slideController.forward();
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (this.widget.layout == TOAST_LAYOUT.LTR) {
+ return _renderLeftLayoutToast(context);
+ } else {
+ return _renderRightLayoutToast(context);
+ }
+ }
+
+ ///render a left layout toast if [this.widget.layout] set to LTR
+ ///
+ Widget _renderLeftLayoutToast(BuildContext context) {
+ return Column(
+ mainAxisAlignment: this.widget.toastPosition == POSITION.TOP ? MainAxisAlignment.start : MainAxisAlignment.end,
+ children: [
+ SlideTransition(
+ position: offsetAnimation,
+ child: Container(
+ decoration: toastDecoration,
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ flex: 2,
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ this.widget.displayIcon
+ ? CherryToatIcon(
+ color: this.widget.themeColor,
+ icon: this.widget.icon,
+ iconSize: this.widget.iconSize,
+ iconColor: this.widget.iconColor,
+ enableAnimation: this.widget.enableIconAnimation,
+ )
+ : Container(),
+ _renderToastContent(),
+ ],
+ ),
+ ),
+ this.widget.displayCloseButton
+ ? Padding(
+ padding: const EdgeInsets.only(top: 10, right: 10),
+ child: _renderCloseButton(context),
+ )
+ : Container(),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+
+ ///render a right layout toast if [this.widget.layout] set to RTL
+ ///
+ Column _renderRightLayoutToast(BuildContext context) {
+ return Column(
+ mainAxisAlignment: this.widget.toastPosition == POSITION.TOP ? MainAxisAlignment.start : MainAxisAlignment.end,
+ children: [
+ SlideTransition(
+ position: offsetAnimation,
+ child: Container(
+ decoration: toastDecoration,
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ this.widget.displayCloseButton
+ ? Padding(
+ padding: const EdgeInsets.only(top: 10, left: 10),
+ child: _renderCloseButton(context),
+ )
+ : Container(),
+ Expanded(
+ flex: 2,
+ child: Row(
+ crossAxisAlignment: this.widget.description == null && this.widget.action == null
+ ? CrossAxisAlignment.center
+ : CrossAxisAlignment.start,
+ children: [
+ _renderToastContent(),
+ CherryToatIcon(
+ color: this.widget.themeColor,
+ icon: this.widget.icon,
+ iconSize: this.widget.iconSize,
+ iconColor: this.widget.iconColor,
+ enableAnimation: this.widget.enableIconAnimation),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+
+ /// render the close button icon with a clickable widget that
+ /// will hide the toast
+ ///
+ InkWell _renderCloseButton(BuildContext context) {
+ return InkWell(
+ onTap: () {
+ slideController.reverse();
+ Timer(this.widget.animationDuration, () {
+ if (mounted) Navigator.pop(context);
+ });
+ },
+ child: Icon(Icons.close, color: Colors.grey[500], size: CLOSE_BUTTON_SIZE),
+ );
+ }
+
+ ///render the toast content (Title, Description and Action)
+ ///
+ Expanded _renderToastContent() {
+ return Expanded(
+ flex: 2,
+ child: Padding(
+ padding: const EdgeInsets.only(left: 10, right: 10),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment:
+ this.widget.layout == TOAST_LAYOUT.LTR ? CrossAxisAlignment.start : CrossAxisAlignment.end,
+ children: [
+ this.widget.displayTitle ? Text(this.widget.title, style: this.widget.titleStyle) : Container(),
+ this.widget.description == null
+ ? Container()
+ : Column(
+ children: [
+ SizedBox(
+ height: 5,
+ ),
+ Text(this.widget.description ?? "", style: this.widget.descriptionStyle)
+ ],
+ ),
+ this.widget.action != null
+ ? Column(
+ children: [
+ SizedBox(
+ height: 5,
+ ),
+ InkWell(
+ onTap: () {
+ this.widget.actionHandler?.call();
+ },
+ child: Text(this.widget.action ?? "", style: this.widget.actionStyle))
+ ],
+ )
+ : Container()
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/app/3rd_party/cherry_toast/lib/cherry_toast_icon.dart b/app/3rd_party/cherry_toast/lib/cherry_toast_icon.dart
new file mode 100755
index 0000000..9762b1f
--- /dev/null
+++ b/app/3rd_party/cherry_toast/lib/cherry_toast_icon.dart
@@ -0,0 +1,90 @@
+import 'package:cherry_toast/resources/constants.dart';
+import 'package:flutter/material.dart';
+
+class CherryToatIcon extends StatefulWidget {
+ ///the color that will be applied on the circle behind the icon
+ ///(required)
+ final Color color;
+
+ ///The toast icon widget (required)
+ ///
+ final IconData icon;
+
+ ///the size of the icon (required)
+ ///
+ final double iconSize;
+
+ ///the icon color (required)
+ final Color iconColor;
+
+ ///define wether the animation will be applied on the icon or not
+ ///
+ final bool enableAnimation;
+
+ CherryToatIcon(
+ {required this.color,
+ required this.icon,
+ required this.iconSize,
+ required this.iconColor,
+ required this.enableAnimation});
+
+ @override
+ _CherryToatIconState createState() => _CherryToatIconState();
+}
+
+class _CherryToatIconState extends State
+ with TickerProviderStateMixin {
+ late Animation _heartAnimation;
+ late AnimationController _heartAnimationController;
+
+ @override
+ void initState() {
+ super.initState();
+ if (this.widget.enableAnimation) {
+ _heartAnimationController = AnimationController(
+ vsync: this, duration: Duration(milliseconds: 1200));
+ _heartAnimation = Tween(
+ begin: this.widget.iconSize * 0.7,
+ end: this.widget.iconSize * 0.95)
+ .animate(CurvedAnimation(
+ curve: Curves.bounceOut, parent: _heartAnimationController));
+
+ _heartAnimationController.addStatusListener((AnimationStatus status) {
+ if (status == AnimationStatus.completed) {
+ _heartAnimationController.repeat();
+ }
+ });
+ _heartAnimationController.forward();
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: DEFAULT_ICON_LAYOUT_SIZE,
+ height: DEFAULT_ICON_LAYOUT_SIZE,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle, color: this.widget.color.withAlpha(20)),
+ child: Center(
+ child: this.widget.enableAnimation
+ ? AnimatedBuilder(
+ builder: (context, child) {
+ return Icon(this.widget.icon,
+ size: this._heartAnimation.value,
+ color: this.widget.iconColor);
+ },
+ animation: this._heartAnimationController,
+ )
+ : Icon(this.widget.icon,
+ size: this.widget.iconSize, color: this.widget.iconColor)),
+ );
+ }
+
+ @override
+ void dispose() {
+ if (this.widget.enableAnimation) {
+ _heartAnimationController.dispose();
+ }
+ super.dispose();
+ }
+}
diff --git a/app/3rd_party/cherry_toast/lib/resources/arrays.dart b/app/3rd_party/cherry_toast/lib/resources/arrays.dart
new file mode 100755
index 0000000..d21492d
--- /dev/null
+++ b/app/3rd_party/cherry_toast/lib/resources/arrays.dart
@@ -0,0 +1,7 @@
+enum CHERRY_TYPE { SUCCESS, WARINING, ERROR, INFO, CUSTOM }
+
+enum POSITION { TOP, BOTTOM }
+
+enum ANIMATION_TYPE { FROM_TOP, FROM_LEFT, FROM_RIGHT }
+
+enum TOAST_LAYOUT { LTR, RTL }
diff --git a/app/3rd_party/cherry_toast/lib/resources/colors.dart b/app/3rd_party/cherry_toast/lib/resources/colors.dart
new file mode 100755
index 0000000..4ea81f3
--- /dev/null
+++ b/app/3rd_party/cherry_toast/lib/resources/colors.dart
@@ -0,0 +1,6 @@
+import 'dart:ui';
+
+const Color ERROR_COLOR = Color(0xffE43837);
+const Color SUCCESS_COLOR = Color(0xFF2F9449);
+const Color INFO_COLOR = Color(0xFF4E5CB9);
+const Color WARINING_COLOR = Color(0xffFC9F00);
diff --git a/app/3rd_party/cherry_toast/lib/resources/constants.dart b/app/3rd_party/cherry_toast/lib/resources/constants.dart
new file mode 100755
index 0000000..de2c168
--- /dev/null
+++ b/app/3rd_party/cherry_toast/lib/resources/constants.dart
@@ -0,0 +1,19 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+const String PACKAGE_NAME = "cherry_toast";
+
+const TextStyle DEFAULT_TITLTE_STYLE =
+ const TextStyle(color: Colors.black, fontWeight: FontWeight.bold);
+const TextStyle DEFAULT_DESCRIPTION_STYLE =
+ const TextStyle(color: Colors.black);
+
+const Duration DEFAULT_ANIMATION_DURATION = Duration(milliseconds: 1500);
+const Duration DEFAULT_TOAST_DURATION = Duration(milliseconds: 3000);
+const Cubic DEFAULT_ANIMATION_CURVE = Curves.ease;
+
+const double CLOSE_BUTTON_SIZE = 15;
+
+const double DEFAULT_ICON_SIZE = 20;
+const double DEFAULT_ICON_LAYOUT_SIZE = 40;
+const double DEFAULT_RADIUS = 20;
diff --git a/app/3rd_party/cherry_toast/pubspec.yaml b/app/3rd_party/cherry_toast/pubspec.yaml
new file mode 100755
index 0000000..831892b
--- /dev/null
+++ b/app/3rd_party/cherry_toast/pubspec.yaml
@@ -0,0 +1,18 @@
+name: cherry_toast
+description: A new way to display toasts in flutter with elegant design and animations
+version: 1.0.2
+homepage: https://github.com/koukibadr/Cherry-Toast
+
+environment:
+ sdk: '>=2.12.0 <3.0.0'
+ flutter: ">=1.17.0"
+
+dependencies:
+ flutter:
+ sdk: flutter
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+flutter:
diff --git a/app/lib/models/scheme.dart b/app/lib/models/scheme.dart
index b09be41..f30deca 100644
--- a/app/lib/models/scheme.dart
+++ b/app/lib/models/scheme.dart
@@ -246,10 +246,10 @@ class GestureProp implements Comparable {
Map toJson() => {
'id': id,
- 'gesture': H.getGestureName(gesture),
+ 'gesture': gesture?.name,
'direction': H.getGestureDirectionName(direction),
'fingers': fingers,
- 'type': H.getGestureTypeName(type),
+ 'type': type?.name,
'command': command,
'remark': remark,
};
diff --git a/app/lib/pages/gesture_editor.dart b/app/lib/pages/gesture_editor.dart
index 92a9852..56aa120 100644
--- a/app/lib/pages/gesture_editor.dart
+++ b/app/lib/pages/gesture_editor.dart
@@ -9,6 +9,7 @@ import 'package:dde_gesture_manager/models/settings.provider.dart';
import 'package:dde_gesture_manager/pages/content.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:dde_gesture_manager/utils/keyboard_mapper.dart';
+import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:dde_gesture_manager/widgets/dde_button.dart';
import 'package:dde_gesture_manager/widgets/dde_data_table.dart';
import 'package:dde_gesture_manager/widgets/dde_text_field.dart';
@@ -126,32 +127,27 @@ class GestureEditor extends StatelessWidget {
controller: horizontalCtrl,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.maxWidth),
- child: IgnorePointer(
- ignoring: schemeProvider.readOnly,
- child: DDataTable(
- showBottomBorder: true,
- headingRowHeight: _headingRowHeight,
- showCheckboxColumn: true,
- headerBackgroundColor: context.t.dialogBackgroundColor,
- verticalScrollController: verticalCtrl,
- dataRowColor:
- MaterialStateProperty.resolveWith((Set states) {
- if (states.contains(MaterialState.hovered))
- return context.t.dialogBackgroundColor;
- if (states.contains(MaterialState.selected))
- return context.read().currentActiveColor;
- return null;
- }),
- columns: [
- DDataColumn(label: Text(LocaleKeys.gesture_editor_fingers.tr()), center: true),
- DDataColumn(label: Text(LocaleKeys.gesture_editor_gesture.tr()), center: true),
- DDataColumn(label: Text(LocaleKeys.gesture_editor_direction.tr()), center: true),
- DDataColumn(label: Text(LocaleKeys.gesture_editor_type.tr()), center: true),
- DDataColumn(label: Text(LocaleKeys.gesture_editor_command.tr())),
- DDataColumn(label: Text(LocaleKeys.gesture_editor_remark.tr())),
- ],
- rows: _buildDataRows(schemeProvider.gestures, context),
- ),
+ child: DDataTable(
+ showBottomBorder: true,
+ headingRowHeight: _headingRowHeight,
+ showCheckboxColumn: true,
+ headerBackgroundColor: context.t.dialogBackgroundColor,
+ verticalScrollController: verticalCtrl,
+ dataRowColor: MaterialStateProperty.resolveWith((Set states) {
+ if (states.contains(MaterialState.hovered)) return context.t.dialogBackgroundColor;
+ if (states.contains(MaterialState.selected))
+ return context.read().currentActiveColor;
+ return null;
+ }),
+ columns: [
+ DDataColumn(label: Text(LocaleKeys.gesture_editor_fingers.tr()), center: true),
+ DDataColumn(label: Text(LocaleKeys.gesture_editor_gesture.tr()), center: true),
+ DDataColumn(label: Text(LocaleKeys.gesture_editor_direction.tr()), center: true),
+ DDataColumn(label: Text(LocaleKeys.gesture_editor_type.tr()), center: true),
+ DDataColumn(label: Text(LocaleKeys.gesture_editor_command.tr())),
+ DDataColumn(label: Text(LocaleKeys.gesture_editor_remark.tr())),
+ ],
+ rows: _buildDataRows(context, schemeProvider.gestures, schemeProvider.readOnly),
),
),
),
@@ -169,9 +165,7 @@ class GestureEditor extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.end,
children: [
DButton.add(
- enabled: !schemeProvider.readOnly &&
- !gesturePropProvider.editMode! &&
- !schemeTree.fullFiled,
+ enabled: !schemeProvider.readOnly && !gesturePropProvider.editMode! && !schemeTree.fullFiled,
onTap: () {
var schemeProvider = context.read();
var newGestures = [
@@ -201,15 +195,16 @@ class GestureEditor extends StatelessWidget {
},
),
DButton.duplicate(
- enabled: !schemeProvider.readOnly &&
- gesturePropProvider != GestureProp.empty() &&
- !gesturePropProvider.editMode!,
+ enabled: gesturePropProvider != GestureProp.empty() && !gesturePropProvider.editMode!,
onTap: () {
var schemeProvider = context.read();
context.read().copyFrom(
schemeProvider.gestures!.firstWhere((element) => element.id == gesturePropProvider.id));
-
- /// todo: give some info to UI.
+ Notificator.success(
+ context,
+ title: LocaleKeys.info_gesture_prop_duplicated_title.tr(),
+ description: LocaleKeys.info_gesture_prop_duplicated_description.tr(),
+ );
},
),
DButton.paste(
@@ -306,7 +301,8 @@ class GestureEditor extends StatelessWidget {
}
}
-List _buildDataRows(List? gestures, BuildContext context) => (gestures ?? []).map((gesture) {
+List _buildDataRows(BuildContext context, List? gestures, bool readOnly) =>
+ (gestures ?? []).map((gesture) {
var gesturePropProvider = context.watch();
bool editing = gesturePropProvider == gesture && gesturePropProvider.editMode == true;
bool selected = gesturePropProvider == gesture && !editing;
@@ -320,7 +316,7 @@ List _buildDataRows(List? gestures, BuildContext context)
Future.microtask(() => provider.setProps(
id: gesture.id,
));
- } else if (selected == false) {
+ } else if (selected == false && !readOnly) {
provider.onEditEnd = (prop) {
var schemeProvider = context.read();
var newGestures = List.of(schemeProvider.gestures!);
@@ -408,7 +404,7 @@ List _buildRowCellsEditing(BuildContext context) {
.map(
(e) => DropdownMenuItem(
child: Text(
- '${LocaleKeys.gesture_editor_gestures}.${H.getGestureName(e)}',
+ '${LocaleKeys.gesture_editor_gestures}.${e.name}',
textScaleFactor: .8,
).tr(),
value: e,
@@ -456,7 +452,7 @@ List _buildRowCellsEditing(BuildContext context) {
.map(
(e) => DropdownMenuItem(
child: Text(
- '${LocaleKeys.gesture_editor_types}.${H.getGestureTypeName(e)}',
+ '${LocaleKeys.gesture_editor_types}.${e.name}',
textScaleFactor: .8,
).tr(),
value: e,
@@ -545,7 +541,7 @@ List _buildRowCellsNormal(BuildContext context, bool selected, Gestur
),
Center(
child: Text(
- '${LocaleKeys.gesture_editor_gestures}.${H.getGestureName(gesture.gesture)}',
+ '${LocaleKeys.gesture_editor_gestures}.${gesture.gesture?.name}',
).tr(),
),
Center(
@@ -554,7 +550,7 @@ List _buildRowCellsNormal(BuildContext context, bool selected, Gestur
).tr()),
Center(
child: Text(
- '${LocaleKeys.gesture_editor_types}.${H.getGestureTypeName(gesture.type)}',
+ '${LocaleKeys.gesture_editor_types}.${gesture.type?.name}',
).tr()),
gesture.type == GestureType.shortcut
? Row(
diff --git a/app/lib/pages/local_manager.dart b/app/lib/pages/local_manager.dart
index 5e7dc57..3e3723f 100644
--- a/app/lib/pages/local_manager.dart
+++ b/app/lib/pages/local_manager.dart
@@ -51,7 +51,7 @@ class _LocalManagerState extends State {
Color _getItemBackgroundColor(int index, String itemPath) {
Color _color = index % 2 == 0 ? context.t.scaffoldBackgroundColor : context.t.backgroundColor;
- if (itemPath == _hoveringItem) _color = context.t.scaffoldBackgroundColor;
+ if (itemPath == _hoveringItem) _color = context.t.dialogBackgroundColor;
if (itemPath == _selectedItemPath) _color = context.read().currentActiveColor;
return _color;
}
@@ -145,7 +145,7 @@ class _LocalManagerState extends State {
cursor: SystemMouseCursors.click,
onEnter: (_) {
setState(() {
- _hoveringItem = localSchemes[index].scheme.id!;
+ _hoveringItem = localSchemes[index].path;
});
},
child: Container(
diff --git a/app/lib/utils/alert_interface.dart b/app/lib/utils/alert_interface.dart
new file mode 100644
index 0000000..fa7a3d9
--- /dev/null
+++ b/app/lib/utils/alert_interface.dart
@@ -0,0 +1,18 @@
+export 'alert_web.dart' if (dart.library.io) 'alert_platform.dart';
+
+import 'package:flutter_platform_alert/flutter_platform_alert.dart';
+
+abstract class Alert {
+ Future showAlert({
+ required String windowTitle,
+ required String text,
+ String? positiveButtonTitle,
+ });
+
+ Future showConfirm({
+ required String windowTitle,
+ required String text,
+ String? positiveButtonTitle,
+ String? negativeButtonTitle,
+ });
+}
\ No newline at end of file
diff --git a/app/lib/utils/alert_platform.dart b/app/lib/utils/alert_platform.dart
new file mode 100644
index 0000000..e9eaead
--- /dev/null
+++ b/app/lib/utils/alert_platform.dart
@@ -0,0 +1,30 @@
+import 'alert_interface.dart';
+import 'package:flutter_platform_alert/flutter_platform_alert.dart';
+
+class AlertImpl implements Alert {
+ @override
+ Future showAlert({
+ required String windowTitle,
+ required String text,
+ String? positiveButtonTitle,
+ }) =>
+ FlutterPlatformAlert.showCustomAlert(
+ windowTitle: windowTitle,
+ text: text,
+ positiveButtonTitle: positiveButtonTitle,
+ );
+
+ @override
+ Future showConfirm({
+ required String windowTitle,
+ required String text,
+ String? positiveButtonTitle,
+ String? negativeButtonTitle,
+ }) =>
+ FlutterPlatformAlert.showCustomAlert(
+ windowTitle: windowTitle,
+ text: text,
+ positiveButtonTitle: positiveButtonTitle,
+ negativeButtonTitle: negativeButtonTitle,
+ );
+}
diff --git a/app/lib/utils/alert_web.dart b/app/lib/utils/alert_web.dart
new file mode 100644
index 0000000..c5bf038
--- /dev/null
+++ b/app/lib/utils/alert_web.dart
@@ -0,0 +1,30 @@
+import 'package:flutter_platform_alert/flutter_platform_alert.dart';
+
+import 'alert_interface.dart';
+
+import 'dart:html' as html;
+
+class AlertImpl implements Alert {
+ @override
+ Future showAlert({
+ required String windowTitle,
+ required String text,
+ String? positiveButtonTitle,
+ }) {
+ html.window.alert([windowTitle, text].join('\n'));
+ return Future.value(CustomButton.positiveButton);
+ }
+
+ @override
+ Future showConfirm({
+ required String windowTitle,
+ required String text,
+ String? positiveButtonTitle,
+ String? negativeButtonTitle,
+ }) {
+ var confirmed = html.window.confirm([windowTitle, text].join('\n'));
+ return Future.value(
+ confirmed ? CustomButton.positiveButton : CustomButton.negativeButton,
+ );
+ }
+}
diff --git a/app/lib/utils/helper.dart b/app/lib/utils/helper.dart
index 6752dcb..61350dd 100644
--- a/app/lib/utils/helper.dart
+++ b/app/lib/utils/helper.dart
@@ -6,6 +6,15 @@ import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
+extension EnumByName on Iterable {
+ T? findByName(String name) {
+ for (var value in this) {
+ if (value.name == name) return value;
+ }
+ return null;
+ }
+}
+
class H {
H._();
@@ -50,19 +59,7 @@ class H {
return preferredPanelsStatus..marketPanelOpened = false;
}
- static String? getGestureName(Gesture? gesture) => const {
- Gesture.swipe: 'swipe',
- Gesture.tap: 'tap',
- Gesture.pinch: 'pinch',
- }[gesture];
-
- static Gesture getGestureByName(String gestureName) =>
- const {
- 'swipe': Gesture.swipe,
- 'tap': Gesture.tap,
- 'pinch': Gesture.pinch,
- }[gestureName] ??
- Gesture.swipe;
+ static Gesture getGestureByName(String gestureName) => Gesture.values.findByName(gestureName) ?? Gesture.swipe;
static String? getGestureDirectionName(GestureDirection? direction) => const {
GestureDirection.up: 'up',
@@ -85,19 +82,8 @@ class H {
}[directionName] ??
GestureDirection.none;
- static String? getGestureTypeName(GestureType? type) => const {
- GestureType.built_in: 'built_in',
- GestureType.shortcut: 'shortcut',
- GestureType.commandline: 'commandline',
- }[type];
-
static GestureType getGestureTypeByName(String typeName) =>
- const {
- 'built_in': GestureType.built_in,
- 'shortcut': GestureType.shortcut,
- 'commandline': GestureType.commandline,
- }[typeName] ??
- GestureType.built_in;
+ GestureType.values.findByName(typeName) ?? GestureType.built_in;
static Color? parseQtActiveColor(String? inp) {
if (inp == null) return null;
diff --git a/app/lib/utils/notificator.dart b/app/lib/utils/notificator.dart
new file mode 100644
index 0000000..3ef808d
--- /dev/null
+++ b/app/lib/utils/notificator.dart
@@ -0,0 +1,127 @@
+import 'package:cherry_toast/cherry_toast.dart';
+import 'package:cherry_toast/resources/arrays.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_platform_alert/flutter_platform_alert.dart';
+
+import 'alert_interface.dart';
+
+class Notificator {
+ static Future showAlert({
+ required String title,
+ required String description,
+ String? positiveButtonTitle,
+ }) {
+ return AlertImpl().showAlert(
+ windowTitle: title,
+ text: description,
+ positiveButtonTitle: positiveButtonTitle,
+ );
+ }
+
+ static Future showConfirm({
+ required String title,
+ required String description,
+ String? positiveButtonTitle,
+ String? negativeButtonTitle,
+ }) {
+ return AlertImpl().showConfirm(
+ windowTitle: title,
+ text: description,
+ positiveButtonTitle: positiveButtonTitle,
+ negativeButtonTitle: negativeButtonTitle,
+ );
+ }
+
+ static _setToastIconBackgroundColor(CherryToast toast, bool isDarkMode) {
+ var hslColor = HSLColor.fromColor(toast.themeColor);
+ toast.themeColor = hslColor.withLightness((hslColor.lightness + (isDarkMode ? 0.4 : 0.1)).clamp(0, 1)).toColor();
+ }
+
+ static CherryToast info(
+ BuildContext context, {
+ required String title,
+ String? description,
+ }) {
+ var themeData = Theme.of(context);
+ var toast = CherryToast.info(
+ title: title,
+ description: description,
+ autoDismiss: true,
+ animationType: ANIMATION_TYPE.FROM_TOP,
+ animationDuration: Duration(milliseconds: 300),
+ toastDuration: Duration(seconds: 3),
+ backgroundColor: themeData.backgroundColor,
+ titleStyle: themeData.textTheme.bodyText1!.copyWith(fontWeight: FontWeight.bold),
+ descriptionStyle: themeData.textTheme.bodyText1!,
+ );
+ _setToastIconBackgroundColor(toast, themeData.brightness == Brightness.dark);
+ toast.show(context);
+ return toast;
+ }
+
+ static CherryToast warning(
+ BuildContext context, {
+ required String title,
+ String? description,
+ }) {
+ var themeData = Theme.of(context);
+ var toast = CherryToast.warning(
+ title: title,
+ description: description,
+ autoDismiss: true,
+ animationType: ANIMATION_TYPE.FROM_TOP,
+ animationDuration: Duration(milliseconds: 300),
+ toastDuration: Duration(seconds: 3),
+ backgroundColor: themeData.backgroundColor,
+ titleStyle: themeData.textTheme.bodyText1!.copyWith(fontWeight: FontWeight.bold),
+ descriptionStyle: themeData.textTheme.bodyText1!,
+ );
+ _setToastIconBackgroundColor(toast, themeData.brightness == Brightness.dark);
+ toast.show(context);
+ return toast;
+ }
+
+ static CherryToast error(
+ BuildContext context, {
+ required String title,
+ String? description,
+ }) {
+ var themeData = Theme.of(context);
+ var toast = CherryToast.error(
+ title: title,
+ description: description,
+ autoDismiss: true,
+ animationType: ANIMATION_TYPE.FROM_TOP,
+ animationDuration: Duration(milliseconds: 300),
+ toastDuration: Duration(seconds: 3),
+ backgroundColor: themeData.backgroundColor,
+ titleStyle: themeData.textTheme.bodyText1!.copyWith(fontWeight: FontWeight.bold),
+ descriptionStyle: themeData.textTheme.bodyText1!,
+ );
+ _setToastIconBackgroundColor(toast, themeData.brightness == Brightness.dark);
+ toast.show(context);
+ return toast;
+ }
+
+ static CherryToast success(
+ BuildContext context, {
+ required String title,
+ String? description,
+ }) {
+ var themeData = Theme.of(context);
+ var toast = CherryToast.success(
+ title: title,
+ description: description,
+ autoDismiss: true,
+ animationType: ANIMATION_TYPE.FROM_TOP,
+ animationDuration: Duration(milliseconds: 300),
+ toastDuration: Duration(seconds: 3),
+ backgroundColor: themeData.backgroundColor,
+ titleStyle: themeData.textTheme.bodyText1!.copyWith(fontWeight: FontWeight.bold),
+ descriptionStyle: themeData.textTheme.bodyText1!,
+ );
+ _setToastIconBackgroundColor(toast, themeData.brightness == Brightness.dark);
+ toast.show(context);
+ return toast;
+ }
+}
diff --git a/app/lib/widgets/dde_data_table.dart b/app/lib/widgets/dde_data_table.dart
index b4e6e96..d145abd 100644
--- a/app/lib/widgets/dde_data_table.dart
+++ b/app/lib/widgets/dde_data_table.dart
@@ -17,7 +17,7 @@ typedef DataColumnSortCallback = void Function(int columnIndex, bool ascending);
///
/// One column configuration must be provided for each column to
/// display in the table. The list of [DataColumn] objects is passed
-/// as the `columns` argument to the [new DataTable] constructor.
+/// as the `columns` argument to the [DataTable] constructor.
@immutable
class DDataColumn {
/// Creates the configuration for a column of a [DataTable].
@@ -73,7 +73,7 @@ class DDataColumn {
///
/// One row configuration must be provided for each row to
/// display in the table. The list of [DataRow] objects is passed
-/// as the `rows` argument to the [new DataTable] constructor.
+/// as the `rows` argument to the [DataTable] constructor.
///
/// The data for this row of the table is provided in the [cells]
/// property of the [DataRow] object.
@@ -995,7 +995,7 @@ class _DDataTableState extends State {
List _skickyHeaders = [];
var _headerBackgroundHSLColor = HSLColor.fromColor(widget.headerBackgroundColor);
- HSLColor.fromColor(widget.headerBackgroundColor).withSaturation(.1).toColor();
+ // HSLColor.fromColor(widget.headerBackgroundColor).withSaturation(.1).toColor();
if (_headersRect != null && _headersRect!.length > 0) {
for (var i = 0; i < _headersRect!.length; i++) {
_skickyHeaders.add(Positioned(
diff --git a/app/linux/flutter/generated_plugin_registrant.cc b/app/linux/flutter/generated_plugin_registrant.cc
index 5a6c006..da1524f 100644
--- a/app/linux/flutter/generated_plugin_registrant.cc
+++ b/app/linux/flutter/generated_plugin_registrant.cc
@@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h"
+#include
#include
void fl_register_plugins(FlPluginRegistry* registry) {
+ g_autoptr(FlPluginRegistrar) flutter_platform_alert_registrar =
+ fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterPlatformAlertPlugin");
+ flutter_platform_alert_plugin_register_with_registrar(flutter_platform_alert_registrar);
g_autoptr(FlPluginRegistrar) window_manager_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
window_manager_plugin_register_with_registrar(window_manager_registrar);
diff --git a/app/linux/flutter/generated_plugins.cmake b/app/linux/flutter/generated_plugins.cmake
index 567db6d..5a9d113 100644
--- a/app/linux/flutter/generated_plugins.cmake
+++ b/app/linux/flutter/generated_plugins.cmake
@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
+ flutter_platform_alert
window_manager
)
diff --git a/app/pubspec.yaml b/app/pubspec.yaml
index 7056b83..42a6021 100644
--- a/app/pubspec.yaml
+++ b/app/pubspec.yaml
@@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.15.0 <3.0.0"
dependencies:
flutter:
@@ -37,6 +37,9 @@ dependencies:
path_provider: ^2.0.5
uuid: ^3.0.5
adaptive_scrollbar: ^2.1.0
+ flutter_platform_alert: ^0.2.1
+ cherry_toast:
+ path: 3rd_party/cherry_toast
xdg_directories_web:
path: 3rd_party/xdg_directories_web
diff --git a/app/resources/langs/en.json b/app/resources/langs/en.json
index 389276f..c8cb52d 100644
--- a/app/resources/langs/en.json
+++ b/app/resources/langs/en.json
@@ -82,5 +82,11 @@
"SplitWindowLeft": "SplitWindowLeft",
"SplitWindowRight": "SplitWindowRight",
"MoveWindow": "MoveWindow"
+ },
+ "info": {
+ "gesture_prop_duplicated": {
+ "title": "Duplicated !",
+ "description": "Now you can go to other scheme and click the paste button ~"
+ }
}
}
\ No newline at end of file
diff --git a/app/resources/langs/zh-CN.json b/app/resources/langs/zh-CN.json
index 00e0f2d..d9a46be 100644
--- a/app/resources/langs/zh-CN.json
+++ b/app/resources/langs/zh-CN.json
@@ -82,5 +82,11 @@
"SplitWindowLeft": "向左分屏",
"SplitWindowRight": "向右分屏",
"MoveWindow": "移动窗口"
+ },
+ "info": {
+ "gesture_prop_duplicated": {
+ "title": "复制成功!",
+ "description": "现在可以去其他方案中点击粘贴按钮试试哦~"
+ }
}
}
\ No newline at end of file