Committed by
GitHub
Merge pull request #2008 from jonataslaw/snackbar2.0
prepare snackbar api to getx 5
Showing
9 changed files
with
1145 additions
and
1162 deletions
| @@ -17,4 +17,4 @@ export 'src/routes/observers/route_observer.dart'; | @@ -17,4 +17,4 @@ export 'src/routes/observers/route_observer.dart'; | ||
| 17 | export 'src/routes/route_middleware.dart'; | 17 | export 'src/routes/route_middleware.dart'; |
| 18 | export 'src/routes/transitions_type.dart'; | 18 | export 'src/routes/transitions_type.dart'; |
| 19 | export 'src/snackbar/snack.dart'; | 19 | export 'src/snackbar/snack.dart'; |
| 20 | -export 'src/snackbar/snack_route.dart'; | 20 | +export 'src/snackbar/snackbar_controller.dart'; |
| @@ -11,243 +11,56 @@ import 'dialog/dialog_route.dart'; | @@ -11,243 +11,56 @@ import 'dialog/dialog_route.dart'; | ||
| 11 | import 'root/parse_route.dart'; | 11 | import 'root/parse_route.dart'; |
| 12 | import 'root/root_controller.dart'; | 12 | import 'root/root_controller.dart'; |
| 13 | import 'routes/transitions_type.dart'; | 13 | import 'routes/transitions_type.dart'; |
| 14 | +import 'snackbar/snackbar_controller.dart'; | ||
| 14 | 15 | ||
| 15 | -extension ExtensionSnackbar on GetInterface { | ||
| 16 | - void rawSnackbar({ | ||
| 17 | - String? title, | ||
| 18 | - String? message, | ||
| 19 | - Widget? titleText, | ||
| 20 | - Widget? messageText, | ||
| 21 | - Widget? icon, | ||
| 22 | - bool instantInit = true, | ||
| 23 | - bool shouldIconPulse = true, | ||
| 24 | - double? maxWidth, | ||
| 25 | - EdgeInsets margin = const EdgeInsets.all(0.0), | ||
| 26 | - EdgeInsets padding = const EdgeInsets.all(16), | ||
| 27 | - double borderRadius = 0.0, | ||
| 28 | - Color? borderColor, | ||
| 29 | - double borderWidth = 1.0, | ||
| 30 | - Color backgroundColor = const Color(0xFF303030), | ||
| 31 | - Color? leftBarIndicatorColor, | ||
| 32 | - List<BoxShadow>? boxShadows, | ||
| 33 | - Gradient? backgroundGradient, | ||
| 34 | - Widget? mainButton, | ||
| 35 | - OnTap? onTap, | ||
| 36 | - Duration duration = const Duration(seconds: 3), | ||
| 37 | - bool isDismissible = true, | ||
| 38 | - SnackDismissDirection dismissDirection = SnackDismissDirection.VERTICAL, | ||
| 39 | - bool showProgressIndicator = false, | ||
| 40 | - AnimationController? progressIndicatorController, | ||
| 41 | - Color? progressIndicatorBackgroundColor, | ||
| 42 | - Animation<Color>? progressIndicatorValueColor, | ||
| 43 | - SnackPosition snackPosition = SnackPosition.BOTTOM, | ||
| 44 | - SnackStyle snackStyle = SnackStyle.FLOATING, | ||
| 45 | - Curve forwardAnimationCurve = Curves.easeOutCirc, | ||
| 46 | - Curve reverseAnimationCurve = Curves.easeOutCirc, | ||
| 47 | - Duration animationDuration = const Duration(seconds: 1), | ||
| 48 | - SnackbarStatusCallback? snackbarStatus, | ||
| 49 | - double? barBlur = 0.0, | ||
| 50 | - double overlayBlur = 0.0, | ||
| 51 | - Color? overlayColor, | ||
| 52 | - Form? userInputForm, | ||
| 53 | - }) async { | ||
| 54 | - final getBar = GetBar( | ||
| 55 | - snackbarStatus: snackbarStatus, | ||
| 56 | - title: title, | ||
| 57 | - message: message, | ||
| 58 | - titleText: titleText, | ||
| 59 | - messageText: messageText, | ||
| 60 | - snackPosition: snackPosition, | ||
| 61 | - borderRadius: borderRadius, | ||
| 62 | - margin: margin, | ||
| 63 | - duration: duration, | ||
| 64 | - barBlur: barBlur, | ||
| 65 | - backgroundColor: backgroundColor, | ||
| 66 | - icon: icon, | ||
| 67 | - shouldIconPulse: shouldIconPulse, | ||
| 68 | - maxWidth: maxWidth, | ||
| 69 | - padding: padding, | ||
| 70 | - borderColor: borderColor, | ||
| 71 | - borderWidth: borderWidth, | ||
| 72 | - leftBarIndicatorColor: leftBarIndicatorColor, | ||
| 73 | - boxShadows: boxShadows, | ||
| 74 | - backgroundGradient: backgroundGradient, | ||
| 75 | - mainButton: mainButton, | ||
| 76 | - onTap: onTap, | ||
| 77 | - isDismissible: isDismissible, | ||
| 78 | - dismissDirection: dismissDirection, | ||
| 79 | - showProgressIndicator: showProgressIndicator, | ||
| 80 | - progressIndicatorController: progressIndicatorController, | ||
| 81 | - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, | ||
| 82 | - progressIndicatorValueColor: progressIndicatorValueColor, | ||
| 83 | - snackStyle: snackStyle, | ||
| 84 | - forwardAnimationCurve: forwardAnimationCurve, | ||
| 85 | - reverseAnimationCurve: reverseAnimationCurve, | ||
| 86 | - animationDuration: animationDuration, | ||
| 87 | - overlayBlur: overlayBlur, | ||
| 88 | - overlayColor: overlayColor, | ||
| 89 | - userInputForm: userInputForm, | ||
| 90 | - ); | ||
| 91 | - | ||
| 92 | - if (instantInit) { | ||
| 93 | - getBar.show(); | ||
| 94 | - } else { | ||
| 95 | - SchedulerBinding.instance!.addPostFrameCallback((_) { | ||
| 96 | - getBar.show(); | ||
| 97 | - }); | ||
| 98 | - } | ||
| 99 | - } | ||
| 100 | - | ||
| 101 | - Future<T?>? showSnackbar<T>(GetBar snackbar) { | ||
| 102 | - return key.currentState?.push(SnackRoute<T>(snack: snackbar)); | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - void snackbar<T>( | ||
| 106 | - String title, | ||
| 107 | - String message, { | ||
| 108 | - Color? colorText, | ||
| 109 | - Duration? duration, | 16 | +/// It replaces the Flutter Navigator, but needs no context. |
| 17 | +/// You can to use navigator.push(YourRoute()) rather | ||
| 18 | +/// Navigator.push(context, YourRoute()); | ||
| 19 | +NavigatorState? get navigator => GetNavigation(Get).key.currentState; | ||
| 110 | 20 | ||
| 111 | - /// with instantInit = false you can put snackbar on initState | ||
| 112 | - bool instantInit = true, | ||
| 113 | - SnackPosition? snackPosition, | ||
| 114 | - Widget? titleText, | ||
| 115 | - Widget? messageText, | ||
| 116 | - Widget? icon, | ||
| 117 | - bool? shouldIconPulse, | ||
| 118 | - double? maxWidth, | ||
| 119 | - EdgeInsets? margin, | ||
| 120 | - EdgeInsets? padding, | ||
| 121 | - double? borderRadius, | ||
| 122 | - Color? borderColor, | ||
| 123 | - double? borderWidth, | 21 | +extension ExtensionBottomSheet on GetInterface { |
| 22 | + Future<T?> bottomSheet<T>( | ||
| 23 | + Widget bottomsheet, { | ||
| 124 | Color? backgroundColor, | 24 | Color? backgroundColor, |
| 125 | - Color? leftBarIndicatorColor, | ||
| 126 | - List<BoxShadow>? boxShadows, | ||
| 127 | - Gradient? backgroundGradient, | ||
| 128 | - TextButton? mainButton, | ||
| 129 | - OnTap? onTap, | ||
| 130 | - bool? isDismissible, | ||
| 131 | - bool? showProgressIndicator, | ||
| 132 | - SnackDismissDirection? dismissDirection, | ||
| 133 | - AnimationController? progressIndicatorController, | ||
| 134 | - Color? progressIndicatorBackgroundColor, | ||
| 135 | - Animation<Color>? progressIndicatorValueColor, | ||
| 136 | - SnackStyle? snackStyle, | ||
| 137 | - Curve? forwardAnimationCurve, | ||
| 138 | - Curve? reverseAnimationCurve, | ||
| 139 | - Duration? animationDuration, | ||
| 140 | - double? barBlur, | ||
| 141 | - double? overlayBlur, | ||
| 142 | - SnackbarStatusCallback? snackbarStatus, | ||
| 143 | - Color? overlayColor, | ||
| 144 | - Form? userInputForm, | ||
| 145 | - }) async { | ||
| 146 | - final getBar = GetBar( | ||
| 147 | - snackbarStatus: snackbarStatus, | ||
| 148 | - titleText: titleText ?? | ||
| 149 | - Text( | ||
| 150 | - title, | ||
| 151 | - style: TextStyle( | ||
| 152 | - color: colorText ?? iconColor ?? Colors.black, | ||
| 153 | - fontWeight: FontWeight.w800, | ||
| 154 | - fontSize: 16, | ||
| 155 | - ), | ||
| 156 | - ), | ||
| 157 | - messageText: messageText ?? | ||
| 158 | - Text( | ||
| 159 | - message, | ||
| 160 | - style: TextStyle( | ||
| 161 | - color: colorText ?? iconColor ?? Colors.black, | ||
| 162 | - fontWeight: FontWeight.w300, | ||
| 163 | - fontSize: 14, | ||
| 164 | - ), | ||
| 165 | - ), | ||
| 166 | - snackPosition: snackPosition ?? SnackPosition.TOP, | ||
| 167 | - borderRadius: borderRadius ?? 15, | ||
| 168 | - margin: margin ?? EdgeInsets.symmetric(horizontal: 10), | ||
| 169 | - duration: duration ?? Duration(seconds: 3), | ||
| 170 | - barBlur: barBlur ?? 7.0, | ||
| 171 | - backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2), | ||
| 172 | - icon: icon, | ||
| 173 | - shouldIconPulse: shouldIconPulse ?? true, | ||
| 174 | - maxWidth: maxWidth, | ||
| 175 | - padding: padding ?? EdgeInsets.all(16), | ||
| 176 | - borderColor: borderColor, | ||
| 177 | - borderWidth: borderWidth, | ||
| 178 | - leftBarIndicatorColor: leftBarIndicatorColor, | ||
| 179 | - boxShadows: boxShadows, | ||
| 180 | - backgroundGradient: backgroundGradient, | ||
| 181 | - mainButton: mainButton, | ||
| 182 | - onTap: onTap, | ||
| 183 | - isDismissible: isDismissible ?? true, | ||
| 184 | - dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL, | ||
| 185 | - showProgressIndicator: showProgressIndicator ?? false, | ||
| 186 | - progressIndicatorController: progressIndicatorController, | ||
| 187 | - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, | ||
| 188 | - progressIndicatorValueColor: progressIndicatorValueColor, | ||
| 189 | - snackStyle: snackStyle ?? SnackStyle.FLOATING, | ||
| 190 | - forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc, | ||
| 191 | - reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc, | ||
| 192 | - animationDuration: animationDuration ?? Duration(seconds: 1), | ||
| 193 | - overlayBlur: overlayBlur ?? 0.0, | ||
| 194 | - overlayColor: overlayColor ?? Colors.transparent, | ||
| 195 | - userInputForm: userInputForm); | ||
| 196 | - | ||
| 197 | - if (instantInit) { | ||
| 198 | - showSnackbar<T>(getBar); | ||
| 199 | - } else { | ||
| 200 | - routing.isSnackbar = true; | ||
| 201 | - SchedulerBinding.instance!.addPostFrameCallback((_) { | ||
| 202 | - showSnackbar<T>(getBar); | ||
| 203 | - }); | ||
| 204 | - } | ||
| 205 | - } | ||
| 206 | -} | ||
| 207 | - | ||
| 208 | -extension OverlayExt on GetInterface { | ||
| 209 | - Future<T> showOverlay<T>({ | ||
| 210 | - required Future<T> Function() asyncFunction, | ||
| 211 | - Color opacityColor = Colors.black, | ||
| 212 | - Widget? loadingWidget, | ||
| 213 | - double opacity = .5, | ||
| 214 | - }) async { | ||
| 215 | - final navigatorState = | ||
| 216 | - Navigator.of(Get.overlayContext!, rootNavigator: false); | ||
| 217 | - final overlayState = navigatorState.overlay!; | ||
| 218 | - | ||
| 219 | - final overlayEntryOpacity = OverlayEntry(builder: (context) { | ||
| 220 | - return Opacity( | ||
| 221 | - opacity: opacity, | ||
| 222 | - child: Container( | ||
| 223 | - color: opacityColor, | ||
| 224 | - )); | ||
| 225 | - }); | ||
| 226 | - final overlayEntryLoader = OverlayEntry(builder: (context) { | ||
| 227 | - return loadingWidget ?? | ||
| 228 | - Center( | ||
| 229 | - child: Container( | ||
| 230 | - height: 90, | ||
| 231 | - width: 90, | ||
| 232 | - child: Text('Loading...'), | ||
| 233 | - )); | ||
| 234 | - }); | ||
| 235 | - overlayState.insert(overlayEntryOpacity); | ||
| 236 | - overlayState.insert(overlayEntryLoader); | ||
| 237 | - | ||
| 238 | - T data; | 25 | + double? elevation, |
| 26 | + bool persistent = true, | ||
| 27 | + ShapeBorder? shape, | ||
| 28 | + Clip? clipBehavior, | ||
| 29 | + Color? barrierColor, | ||
| 30 | + bool? ignoreSafeArea, | ||
| 31 | + bool isScrollControlled = false, | ||
| 32 | + bool useRootNavigator = false, | ||
| 33 | + bool isDismissible = true, | ||
| 34 | + bool enableDrag = true, | ||
| 35 | + RouteSettings? settings, | ||
| 36 | + Duration? enterBottomSheetDuration, | ||
| 37 | + Duration? exitBottomSheetDuration, | ||
| 38 | + }) { | ||
| 39 | + return Navigator.of(overlayContext!, rootNavigator: useRootNavigator) | ||
| 40 | + .push(GetModalBottomSheetRoute<T>( | ||
| 41 | + builder: (_) => bottomsheet, | ||
| 42 | + isPersistent: persistent, | ||
| 43 | + // theme: Theme.of(key.currentContext, shadowThemeOnly: true), | ||
| 44 | + theme: Theme.of(key.currentContext!), | ||
| 45 | + isScrollControlled: isScrollControlled, | ||
| 239 | 46 | ||
| 240 | - try { | ||
| 241 | - data = await asyncFunction(); | ||
| 242 | - } on Exception catch (_) { | ||
| 243 | - overlayEntryLoader.remove(); | ||
| 244 | - overlayEntryOpacity.remove(); | ||
| 245 | - rethrow; | ||
| 246 | - } | 47 | + barrierLabel: MaterialLocalizations.of(key.currentContext!) |
| 48 | + .modalBarrierDismissLabel, | ||
| 247 | 49 | ||
| 248 | - overlayEntryLoader.remove(); | ||
| 249 | - overlayEntryOpacity.remove(); | ||
| 250 | - return data; | 50 | + backgroundColor: backgroundColor ?? Colors.transparent, |
| 51 | + elevation: elevation, | ||
| 52 | + shape: shape, | ||
| 53 | + removeTop: ignoreSafeArea ?? true, | ||
| 54 | + clipBehavior: clipBehavior, | ||
| 55 | + isDismissible: isDismissible, | ||
| 56 | + modalBarrierColor: barrierColor, | ||
| 57 | + settings: settings, | ||
| 58 | + enableDrag: enableDrag, | ||
| 59 | + enterBottomSheetDuration: | ||
| 60 | + enterBottomSheetDuration ?? const Duration(milliseconds: 250), | ||
| 61 | + exitBottomSheetDuration: | ||
| 62 | + exitBottomSheetDuration ?? const Duration(milliseconds: 200), | ||
| 63 | + )); | ||
| 251 | } | 64 | } |
| 252 | } | 65 | } |
| 253 | 66 | ||
| @@ -378,7 +191,7 @@ extension ExtensionDialog on GetInterface { | @@ -378,7 +191,7 @@ extension ExtensionDialog on GetInterface { | ||
| 378 | padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8), | 191 | padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8), |
| 379 | shape: RoundedRectangleBorder( | 192 | shape: RoundedRectangleBorder( |
| 380 | side: BorderSide( | 193 | side: BorderSide( |
| 381 | - color: buttonColor ?? theme.accentColor, | 194 | + color: buttonColor ?? theme.colorScheme.secondary, |
| 382 | width: 2, | 195 | width: 2, |
| 383 | style: BorderStyle.solid), | 196 | style: BorderStyle.solid), |
| 384 | borderRadius: BorderRadius.circular(100)), | 197 | borderRadius: BorderRadius.circular(100)), |
| @@ -389,7 +202,8 @@ extension ExtensionDialog on GetInterface { | @@ -389,7 +202,8 @@ extension ExtensionDialog on GetInterface { | ||
| 389 | }, | 202 | }, |
| 390 | child: Text( | 203 | child: Text( |
| 391 | textCancel ?? "Cancel", | 204 | textCancel ?? "Cancel", |
| 392 | - style: TextStyle(color: cancelTextColor ?? theme.accentColor), | 205 | + style: TextStyle( |
| 206 | + color: cancelTextColor ?? theme.colorScheme.secondary), | ||
| 393 | ), | 207 | ), |
| 394 | )); | 208 | )); |
| 395 | } | 209 | } |
| @@ -397,113 +211,265 @@ extension ExtensionDialog on GetInterface { | @@ -397,113 +211,265 @@ extension ExtensionDialog on GetInterface { | ||
| 397 | if (confirm != null) { | 211 | if (confirm != null) { |
| 398 | actions.add(confirm); | 212 | actions.add(confirm); |
| 399 | } else { | 213 | } else { |
| 400 | - if (leanConfirm) { | ||
| 401 | - actions.add(TextButton( | ||
| 402 | - style: TextButton.styleFrom( | ||
| 403 | - tapTargetSize: MaterialTapTargetSize.shrinkWrap, | ||
| 404 | - backgroundColor: buttonColor ?? theme.accentColor, | ||
| 405 | - shape: RoundedRectangleBorder( | ||
| 406 | - borderRadius: BorderRadius.circular(100)), | ||
| 407 | - ), | ||
| 408 | - child: Text( | ||
| 409 | - textConfirm ?? "Ok", | ||
| 410 | - style: | ||
| 411 | - TextStyle(color: confirmTextColor ?? theme.backgroundColor), | ||
| 412 | - ), | ||
| 413 | - onPressed: () { | ||
| 414 | - onConfirm?.call(); | ||
| 415 | - })); | ||
| 416 | - } | 214 | + if (leanConfirm) { |
| 215 | + actions.add(TextButton( | ||
| 216 | + style: TextButton.styleFrom( | ||
| 217 | + tapTargetSize: MaterialTapTargetSize.shrinkWrap, | ||
| 218 | + backgroundColor: buttonColor ?? theme.colorScheme.secondary, | ||
| 219 | + shape: RoundedRectangleBorder( | ||
| 220 | + borderRadius: BorderRadius.circular(100)), | ||
| 221 | + ), | ||
| 222 | + child: Text( | ||
| 223 | + textConfirm ?? "Ok", | ||
| 224 | + style: | ||
| 225 | + TextStyle(color: confirmTextColor ?? theme.backgroundColor), | ||
| 226 | + ), | ||
| 227 | + onPressed: () { | ||
| 228 | + onConfirm?.call(); | ||
| 229 | + })); | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + Widget baseAlertDialog = AlertDialog( | ||
| 234 | + titlePadding: titlePadding ?? EdgeInsets.all(8), | ||
| 235 | + contentPadding: contentPadding ?? EdgeInsets.all(8), | ||
| 236 | + | ||
| 237 | + backgroundColor: backgroundColor ?? theme.dialogBackgroundColor, | ||
| 238 | + shape: RoundedRectangleBorder( | ||
| 239 | + borderRadius: BorderRadius.all(Radius.circular(radius))), | ||
| 240 | + title: Text(title, textAlign: TextAlign.center, style: titleStyle), | ||
| 241 | + content: Column( | ||
| 242 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 243 | + mainAxisSize: MainAxisSize.min, | ||
| 244 | + children: [ | ||
| 245 | + content ?? | ||
| 246 | + Text(middleText, | ||
| 247 | + textAlign: TextAlign.center, style: middleTextStyle), | ||
| 248 | + SizedBox(height: 16), | ||
| 249 | + ButtonTheme( | ||
| 250 | + minWidth: 78.0, | ||
| 251 | + height: 34.0, | ||
| 252 | + child: Wrap( | ||
| 253 | + alignment: WrapAlignment.center, | ||
| 254 | + spacing: 8, | ||
| 255 | + runSpacing: 8, | ||
| 256 | + children: actions, | ||
| 257 | + ), | ||
| 258 | + ) | ||
| 259 | + ], | ||
| 260 | + ), | ||
| 261 | + // actions: actions, // ?? <Widget>[cancelButton, confirmButton], | ||
| 262 | + buttonPadding: EdgeInsets.zero, | ||
| 263 | + ); | ||
| 264 | + | ||
| 265 | + return dialog<T>( | ||
| 266 | + onWillPop != null | ||
| 267 | + ? WillPopScope( | ||
| 268 | + onWillPop: onWillPop, | ||
| 269 | + child: baseAlertDialog, | ||
| 270 | + ) | ||
| 271 | + : baseAlertDialog, | ||
| 272 | + barrierDismissible: barrierDismissible, | ||
| 273 | + navigatorKey: navigatorKey, | ||
| 274 | + ); | ||
| 275 | + } | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | +extension ExtensionSnackbar on GetInterface { | ||
| 279 | + void rawSnackbar({ | ||
| 280 | + String? title, | ||
| 281 | + String? message, | ||
| 282 | + Widget? titleText, | ||
| 283 | + Widget? messageText, | ||
| 284 | + Widget? icon, | ||
| 285 | + bool instantInit = true, | ||
| 286 | + bool shouldIconPulse = true, | ||
| 287 | + double? maxWidth, | ||
| 288 | + EdgeInsets margin = const EdgeInsets.all(0.0), | ||
| 289 | + EdgeInsets padding = const EdgeInsets.all(16), | ||
| 290 | + double borderRadius = 0.0, | ||
| 291 | + Color? borderColor, | ||
| 292 | + double borderWidth = 1.0, | ||
| 293 | + Color backgroundColor = const Color(0xFF303030), | ||
| 294 | + Color? leftBarIndicatorColor, | ||
| 295 | + List<BoxShadow>? boxShadows, | ||
| 296 | + Gradient? backgroundGradient, | ||
| 297 | + Widget? mainButton, | ||
| 298 | + OnTap? onTap, | ||
| 299 | + Duration duration = const Duration(seconds: 3), | ||
| 300 | + bool isDismissible = true, | ||
| 301 | + DismissDirection? dismissDirection, | ||
| 302 | + bool showProgressIndicator = false, | ||
| 303 | + AnimationController? progressIndicatorController, | ||
| 304 | + Color? progressIndicatorBackgroundColor, | ||
| 305 | + Animation<Color>? progressIndicatorValueColor, | ||
| 306 | + SnackPosition snackPosition = SnackPosition.BOTTOM, | ||
| 307 | + SnackStyle snackStyle = SnackStyle.FLOATING, | ||
| 308 | + Curve forwardAnimationCurve = Curves.easeOutCirc, | ||
| 309 | + Curve reverseAnimationCurve = Curves.easeOutCirc, | ||
| 310 | + Duration animationDuration = const Duration(seconds: 1), | ||
| 311 | + SnackbarStatusCallback? snackbarStatus, | ||
| 312 | + double? barBlur = 0.0, | ||
| 313 | + double overlayBlur = 0.0, | ||
| 314 | + Color? overlayColor, | ||
| 315 | + Form? userInputForm, | ||
| 316 | + }) async { | ||
| 317 | + final getBar = GetSnackBar( | ||
| 318 | + snackbarStatus: snackbarStatus, | ||
| 319 | + title: title, | ||
| 320 | + message: message, | ||
| 321 | + titleText: titleText, | ||
| 322 | + messageText: messageText, | ||
| 323 | + snackPosition: snackPosition, | ||
| 324 | + borderRadius: borderRadius, | ||
| 325 | + margin: margin, | ||
| 326 | + duration: duration, | ||
| 327 | + barBlur: barBlur, | ||
| 328 | + backgroundColor: backgroundColor, | ||
| 329 | + icon: icon, | ||
| 330 | + shouldIconPulse: shouldIconPulse, | ||
| 331 | + maxWidth: maxWidth, | ||
| 332 | + padding: padding, | ||
| 333 | + borderColor: borderColor, | ||
| 334 | + borderWidth: borderWidth, | ||
| 335 | + leftBarIndicatorColor: leftBarIndicatorColor, | ||
| 336 | + boxShadows: boxShadows, | ||
| 337 | + backgroundGradient: backgroundGradient, | ||
| 338 | + mainButton: mainButton, | ||
| 339 | + onTap: onTap, | ||
| 340 | + isDismissible: isDismissible, | ||
| 341 | + dismissDirection: dismissDirection, | ||
| 342 | + showProgressIndicator: showProgressIndicator, | ||
| 343 | + progressIndicatorController: progressIndicatorController, | ||
| 344 | + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, | ||
| 345 | + progressIndicatorValueColor: progressIndicatorValueColor, | ||
| 346 | + snackStyle: snackStyle, | ||
| 347 | + forwardAnimationCurve: forwardAnimationCurve, | ||
| 348 | + reverseAnimationCurve: reverseAnimationCurve, | ||
| 349 | + animationDuration: animationDuration, | ||
| 350 | + overlayBlur: overlayBlur, | ||
| 351 | + overlayColor: overlayColor, | ||
| 352 | + userInputForm: userInputForm, | ||
| 353 | + ); | ||
| 354 | + | ||
| 355 | + if (instantInit) { | ||
| 356 | + getBar.show(); | ||
| 357 | + } else { | ||
| 358 | + SchedulerBinding.instance!.addPostFrameCallback((_) { | ||
| 359 | + getBar.show(); | ||
| 360 | + }); | ||
| 417 | } | 361 | } |
| 362 | + } | ||
| 418 | 363 | ||
| 419 | - Widget baseAlertDialog = AlertDialog( | ||
| 420 | - titlePadding: titlePadding ?? EdgeInsets.all(8), | ||
| 421 | - contentPadding: contentPadding ?? EdgeInsets.all(8), | ||
| 422 | - | ||
| 423 | - backgroundColor: backgroundColor ?? theme.dialogBackgroundColor, | ||
| 424 | - shape: RoundedRectangleBorder( | ||
| 425 | - borderRadius: BorderRadius.all(Radius.circular(radius))), | ||
| 426 | - title: Text(title, textAlign: TextAlign.center, style: titleStyle), | ||
| 427 | - content: Column( | ||
| 428 | - crossAxisAlignment: CrossAxisAlignment.center, | ||
| 429 | - mainAxisSize: MainAxisSize.min, | ||
| 430 | - children: [ | ||
| 431 | - content ?? | ||
| 432 | - Text(middleText, | ||
| 433 | - textAlign: TextAlign.center, style: middleTextStyle), | ||
| 434 | - SizedBox(height: 16), | ||
| 435 | - ButtonTheme( | ||
| 436 | - minWidth: 78.0, | ||
| 437 | - height: 34.0, | ||
| 438 | - child: Wrap( | ||
| 439 | - alignment: WrapAlignment.center, | ||
| 440 | - spacing: 8, | ||
| 441 | - runSpacing: 8, | ||
| 442 | - children: actions, | ||
| 443 | - ), | ||
| 444 | - ) | ||
| 445 | - ], | ||
| 446 | - ), | ||
| 447 | - // actions: actions, // ?? <Widget>[cancelButton, confirmButton], | ||
| 448 | - buttonPadding: EdgeInsets.zero, | ||
| 449 | - ); | ||
| 450 | - | ||
| 451 | - return dialog<T>( | ||
| 452 | - onWillPop != null | ||
| 453 | - ? WillPopScope( | ||
| 454 | - onWillPop: onWillPop, | ||
| 455 | - child: baseAlertDialog, | ||
| 456 | - ) | ||
| 457 | - : baseAlertDialog, | ||
| 458 | - barrierDismissible: barrierDismissible, | ||
| 459 | - navigatorKey: navigatorKey, | ||
| 460 | - ); | 364 | + SnackbarController showSnackbar(GetSnackBar snackbar) { |
| 365 | + final controller = SnackbarController(snackbar); | ||
| 366 | + controller.show(); | ||
| 367 | + return controller; | ||
| 461 | } | 368 | } |
| 462 | -} | ||
| 463 | 369 | ||
| 464 | -extension ExtensionBottomSheet on GetInterface { | ||
| 465 | - Future<T?> bottomSheet<T>( | ||
| 466 | - Widget bottomsheet, { | 370 | + SnackbarController snackbar( |
| 371 | + String title, | ||
| 372 | + String message, { | ||
| 373 | + Color? colorText, | ||
| 374 | + Duration? duration, | ||
| 375 | + | ||
| 376 | + /// with instantInit = false you can put snackbar on initState | ||
| 377 | + bool instantInit = true, | ||
| 378 | + SnackPosition? snackPosition, | ||
| 379 | + Widget? titleText, | ||
| 380 | + Widget? messageText, | ||
| 381 | + Widget? icon, | ||
| 382 | + bool? shouldIconPulse, | ||
| 383 | + double? maxWidth, | ||
| 384 | + EdgeInsets? margin, | ||
| 385 | + EdgeInsets? padding, | ||
| 386 | + double? borderRadius, | ||
| 387 | + Color? borderColor, | ||
| 388 | + double? borderWidth, | ||
| 467 | Color? backgroundColor, | 389 | Color? backgroundColor, |
| 468 | - double? elevation, | ||
| 469 | - bool persistent = true, | ||
| 470 | - ShapeBorder? shape, | ||
| 471 | - Clip? clipBehavior, | ||
| 472 | - Color? barrierColor, | ||
| 473 | - bool? ignoreSafeArea, | ||
| 474 | - bool isScrollControlled = false, | ||
| 475 | - bool useRootNavigator = false, | ||
| 476 | - bool isDismissible = true, | ||
| 477 | - bool enableDrag = true, | ||
| 478 | - RouteSettings? settings, | ||
| 479 | - Duration? enterBottomSheetDuration, | ||
| 480 | - Duration? exitBottomSheetDuration, | 390 | + Color? leftBarIndicatorColor, |
| 391 | + List<BoxShadow>? boxShadows, | ||
| 392 | + Gradient? backgroundGradient, | ||
| 393 | + TextButton? mainButton, | ||
| 394 | + OnTap? onTap, | ||
| 395 | + bool? isDismissible, | ||
| 396 | + bool? showProgressIndicator, | ||
| 397 | + DismissDirection? dismissDirection, | ||
| 398 | + AnimationController? progressIndicatorController, | ||
| 399 | + Color? progressIndicatorBackgroundColor, | ||
| 400 | + Animation<Color>? progressIndicatorValueColor, | ||
| 401 | + SnackStyle? snackStyle, | ||
| 402 | + Curve? forwardAnimationCurve, | ||
| 403 | + Curve? reverseAnimationCurve, | ||
| 404 | + Duration? animationDuration, | ||
| 405 | + double? barBlur, | ||
| 406 | + double? overlayBlur, | ||
| 407 | + SnackbarStatusCallback? snackbarStatus, | ||
| 408 | + Color? overlayColor, | ||
| 409 | + Form? userInputForm, | ||
| 481 | }) { | 410 | }) { |
| 482 | - return Navigator.of(overlayContext!, rootNavigator: useRootNavigator) | ||
| 483 | - .push(GetModalBottomSheetRoute<T>( | ||
| 484 | - builder: (_) => bottomsheet, | ||
| 485 | - isPersistent: persistent, | ||
| 486 | - // theme: Theme.of(key.currentContext, shadowThemeOnly: true), | ||
| 487 | - theme: Theme.of(key.currentContext!), | ||
| 488 | - isScrollControlled: isScrollControlled, | 411 | + final getSnackBar = GetSnackBar( |
| 412 | + snackbarStatus: snackbarStatus, | ||
| 413 | + titleText: titleText ?? | ||
| 414 | + Text( | ||
| 415 | + title, | ||
| 416 | + style: TextStyle( | ||
| 417 | + color: colorText ?? iconColor ?? Colors.black, | ||
| 418 | + fontWeight: FontWeight.w800, | ||
| 419 | + fontSize: 16, | ||
| 420 | + ), | ||
| 421 | + ), | ||
| 422 | + messageText: messageText ?? | ||
| 423 | + Text( | ||
| 424 | + message, | ||
| 425 | + style: TextStyle( | ||
| 426 | + color: colorText ?? iconColor ?? Colors.black, | ||
| 427 | + fontWeight: FontWeight.w300, | ||
| 428 | + fontSize: 14, | ||
| 429 | + ), | ||
| 430 | + ), | ||
| 431 | + snackPosition: snackPosition ?? SnackPosition.TOP, | ||
| 432 | + borderRadius: borderRadius ?? 15, | ||
| 433 | + margin: margin ?? EdgeInsets.symmetric(horizontal: 10), | ||
| 434 | + duration: duration ?? Duration(seconds: 3), | ||
| 435 | + barBlur: barBlur ?? 7.0, | ||
| 436 | + backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2), | ||
| 437 | + icon: icon, | ||
| 438 | + shouldIconPulse: shouldIconPulse ?? true, | ||
| 439 | + maxWidth: maxWidth, | ||
| 440 | + padding: padding ?? EdgeInsets.all(16), | ||
| 441 | + borderColor: borderColor, | ||
| 442 | + borderWidth: borderWidth, | ||
| 443 | + leftBarIndicatorColor: leftBarIndicatorColor, | ||
| 444 | + boxShadows: boxShadows, | ||
| 445 | + backgroundGradient: backgroundGradient, | ||
| 446 | + mainButton: mainButton, | ||
| 447 | + onTap: onTap, | ||
| 448 | + isDismissible: isDismissible ?? true, | ||
| 449 | + dismissDirection: dismissDirection, | ||
| 450 | + showProgressIndicator: showProgressIndicator ?? false, | ||
| 451 | + progressIndicatorController: progressIndicatorController, | ||
| 452 | + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, | ||
| 453 | + progressIndicatorValueColor: progressIndicatorValueColor, | ||
| 454 | + snackStyle: snackStyle ?? SnackStyle.FLOATING, | ||
| 455 | + forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc, | ||
| 456 | + reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc, | ||
| 457 | + animationDuration: animationDuration ?? Duration(seconds: 1), | ||
| 458 | + overlayBlur: overlayBlur ?? 0.0, | ||
| 459 | + overlayColor: overlayColor ?? Colors.transparent, | ||
| 460 | + userInputForm: userInputForm); | ||
| 489 | 461 | ||
| 490 | - barrierLabel: MaterialLocalizations.of(key.currentContext!) | ||
| 491 | - .modalBarrierDismissLabel, | 462 | + final controller = SnackbarController(getSnackBar); |
| 492 | 463 | ||
| 493 | - backgroundColor: backgroundColor ?? Colors.transparent, | ||
| 494 | - elevation: elevation, | ||
| 495 | - shape: shape, | ||
| 496 | - removeTop: ignoreSafeArea ?? true, | ||
| 497 | - clipBehavior: clipBehavior, | ||
| 498 | - isDismissible: isDismissible, | ||
| 499 | - modalBarrierColor: barrierColor, | ||
| 500 | - settings: settings, | ||
| 501 | - enableDrag: enableDrag, | ||
| 502 | - enterBottomSheetDuration: | ||
| 503 | - enterBottomSheetDuration ?? const Duration(milliseconds: 250), | ||
| 504 | - exitBottomSheetDuration: | ||
| 505 | - exitBottomSheetDuration ?? const Duration(milliseconds: 200), | ||
| 506 | - )); | 464 | + if (instantInit) { |
| 465 | + controller.show(); | ||
| 466 | + } else { | ||
| 467 | + //routing.isSnackbar = true; | ||
| 468 | + SchedulerBinding.instance!.addPostFrameCallback((_) { | ||
| 469 | + controller.show(); | ||
| 470 | + }); | ||
| 471 | + } | ||
| 472 | + return controller; | ||
| 507 | } | 473 | } |
| 508 | } | 474 | } |
| 509 | 475 | ||
| @@ -826,11 +792,11 @@ you can only use widgets and widget functions here'''; | @@ -826,11 +792,11 @@ you can only use widgets and widget functions here'''; | ||
| 826 | 792 | ||
| 827 | /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN | 793 | /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN |
| 828 | bool get isOverlaysOpen => | 794 | bool get isOverlaysOpen => |
| 829 | - (isSnackbarOpen! || isDialogOpen! || isBottomSheetOpen!); | 795 | + (isSnackbarOpen || isDialogOpen! || isBottomSheetOpen!); |
| 830 | 796 | ||
| 831 | /// Returns true if there is no Snackbar, Dialog or BottomSheet open | 797 | /// Returns true if there is no Snackbar, Dialog or BottomSheet open |
| 832 | bool get isOverlaysClosed => | 798 | bool get isOverlaysClosed => |
| 833 | - (!isSnackbarOpen! && !isDialogOpen! && !isBottomSheetOpen!); | 799 | + (!isSnackbarOpen && !isDialogOpen! && !isBottomSheetOpen!); |
| 834 | 800 | ||
| 835 | /// **Navigation.popUntil()** shortcut.<br><br> | 801 | /// **Navigation.popUntil()** shortcut.<br><br> |
| 836 | /// | 802 | /// |
| @@ -851,8 +817,11 @@ you can only use widgets and widget functions here'''; | @@ -851,8 +817,11 @@ you can only use widgets and widget functions here'''; | ||
| 851 | int? id, | 817 | int? id, |
| 852 | }) { | 818 | }) { |
| 853 | if (closeOverlays && isOverlaysOpen) { | 819 | if (closeOverlays && isOverlaysOpen) { |
| 820 | + if (isSnackbarOpen) { | ||
| 821 | + closeAllSnackbars(); | ||
| 822 | + } | ||
| 854 | navigator?.popUntil((route) { | 823 | navigator?.popUntil((route) { |
| 855 | - return (isOverlaysClosed); | 824 | + return (!isDialogOpen! && !isBottomSheetOpen!); |
| 856 | }); | 825 | }); |
| 857 | } | 826 | } |
| 858 | if (canPop) { | 827 | if (canPop) { |
| @@ -1135,7 +1104,16 @@ you can only use widgets and widget functions here'''; | @@ -1135,7 +1104,16 @@ you can only use widgets and widget functions here'''; | ||
| 1135 | String get previousRoute => routing.previous; | 1104 | String get previousRoute => routing.previous; |
| 1136 | 1105 | ||
| 1137 | /// check if snackbar is open | 1106 | /// check if snackbar is open |
| 1138 | - bool? get isSnackbarOpen => routing.isSnackbar; | 1107 | + bool get isSnackbarOpen => |
| 1108 | + SnackbarController.isSnackbarBeingShown; //routing.isSnackbar; | ||
| 1109 | + | ||
| 1110 | + void closeAllSnackbars() { | ||
| 1111 | + SnackbarController.cancelAllSnackbars(); | ||
| 1112 | + } | ||
| 1113 | + | ||
| 1114 | + void closeCurrentSnackbar() { | ||
| 1115 | + SnackbarController.closeCurrentSnackbar(); | ||
| 1116 | + } | ||
| 1139 | 1117 | ||
| 1140 | /// check if dialog is open | 1118 | /// check if dialog is open |
| 1141 | bool? get isDialogOpen => routing.isDialog; | 1119 | bool? get isDialogOpen => routing.isDialog; |
| @@ -1341,7 +1319,48 @@ extension NavTwoExt on GetInterface { | @@ -1341,7 +1319,48 @@ extension NavTwoExt on GetInterface { | ||
| 1341 | } | 1319 | } |
| 1342 | } | 1320 | } |
| 1343 | 1321 | ||
| 1344 | -/// It replaces the Flutter Navigator, but needs no context. | ||
| 1345 | -/// You can to use navigator.push(YourRoute()) rather | ||
| 1346 | -/// Navigator.push(context, YourRoute()); | ||
| 1347 | -NavigatorState? get navigator => GetNavigation(Get).key.currentState; | 1322 | +extension OverlayExt on GetInterface { |
| 1323 | + Future<T> showOverlay<T>({ | ||
| 1324 | + required Future<T> Function() asyncFunction, | ||
| 1325 | + Color opacityColor = Colors.black, | ||
| 1326 | + Widget? loadingWidget, | ||
| 1327 | + double opacity = .5, | ||
| 1328 | + }) async { | ||
| 1329 | + final navigatorState = | ||
| 1330 | + Navigator.of(Get.overlayContext!, rootNavigator: false); | ||
| 1331 | + final overlayState = navigatorState.overlay!; | ||
| 1332 | + | ||
| 1333 | + final overlayEntryOpacity = OverlayEntry(builder: (context) { | ||
| 1334 | + return Opacity( | ||
| 1335 | + opacity: opacity, | ||
| 1336 | + child: Container( | ||
| 1337 | + color: opacityColor, | ||
| 1338 | + )); | ||
| 1339 | + }); | ||
| 1340 | + final overlayEntryLoader = OverlayEntry(builder: (context) { | ||
| 1341 | + return loadingWidget ?? | ||
| 1342 | + Center( | ||
| 1343 | + child: Container( | ||
| 1344 | + height: 90, | ||
| 1345 | + width: 90, | ||
| 1346 | + child: Text('Loading...'), | ||
| 1347 | + )); | ||
| 1348 | + }); | ||
| 1349 | + overlayState.insert(overlayEntryOpacity); | ||
| 1350 | + overlayState.insert(overlayEntryLoader); | ||
| 1351 | + | ||
| 1352 | + T data; | ||
| 1353 | + | ||
| 1354 | + try { | ||
| 1355 | + data = await asyncFunction(); | ||
| 1356 | + } on Exception catch (_) { | ||
| 1357 | + overlayEntryLoader.remove(); | ||
| 1358 | + overlayEntryOpacity.remove(); | ||
| 1359 | + rethrow; | ||
| 1360 | + } | ||
| 1361 | + | ||
| 1362 | + overlayEntryLoader.remove(); | ||
| 1363 | + overlayEntryOpacity.remove(); | ||
| 1364 | + return data; | ||
| 1365 | + } | ||
| 1366 | +} |
| @@ -10,6 +10,63 @@ import '../../get_navigation.dart'; | @@ -10,6 +10,63 @@ import '../../get_navigation.dart'; | ||
| 10 | import 'root_controller.dart'; | 10 | import 'root_controller.dart'; |
| 11 | 11 | ||
| 12 | class GetMaterialApp extends StatelessWidget { | 12 | class GetMaterialApp extends StatelessWidget { |
| 13 | + final GlobalKey<NavigatorState>? navigatorKey; | ||
| 14 | + | ||
| 15 | + final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey; | ||
| 16 | + final Widget? home; | ||
| 17 | + final Map<String, WidgetBuilder>? routes; | ||
| 18 | + final String? initialRoute; | ||
| 19 | + final RouteFactory? onGenerateRoute; | ||
| 20 | + final InitialRouteListFactory? onGenerateInitialRoutes; | ||
| 21 | + final RouteFactory? onUnknownRoute; | ||
| 22 | + final List<NavigatorObserver>? navigatorObservers; | ||
| 23 | + final TransitionBuilder? builder; | ||
| 24 | + final String title; | ||
| 25 | + final GenerateAppTitle? onGenerateTitle; | ||
| 26 | + final ThemeData? theme; | ||
| 27 | + final ThemeData? darkTheme; | ||
| 28 | + final ThemeMode themeMode; | ||
| 29 | + final CustomTransition? customTransition; | ||
| 30 | + final Color? color; | ||
| 31 | + final Map<String, Map<String, String>>? translationsKeys; | ||
| 32 | + final Translations? translations; | ||
| 33 | + final TextDirection? textDirection; | ||
| 34 | + final Locale? locale; | ||
| 35 | + final Locale? fallbackLocale; | ||
| 36 | + final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates; | ||
| 37 | + final LocaleListResolutionCallback? localeListResolutionCallback; | ||
| 38 | + final LocaleResolutionCallback? localeResolutionCallback; | ||
| 39 | + final Iterable<Locale> supportedLocales; | ||
| 40 | + final bool showPerformanceOverlay; | ||
| 41 | + final bool checkerboardRasterCacheImages; | ||
| 42 | + final bool checkerboardOffscreenLayers; | ||
| 43 | + final bool showSemanticsDebugger; | ||
| 44 | + final bool debugShowCheckedModeBanner; | ||
| 45 | + final Map<LogicalKeySet, Intent>? shortcuts; | ||
| 46 | + final ScrollBehavior? scrollBehavior; | ||
| 47 | + final ThemeData? highContrastTheme; | ||
| 48 | + final ThemeData? highContrastDarkTheme; | ||
| 49 | + final Map<Type, Action<Intent>>? actions; | ||
| 50 | + final bool debugShowMaterialGrid; | ||
| 51 | + final ValueChanged<Routing?>? routingCallback; | ||
| 52 | + final Transition? defaultTransition; | ||
| 53 | + final bool? opaqueRoute; | ||
| 54 | + final VoidCallback? onInit; | ||
| 55 | + final VoidCallback? onReady; | ||
| 56 | + final VoidCallback? onDispose; | ||
| 57 | + final bool? enableLog; | ||
| 58 | + final LogWriterCallback? logWriterCallback; | ||
| 59 | + final bool? popGesture; | ||
| 60 | + final SmartManagement smartManagement; | ||
| 61 | + final Bindings? initialBinding; | ||
| 62 | + final Duration? transitionDuration; | ||
| 63 | + final bool? defaultGlobalState; | ||
| 64 | + final List<GetPage>? getPages; | ||
| 65 | + final GetPage? unknownRoute; | ||
| 66 | + final RouteInformationProvider? routeInformationProvider; | ||
| 67 | + final RouteInformationParser<Object>? routeInformationParser; | ||
| 68 | + final RouterDelegate<Object>? routerDelegate; | ||
| 69 | + final BackButtonDispatcher? backButtonDispatcher; | ||
| 13 | const GetMaterialApp({ | 70 | const GetMaterialApp({ |
| 14 | Key? key, | 71 | Key? key, |
| 15 | this.navigatorKey, | 72 | this.navigatorKey, |
| @@ -72,63 +129,6 @@ class GetMaterialApp extends StatelessWidget { | @@ -72,63 +129,6 @@ class GetMaterialApp extends StatelessWidget { | ||
| 72 | backButtonDispatcher = null, | 129 | backButtonDispatcher = null, |
| 73 | super(key: key); | 130 | super(key: key); |
| 74 | 131 | ||
| 75 | - final GlobalKey<NavigatorState>? navigatorKey; | ||
| 76 | - final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey; | ||
| 77 | - final Widget? home; | ||
| 78 | - final Map<String, WidgetBuilder>? routes; | ||
| 79 | - final String? initialRoute; | ||
| 80 | - final RouteFactory? onGenerateRoute; | ||
| 81 | - final InitialRouteListFactory? onGenerateInitialRoutes; | ||
| 82 | - final RouteFactory? onUnknownRoute; | ||
| 83 | - final List<NavigatorObserver>? navigatorObservers; | ||
| 84 | - final TransitionBuilder? builder; | ||
| 85 | - final String title; | ||
| 86 | - final GenerateAppTitle? onGenerateTitle; | ||
| 87 | - final ThemeData? theme; | ||
| 88 | - final ThemeData? darkTheme; | ||
| 89 | - final ThemeMode themeMode; | ||
| 90 | - final CustomTransition? customTransition; | ||
| 91 | - final Color? color; | ||
| 92 | - final Map<String, Map<String, String>>? translationsKeys; | ||
| 93 | - final Translations? translations; | ||
| 94 | - final TextDirection? textDirection; | ||
| 95 | - final Locale? locale; | ||
| 96 | - final Locale? fallbackLocale; | ||
| 97 | - final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates; | ||
| 98 | - final LocaleListResolutionCallback? localeListResolutionCallback; | ||
| 99 | - final LocaleResolutionCallback? localeResolutionCallback; | ||
| 100 | - final Iterable<Locale> supportedLocales; | ||
| 101 | - final bool showPerformanceOverlay; | ||
| 102 | - final bool checkerboardRasterCacheImages; | ||
| 103 | - final bool checkerboardOffscreenLayers; | ||
| 104 | - final bool showSemanticsDebugger; | ||
| 105 | - final bool debugShowCheckedModeBanner; | ||
| 106 | - final Map<LogicalKeySet, Intent>? shortcuts; | ||
| 107 | - final ScrollBehavior? scrollBehavior; | ||
| 108 | - final ThemeData? highContrastTheme; | ||
| 109 | - final ThemeData? highContrastDarkTheme; | ||
| 110 | - final Map<Type, Action<Intent>>? actions; | ||
| 111 | - final bool debugShowMaterialGrid; | ||
| 112 | - final ValueChanged<Routing?>? routingCallback; | ||
| 113 | - final Transition? defaultTransition; | ||
| 114 | - final bool? opaqueRoute; | ||
| 115 | - final VoidCallback? onInit; | ||
| 116 | - final VoidCallback? onReady; | ||
| 117 | - final VoidCallback? onDispose; | ||
| 118 | - final bool? enableLog; | ||
| 119 | - final LogWriterCallback? logWriterCallback; | ||
| 120 | - final bool? popGesture; | ||
| 121 | - final SmartManagement smartManagement; | ||
| 122 | - final Bindings? initialBinding; | ||
| 123 | - final Duration? transitionDuration; | ||
| 124 | - final bool? defaultGlobalState; | ||
| 125 | - final List<GetPage>? getPages; | ||
| 126 | - final GetPage? unknownRoute; | ||
| 127 | - final RouteInformationProvider? routeInformationProvider; | ||
| 128 | - final RouteInformationParser<Object>? routeInformationParser; | ||
| 129 | - final RouterDelegate<Object>? routerDelegate; | ||
| 130 | - final BackButtonDispatcher? backButtonDispatcher; | ||
| 131 | - | ||
| 132 | GetMaterialApp.router({ | 132 | GetMaterialApp.router({ |
| 133 | Key? key, | 133 | Key? key, |
| 134 | this.routeInformationProvider, | 134 | this.routeInformationProvider, |
| @@ -200,31 +200,6 @@ class GetMaterialApp extends StatelessWidget { | @@ -200,31 +200,6 @@ class GetMaterialApp extends StatelessWidget { | ||
| 200 | Get.routeInformationParser = routeInformationParser; | 200 | Get.routeInformationParser = routeInformationParser; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | - Route<dynamic> generator(RouteSettings settings) { | ||
| 204 | - return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | ||
| 205 | - } | ||
| 206 | - | ||
| 207 | - List<Route<dynamic>> initialRoutesGenerate(String name) { | ||
| 208 | - return [ | ||
| 209 | - PageRedirect( | ||
| 210 | - settings: RouteSettings(name: name), | ||
| 211 | - unknownRoute: unknownRoute, | ||
| 212 | - ).page() | ||
| 213 | - ]; | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - Widget defaultBuilder(BuildContext context, Widget? child) { | ||
| 217 | - return Directionality( | ||
| 218 | - textDirection: textDirection ?? | ||
| 219 | - (rtlLanguages.contains(Get.locale?.languageCode) | ||
| 220 | - ? TextDirection.rtl | ||
| 221 | - : TextDirection.ltr), | ||
| 222 | - child: builder == null | ||
| 223 | - ? (child ?? Material()) | ||
| 224 | - : builder!(context, child ?? Material()), | ||
| 225 | - ); | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | @override | 203 | @override |
| 229 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 204 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
| 230 | init: Get.rootController, | 205 | init: Get.rootController, |
| @@ -270,7 +245,6 @@ class GetMaterialApp extends StatelessWidget { | @@ -270,7 +245,6 @@ class GetMaterialApp extends StatelessWidget { | ||
| 270 | ? MaterialApp.router( | 245 | ? MaterialApp.router( |
| 271 | routerDelegate: routerDelegate!, | 246 | routerDelegate: routerDelegate!, |
| 272 | routeInformationParser: routeInformationParser!, | 247 | routeInformationParser: routeInformationParser!, |
| 273 | - scaffoldMessengerKey: scaffoldMessengerKey, | ||
| 274 | backButtonDispatcher: backButtonDispatcher, | 248 | backButtonDispatcher: backButtonDispatcher, |
| 275 | routeInformationProvider: routeInformationProvider, | 249 | routeInformationProvider: routeInformationProvider, |
| 276 | key: _.unikey, | 250 | key: _.unikey, |
| @@ -283,6 +257,8 @@ class GetMaterialApp extends StatelessWidget { | @@ -283,6 +257,8 @@ class GetMaterialApp extends StatelessWidget { | ||
| 283 | _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), | 257 | _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), |
| 284 | themeMode: _.themeMode ?? themeMode, | 258 | themeMode: _.themeMode ?? themeMode, |
| 285 | locale: Get.locale ?? locale, | 259 | locale: Get.locale ?? locale, |
| 260 | + scaffoldMessengerKey: | ||
| 261 | + scaffoldMessengerKey ?? _.scaffoldMessengerKey, | ||
| 286 | localizationsDelegates: localizationsDelegates, | 262 | localizationsDelegates: localizationsDelegates, |
| 287 | localeListResolutionCallback: localeListResolutionCallback, | 263 | localeListResolutionCallback: localeListResolutionCallback, |
| 288 | localeResolutionCallback: localeResolutionCallback, | 264 | localeResolutionCallback: localeResolutionCallback, |
| @@ -301,7 +277,8 @@ class GetMaterialApp extends StatelessWidget { | @@ -301,7 +277,8 @@ class GetMaterialApp extends StatelessWidget { | ||
| 301 | navigatorKey: (navigatorKey == null | 277 | navigatorKey: (navigatorKey == null |
| 302 | ? Get.key | 278 | ? Get.key |
| 303 | : Get.addKey(navigatorKey!)), | 279 | : Get.addKey(navigatorKey!)), |
| 304 | - scaffoldMessengerKey: scaffoldMessengerKey, | 280 | + scaffoldMessengerKey: |
| 281 | + scaffoldMessengerKey ?? _.scaffoldMessengerKey, | ||
| 305 | home: home, | 282 | home: home, |
| 306 | routes: routes ?? const <String, WidgetBuilder>{}, | 283 | routes: routes ?? const <String, WidgetBuilder>{}, |
| 307 | initialRoute: initialRoute, | 284 | initialRoute: initialRoute, |
| @@ -343,4 +320,29 @@ class GetMaterialApp extends StatelessWidget { | @@ -343,4 +320,29 @@ class GetMaterialApp extends StatelessWidget { | ||
| 343 | // actions: actions, | 320 | // actions: actions, |
| 344 | ), | 321 | ), |
| 345 | ); | 322 | ); |
| 323 | + | ||
| 324 | + Widget defaultBuilder(BuildContext context, Widget? child) { | ||
| 325 | + return Directionality( | ||
| 326 | + textDirection: textDirection ?? | ||
| 327 | + (rtlLanguages.contains(Get.locale?.languageCode) | ||
| 328 | + ? TextDirection.rtl | ||
| 329 | + : TextDirection.ltr), | ||
| 330 | + child: builder == null | ||
| 331 | + ? (child ?? Material()) | ||
| 332 | + : builder!(context, child ?? Material()), | ||
| 333 | + ); | ||
| 334 | + } | ||
| 335 | + | ||
| 336 | + Route<dynamic> generator(RouteSettings settings) { | ||
| 337 | + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | ||
| 338 | + } | ||
| 339 | + | ||
| 340 | + List<Route<dynamic>> initialRoutesGenerate(String name) { | ||
| 341 | + return [ | ||
| 342 | + PageRedirect( | ||
| 343 | + settings: RouteSettings(name: name), | ||
| 344 | + unknownRoute: unknownRoute, | ||
| 345 | + ).page() | ||
| 346 | + ]; | ||
| 347 | + } | ||
| 346 | } | 348 | } |
| 1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 2 | + | ||
| 2 | import '../../../get_state_manager/get_state_manager.dart'; | 3 | import '../../../get_state_manager/get_state_manager.dart'; |
| 3 | import '../../../get_utils/get_utils.dart'; | 4 | import '../../../get_utils/get_utils.dart'; |
| 4 | import '../routes/custom_transition.dart'; | 5 | import '../routes/custom_transition.dart'; |
| @@ -12,6 +13,8 @@ class GetMaterialController extends GetxController { | @@ -12,6 +13,8 @@ class GetMaterialController extends GetxController { | ||
| 12 | ThemeData? darkTheme; | 13 | ThemeData? darkTheme; |
| 13 | ThemeMode? themeMode; | 14 | ThemeMode? themeMode; |
| 14 | 15 | ||
| 16 | + final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>(); | ||
| 17 | + | ||
| 15 | bool defaultPopGesture = GetPlatform.isIOS; | 18 | bool defaultPopGesture = GetPlatform.isIOS; |
| 16 | bool defaultOpaqueRoute = true; | 19 | bool defaultOpaqueRoute = true; |
| 17 | 20 | ||
| @@ -31,6 +34,8 @@ class GetMaterialController extends GetxController { | @@ -31,6 +34,8 @@ class GetMaterialController extends GetxController { | ||
| 31 | 34 | ||
| 32 | var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default'); | 35 | var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default'); |
| 33 | 36 | ||
| 37 | + Map<dynamic, GlobalKey<NavigatorState>> keys = {}; | ||
| 38 | + | ||
| 34 | GlobalKey<NavigatorState> get key => _key; | 39 | GlobalKey<NavigatorState> get key => _key; |
| 35 | 40 | ||
| 36 | GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { | 41 | GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { |
| @@ -38,7 +43,10 @@ class GetMaterialController extends GetxController { | @@ -38,7 +43,10 @@ class GetMaterialController extends GetxController { | ||
| 38 | return key; | 43 | return key; |
| 39 | } | 44 | } |
| 40 | 45 | ||
| 41 | - Map<dynamic, GlobalKey<NavigatorState>> keys = {}; | 46 | + void restartApp() { |
| 47 | + unikey = UniqueKey(); | ||
| 48 | + update(); | ||
| 49 | + } | ||
| 42 | 50 | ||
| 43 | void setTheme(ThemeData value) { | 51 | void setTheme(ThemeData value) { |
| 44 | if (darkTheme == null) { | 52 | if (darkTheme == null) { |
| @@ -57,9 +65,4 @@ class GetMaterialController extends GetxController { | @@ -57,9 +65,4 @@ class GetMaterialController extends GetxController { | ||
| 57 | themeMode = value; | 65 | themeMode = value; |
| 58 | update(); | 66 | update(); |
| 59 | } | 67 | } |
| 60 | - | ||
| 61 | - void restartApp() { | ||
| 62 | - unikey = UniqueKey(); | ||
| 63 | - update(); | ||
| 64 | - } | ||
| 65 | } | 68 | } |
| @@ -5,37 +5,8 @@ import '../../../../instance_manager.dart'; | @@ -5,37 +5,8 @@ import '../../../../instance_manager.dart'; | ||
| 5 | import '../../../get_navigation.dart'; | 5 | import '../../../get_navigation.dart'; |
| 6 | import '../../dialog/dialog_route.dart'; | 6 | import '../../dialog/dialog_route.dart'; |
| 7 | import '../../router_report.dart'; | 7 | import '../../router_report.dart'; |
| 8 | -import '../../snackbar/snack_route.dart'; | ||
| 9 | import '../default_route.dart'; | 8 | import '../default_route.dart'; |
| 10 | 9 | ||
| 11 | -class Routing { | ||
| 12 | - String current; | ||
| 13 | - String previous; | ||
| 14 | - dynamic args; | ||
| 15 | - String removed; | ||
| 16 | - Route<dynamic>? route; | ||
| 17 | - bool? isBack; | ||
| 18 | - bool? isSnackbar; | ||
| 19 | - bool? isBottomSheet; | ||
| 20 | - bool? isDialog; | ||
| 21 | - | ||
| 22 | - Routing({ | ||
| 23 | - this.current = '', | ||
| 24 | - this.previous = '', | ||
| 25 | - this.args, | ||
| 26 | - this.removed = '', | ||
| 27 | - this.route, | ||
| 28 | - this.isBack, | ||
| 29 | - this.isSnackbar, | ||
| 30 | - this.isBottomSheet, | ||
| 31 | - this.isDialog, | ||
| 32 | - }); | ||
| 33 | - | ||
| 34 | - void update(void fn(Routing value)) { | ||
| 35 | - fn(this); | ||
| 36 | - } | ||
| 37 | -} | ||
| 38 | - | ||
| 39 | /// Extracts the name of a route based on it's instance type | 10 | /// Extracts the name of a route based on it's instance type |
| 40 | /// or null if not possible. | 11 | /// or null if not possible. |
| 41 | String? _extractRouteName(Route? route) { | 12 | String? _extractRouteName(Route? route) { |
| @@ -58,49 +29,70 @@ String? _extractRouteName(Route? route) { | @@ -58,49 +29,70 @@ String? _extractRouteName(Route? route) { | ||
| 58 | return null; | 29 | return null; |
| 59 | } | 30 | } |
| 60 | 31 | ||
| 61 | -/// This is basically a util for rules about 'what a route is' | ||
| 62 | -class _RouteData { | ||
| 63 | - final bool isGetPageRoute; | ||
| 64 | - final bool isSnackbar; | ||
| 65 | - final bool isBottomSheet; | ||
| 66 | - final bool isDialog; | ||
| 67 | - final String? name; | ||
| 68 | - | ||
| 69 | - _RouteData({ | ||
| 70 | - required this.name, | ||
| 71 | - required this.isGetPageRoute, | ||
| 72 | - required this.isSnackbar, | ||
| 73 | - required this.isBottomSheet, | ||
| 74 | - required this.isDialog, | ||
| 75 | - }); | ||
| 76 | - | ||
| 77 | - factory _RouteData.ofRoute(Route? route) { | ||
| 78 | - return _RouteData( | ||
| 79 | - name: _extractRouteName(route), | ||
| 80 | - isGetPageRoute: route is GetPageRoute, | ||
| 81 | - isSnackbar: route is SnackRoute, | ||
| 82 | - isDialog: route is GetDialogRoute, | ||
| 83 | - isBottomSheet: route is GetModalBottomSheetRoute, | ||
| 84 | - ); | ||
| 85 | - } | ||
| 86 | -} | ||
| 87 | - | ||
| 88 | class GetObserver extends NavigatorObserver { | 32 | class GetObserver extends NavigatorObserver { |
| 89 | final Function(Routing?)? routing; | 33 | final Function(Routing?)? routing; |
| 90 | 34 | ||
| 35 | + final Routing? _routeSend; | ||
| 36 | + | ||
| 91 | GetObserver([this.routing, this._routeSend]); | 37 | GetObserver([this.routing, this._routeSend]); |
| 92 | 38 | ||
| 93 | - final Routing? _routeSend; | 39 | + @override |
| 40 | + void didPop(Route route, Route? previousRoute) { | ||
| 41 | + super.didPop(route, previousRoute); | ||
| 42 | + final currentRoute = _RouteData.ofRoute(route); | ||
| 43 | + final newRoute = _RouteData.ofRoute(previousRoute); | ||
| 44 | + | ||
| 45 | + // if (currentRoute.isSnackbar) { | ||
| 46 | + // // Get.log("CLOSE SNACKBAR ${currentRoute.name}"); | ||
| 47 | + // Get.log("CLOSE SNACKBAR"); | ||
| 48 | + // } else | ||
| 49 | + | ||
| 50 | + if (currentRoute.isBottomSheet || currentRoute.isDialog) { | ||
| 51 | + Get.log("CLOSE ${currentRoute.name}"); | ||
| 52 | + } else if (currentRoute.isGetPageRoute) { | ||
| 53 | + Get.log("CLOSE TO ROUTE ${currentRoute.name}"); | ||
| 54 | + } | ||
| 55 | + if (previousRoute != null) { | ||
| 56 | + RouterReportManager.reportCurrentRoute(previousRoute); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + // Here we use a 'inverse didPush set', meaning that we use | ||
| 60 | + // previous route instead of 'route' because this is | ||
| 61 | + // a 'inverse push' | ||
| 62 | + _routeSend?.update((value) { | ||
| 63 | + // Only PageRoute is allowed to change current value | ||
| 64 | + if (previousRoute is PageRoute) { | ||
| 65 | + value.current = _extractRouteName(previousRoute) ?? ''; | ||
| 66 | + value.previous = newRoute.name ?? ''; | ||
| 67 | + } else if (value.previous.isNotEmpty) { | ||
| 68 | + value.current = value.previous; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + value.args = previousRoute?.settings.arguments; | ||
| 72 | + value.route = previousRoute; | ||
| 73 | + value.isBack = true; | ||
| 74 | + value.removed = ''; | ||
| 75 | + // value.isSnackbar = newRoute.isSnackbar; | ||
| 76 | + value.isBottomSheet = newRoute.isBottomSheet; | ||
| 77 | + value.isDialog = newRoute.isDialog; | ||
| 78 | + }); | ||
| 79 | + | ||
| 80 | + // print('currentRoute.isDialog ${currentRoute.isDialog}'); | ||
| 81 | + | ||
| 82 | + routing?.call(_routeSend); | ||
| 83 | + } | ||
| 94 | 84 | ||
| 95 | @override | 85 | @override |
| 96 | void didPush(Route route, Route? previousRoute) { | 86 | void didPush(Route route, Route? previousRoute) { |
| 97 | super.didPush(route, previousRoute); | 87 | super.didPush(route, previousRoute); |
| 98 | final newRoute = _RouteData.ofRoute(route); | 88 | final newRoute = _RouteData.ofRoute(route); |
| 99 | 89 | ||
| 100 | - if (newRoute.isSnackbar) { | ||
| 101 | - // Get.log("OPEN SNACKBAR ${newRoute.name}"); | ||
| 102 | - Get.log("OPEN SNACKBAR"); | ||
| 103 | - } else if (newRoute.isBottomSheet || newRoute.isDialog) { | 90 | + // if (newRoute.isSnackbar) { |
| 91 | + // // Get.log("OPEN SNACKBAR ${newRoute.name}"); | ||
| 92 | + // Get.log("OPEN SNACKBAR"); | ||
| 93 | + // } else | ||
| 94 | + | ||
| 95 | + if (newRoute.isBottomSheet || newRoute.isDialog) { | ||
| 104 | Get.log("OPEN ${newRoute.name}"); | 96 | Get.log("OPEN ${newRoute.name}"); |
| 105 | } else if (newRoute.isGetPageRoute) { | 97 | } else if (newRoute.isGetPageRoute) { |
| 106 | Get.log("GOING TO ROUTE ${newRoute.name}"); | 98 | Get.log("GOING TO ROUTE ${newRoute.name}"); |
| @@ -121,7 +113,7 @@ class GetObserver extends NavigatorObserver { | @@ -121,7 +113,7 @@ class GetObserver extends NavigatorObserver { | ||
| 121 | value.route = route; | 113 | value.route = route; |
| 122 | value.isBack = false; | 114 | value.isBack = false; |
| 123 | value.removed = ''; | 115 | value.removed = ''; |
| 124 | - value.isSnackbar = newRoute.isSnackbar ? true : value.isSnackbar ?? false; | 116 | + // value.isSnackbar = newRoute.isSnackbar ? true : value.isSnackbar ?? false; |
| 125 | value.isBottomSheet = | 117 | value.isBottomSheet = |
| 126 | newRoute.isBottomSheet ? true : value.isBottomSheet ?? false; | 118 | newRoute.isBottomSheet ? true : value.isBottomSheet ?? false; |
| 127 | value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false; | 119 | value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false; |
| @@ -133,46 +125,27 @@ class GetObserver extends NavigatorObserver { | @@ -133,46 +125,27 @@ class GetObserver extends NavigatorObserver { | ||
| 133 | } | 125 | } |
| 134 | 126 | ||
| 135 | @override | 127 | @override |
| 136 | - void didPop(Route route, Route? previousRoute) { | ||
| 137 | - super.didPop(route, previousRoute); | 128 | + void didRemove(Route route, Route? previousRoute) { |
| 129 | + super.didRemove(route, previousRoute); | ||
| 130 | + final routeName = _extractRouteName(route); | ||
| 138 | final currentRoute = _RouteData.ofRoute(route); | 131 | final currentRoute = _RouteData.ofRoute(route); |
| 139 | - final newRoute = _RouteData.ofRoute(previousRoute); | ||
| 140 | 132 | ||
| 141 | - if (currentRoute.isSnackbar) { | ||
| 142 | - // Get.log("CLOSE SNACKBAR ${currentRoute.name}"); | ||
| 143 | - Get.log("CLOSE SNACKBAR"); | ||
| 144 | - } else if (currentRoute.isBottomSheet || currentRoute.isDialog) { | ||
| 145 | - Get.log("CLOSE ${currentRoute.name}"); | ||
| 146 | - } else if (currentRoute.isGetPageRoute) { | ||
| 147 | - Get.log("CLOSE TO ROUTE ${currentRoute.name}"); | ||
| 148 | - } | ||
| 149 | - if (previousRoute != null) { | ||
| 150 | - RouterReportManager.reportCurrentRoute(previousRoute); | ||
| 151 | - } | 133 | + Get.log("REMOVING ROUTE $routeName"); |
| 152 | 134 | ||
| 153 | - // Here we use a 'inverse didPush set', meaning that we use | ||
| 154 | - // previous route instead of 'route' because this is | ||
| 155 | - // a 'inverse push' | ||
| 156 | _routeSend?.update((value) { | 135 | _routeSend?.update((value) { |
| 157 | - // Only PageRoute is allowed to change current value | ||
| 158 | - if (previousRoute is PageRoute) { | ||
| 159 | - value.current = _extractRouteName(previousRoute) ?? ''; | ||
| 160 | - value.previous = newRoute.name ?? ''; | ||
| 161 | - } else if (value.previous.isNotEmpty) { | ||
| 162 | - value.current = value.previous; | ||
| 163 | - } | ||
| 164 | - | ||
| 165 | - value.args = previousRoute?.settings.arguments; | ||
| 166 | value.route = previousRoute; | 136 | value.route = previousRoute; |
| 167 | - value.isBack = true; | ||
| 168 | - value.removed = ''; | ||
| 169 | - value.isSnackbar = newRoute.isSnackbar; | ||
| 170 | - value.isBottomSheet = newRoute.isBottomSheet; | ||
| 171 | - value.isDialog = newRoute.isDialog; | 137 | + value.isBack = false; |
| 138 | + value.removed = routeName ?? ''; | ||
| 139 | + value.previous = routeName ?? ''; | ||
| 140 | + // value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar; | ||
| 141 | + value.isBottomSheet = | ||
| 142 | + currentRoute.isBottomSheet ? false : value.isBottomSheet; | ||
| 143 | + value.isDialog = currentRoute.isDialog ? false : value.isDialog; | ||
| 172 | }); | 144 | }); |
| 173 | 145 | ||
| 174 | - // print('currentRoute.isDialog ${currentRoute.isDialog}'); | ||
| 175 | - | 146 | + if (route is GetPageRoute) { |
| 147 | + RouterReportManager.reportRouteWillDispose(route); | ||
| 148 | + } | ||
| 176 | routing?.call(_routeSend); | 149 | routing?.call(_routeSend); |
| 177 | } | 150 | } |
| 178 | 151 | ||
| @@ -201,7 +174,7 @@ class GetObserver extends NavigatorObserver { | @@ -201,7 +174,7 @@ class GetObserver extends NavigatorObserver { | ||
| 201 | value.isBack = false; | 174 | value.isBack = false; |
| 202 | value.removed = ''; | 175 | value.removed = ''; |
| 203 | value.previous = '$oldName'; | 176 | value.previous = '$oldName'; |
| 204 | - value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar; | 177 | + // value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar; |
| 205 | value.isBottomSheet = | 178 | value.isBottomSheet = |
| 206 | currentRoute.isBottomSheet ? false : value.isBottomSheet; | 179 | currentRoute.isBottomSheet ? false : value.isBottomSheet; |
| 207 | value.isDialog = currentRoute.isDialog ? false : value.isDialog; | 180 | value.isDialog = currentRoute.isDialog ? false : value.isDialog; |
| @@ -212,29 +185,59 @@ class GetObserver extends NavigatorObserver { | @@ -212,29 +185,59 @@ class GetObserver extends NavigatorObserver { | ||
| 212 | 185 | ||
| 213 | routing?.call(_routeSend); | 186 | routing?.call(_routeSend); |
| 214 | } | 187 | } |
| 188 | +} | ||
| 215 | 189 | ||
| 216 | - @override | ||
| 217 | - void didRemove(Route route, Route? previousRoute) { | ||
| 218 | - super.didRemove(route, previousRoute); | ||
| 219 | - final routeName = _extractRouteName(route); | ||
| 220 | - final currentRoute = _RouteData.ofRoute(route); | 190 | +class Routing { |
| 191 | + String current; | ||
| 192 | + String previous; | ||
| 193 | + dynamic args; | ||
| 194 | + String removed; | ||
| 195 | + Route<dynamic>? route; | ||
| 196 | + bool? isBack; | ||
| 197 | + // bool? isSnackbar; | ||
| 198 | + bool? isBottomSheet; | ||
| 199 | + bool? isDialog; | ||
| 221 | 200 | ||
| 222 | - Get.log("REMOVING ROUTE $routeName"); | 201 | + Routing({ |
| 202 | + this.current = '', | ||
| 203 | + this.previous = '', | ||
| 204 | + this.args, | ||
| 205 | + this.removed = '', | ||
| 206 | + this.route, | ||
| 207 | + this.isBack, | ||
| 208 | + // this.isSnackbar, | ||
| 209 | + this.isBottomSheet, | ||
| 210 | + this.isDialog, | ||
| 211 | + }); | ||
| 223 | 212 | ||
| 224 | - _routeSend?.update((value) { | ||
| 225 | - value.route = previousRoute; | ||
| 226 | - value.isBack = false; | ||
| 227 | - value.removed = routeName ?? ''; | ||
| 228 | - value.previous = routeName ?? ''; | ||
| 229 | - value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar; | ||
| 230 | - value.isBottomSheet = | ||
| 231 | - currentRoute.isBottomSheet ? false : value.isBottomSheet; | ||
| 232 | - value.isDialog = currentRoute.isDialog ? false : value.isDialog; | ||
| 233 | - }); | 213 | + void update(void fn(Routing value)) { |
| 214 | + fn(this); | ||
| 215 | + } | ||
| 216 | +} | ||
| 234 | 217 | ||
| 235 | - if (route is GetPageRoute) { | ||
| 236 | - RouterReportManager.reportRouteWillDispose(route); | ||
| 237 | - } | ||
| 238 | - routing?.call(_routeSend); | 218 | +/// This is basically a util for rules about 'what a route is' |
| 219 | +class _RouteData { | ||
| 220 | + final bool isGetPageRoute; | ||
| 221 | + //final bool isSnackbar; | ||
| 222 | + final bool isBottomSheet; | ||
| 223 | + final bool isDialog; | ||
| 224 | + final String? name; | ||
| 225 | + | ||
| 226 | + _RouteData({ | ||
| 227 | + required this.name, | ||
| 228 | + required this.isGetPageRoute, | ||
| 229 | + // required this.isSnackbar, | ||
| 230 | + required this.isBottomSheet, | ||
| 231 | + required this.isDialog, | ||
| 232 | + }); | ||
| 233 | + | ||
| 234 | + factory _RouteData.ofRoute(Route? route) { | ||
| 235 | + return _RouteData( | ||
| 236 | + name: _extractRouteName(route), | ||
| 237 | + isGetPageRoute: route is GetPageRoute, | ||
| 238 | + // isSnackbar: route is SnackRoute, | ||
| 239 | + isDialog: route is GetDialogRoute, | ||
| 240 | + isBottomSheet: route is GetModalBottomSheetRoute, | ||
| 241 | + ); | ||
| 239 | } | 242 | } |
| 240 | } | 243 | } |
| 1 | import 'dart:async'; | 1 | import 'dart:async'; |
| 2 | import 'dart:ui'; | 2 | import 'dart:ui'; |
| 3 | + | ||
| 3 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
| 4 | import 'package:flutter/scheduler.dart'; | 5 | import 'package:flutter/scheduler.dart'; |
| 6 | + | ||
| 5 | import '../../../get_core/get_core.dart'; | 7 | import '../../../get_core/get_core.dart'; |
| 6 | import '../../get_navigation.dart'; | 8 | import '../../get_navigation.dart'; |
| 7 | 9 | ||
| 10 | +typedef OnTap = void Function(GetSnackBar snack); | ||
| 8 | typedef SnackbarStatusCallback = void Function(SnackbarStatus? status); | 11 | typedef SnackbarStatusCallback = void Function(SnackbarStatus? status); |
| 9 | -typedef OnTap = void Function(GetBar snack); | ||
| 10 | - | ||
| 11 | -class GetBar<T extends Object> extends StatefulWidget { | ||
| 12 | - GetBar({ | ||
| 13 | - Key? key, | ||
| 14 | - this.title, | ||
| 15 | - this.message, | ||
| 16 | - this.titleText, | ||
| 17 | - this.messageText, | ||
| 18 | - this.icon, | ||
| 19 | - this.shouldIconPulse = true, | ||
| 20 | - this.maxWidth, | ||
| 21 | - this.margin = const EdgeInsets.all(0.0), | ||
| 22 | - this.padding = const EdgeInsets.all(16), | ||
| 23 | - this.borderRadius = 0.0, | ||
| 24 | - this.borderColor, | ||
| 25 | - this.borderWidth = 1.0, | ||
| 26 | - this.backgroundColor = const Color(0xFF303030), | ||
| 27 | - this.leftBarIndicatorColor, | ||
| 28 | - this.boxShadows, | ||
| 29 | - this.backgroundGradient, | ||
| 30 | - this.mainButton, | ||
| 31 | - this.onTap, | ||
| 32 | - this.duration, | ||
| 33 | - this.isDismissible = true, | ||
| 34 | - this.dismissDirection = SnackDismissDirection.VERTICAL, | ||
| 35 | - this.showProgressIndicator = false, | ||
| 36 | - this.progressIndicatorController, | ||
| 37 | - this.progressIndicatorBackgroundColor, | ||
| 38 | - this.progressIndicatorValueColor, | ||
| 39 | - this.snackPosition = SnackPosition.BOTTOM, | ||
| 40 | - this.snackStyle = SnackStyle.FLOATING, | ||
| 41 | - this.forwardAnimationCurve = Curves.easeOutCirc, | ||
| 42 | - this.reverseAnimationCurve = Curves.easeOutCirc, | ||
| 43 | - this.animationDuration = const Duration(seconds: 1), | ||
| 44 | - this.barBlur = 0.0, | ||
| 45 | - this.overlayBlur = 0.0, | ||
| 46 | - this.overlayColor = Colors.transparent, | ||
| 47 | - this.userInputForm, | ||
| 48 | - SnackbarStatusCallback? snackbarStatus, | ||
| 49 | - }) : snackbarStatus = (snackbarStatus ?? (status) {}), | ||
| 50 | - super(key: key); | ||
| 51 | 12 | ||
| 13 | +class GetSnackBar extends StatefulWidget { | ||
| 52 | /// A callback for you to listen to the different Snack status | 14 | /// A callback for you to listen to the different Snack status |
| 53 | - final SnackbarStatusCallback snackbarStatus; | 15 | + final SnackbarStatusCallback? snackbarStatus; |
| 54 | 16 | ||
| 55 | /// The title displayed to the user | 17 | /// The title displayed to the user |
| 56 | final String? title; | 18 | final String? title; |
| 57 | 19 | ||
| 20 | + final DismissDirection? dismissDirection; | ||
| 21 | + | ||
| 58 | /// The message displayed to the user. | 22 | /// The message displayed to the user. |
| 59 | final String? message; | 23 | final String? message; |
| 60 | 24 | ||
| @@ -150,11 +114,6 @@ class GetBar<T extends Object> extends StatefulWidget { | @@ -150,11 +114,6 @@ class GetBar<T extends Object> extends StatefulWidget { | ||
| 150 | /// [SnackPosition.BOTTOM] is the default. | 114 | /// [SnackPosition.BOTTOM] is the default. |
| 151 | final SnackPosition snackPosition; | 115 | final SnackPosition snackPosition; |
| 152 | 116 | ||
| 153 | - /// [SnackDismissDirection.VERTICAL] by default. | ||
| 154 | - /// Can also be [SnackDismissDirection.HORIZONTAL] in which case both left | ||
| 155 | - /// and right dismiss are allowed. | ||
| 156 | - final SnackDismissDirection dismissDirection; | ||
| 157 | - | ||
| 158 | /// Snack can be floating or be grounded to the edge of the screen. | 117 | /// Snack can be floating or be grounded to the edge of the screen. |
| 159 | /// If grounded, I do not recommend using [margin] or [borderRadius]. | 118 | /// If grounded, I do not recommend using [margin] or [borderRadius]. |
| 160 | /// [SnackStyle.FLOATING] is the default | 119 | /// [SnackStyle.FLOATING] is the default |
| @@ -192,22 +151,73 @@ class GetBar<T extends Object> extends StatefulWidget { | @@ -192,22 +151,73 @@ class GetBar<T extends Object> extends StatefulWidget { | ||
| 192 | /// Every other widget is ignored if this is not null. | 151 | /// Every other widget is ignored if this is not null. |
| 193 | final Form? userInputForm; | 152 | final Form? userInputForm; |
| 194 | 153 | ||
| 154 | + const GetSnackBar({ | ||
| 155 | + Key? key, | ||
| 156 | + this.title, | ||
| 157 | + this.message, | ||
| 158 | + this.titleText, | ||
| 159 | + this.messageText, | ||
| 160 | + this.icon, | ||
| 161 | + this.shouldIconPulse = true, | ||
| 162 | + this.maxWidth, | ||
| 163 | + this.margin = const EdgeInsets.all(0.0), | ||
| 164 | + this.padding = const EdgeInsets.all(16), | ||
| 165 | + this.borderRadius = 0.0, | ||
| 166 | + this.borderColor, | ||
| 167 | + this.borderWidth = 1.0, | ||
| 168 | + this.backgroundColor = const Color(0xFF303030), | ||
| 169 | + this.leftBarIndicatorColor, | ||
| 170 | + this.boxShadows, | ||
| 171 | + this.backgroundGradient, | ||
| 172 | + this.mainButton, | ||
| 173 | + this.onTap, | ||
| 174 | + this.duration, | ||
| 175 | + this.isDismissible = true, | ||
| 176 | + this.dismissDirection, | ||
| 177 | + this.showProgressIndicator = false, | ||
| 178 | + this.progressIndicatorController, | ||
| 179 | + this.progressIndicatorBackgroundColor, | ||
| 180 | + this.progressIndicatorValueColor, | ||
| 181 | + this.snackPosition = SnackPosition.BOTTOM, | ||
| 182 | + this.snackStyle = SnackStyle.FLOATING, | ||
| 183 | + this.forwardAnimationCurve = Curves.easeOutCirc, | ||
| 184 | + this.reverseAnimationCurve = Curves.easeOutCirc, | ||
| 185 | + this.animationDuration = const Duration(seconds: 1), | ||
| 186 | + this.barBlur = 0.0, | ||
| 187 | + this.overlayBlur = 0.0, | ||
| 188 | + this.overlayColor = Colors.transparent, | ||
| 189 | + this.userInputForm, | ||
| 190 | + this.snackbarStatus, | ||
| 191 | + }) : super(key: key); | ||
| 192 | + | ||
| 193 | + @override | ||
| 194 | + State createState() => _GetSnackBarState(); | ||
| 195 | + | ||
| 195 | /// Show the snack. It's call [SnackbarStatus.OPENING] state | 196 | /// Show the snack. It's call [SnackbarStatus.OPENING] state |
| 196 | /// followed by [SnackbarStatus.OPEN] | 197 | /// followed by [SnackbarStatus.OPEN] |
| 197 | - Future<T?>? show<T>() async { | 198 | + SnackbarController show() { |
| 198 | return Get.showSnackbar(this); | 199 | return Get.showSnackbar(this); |
| 199 | } | 200 | } |
| 200 | - | ||
| 201 | - @override | ||
| 202 | - State createState() { | ||
| 203 | - return _GetBarState<T>(); | ||
| 204 | - } | ||
| 205 | } | 201 | } |
| 206 | 202 | ||
| 207 | -class _GetBarState<K extends Object> extends State<GetBar> | ||
| 208 | - with TickerProviderStateMixin { | ||
| 209 | - SnackbarStatus? currentStatus; | 203 | +/// Indicates Status of snackbar |
| 204 | +/// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar | ||
| 205 | +/// has closed, | ||
| 206 | +/// [SnackbarStatus.OPENING] Starts with the opening animation and ends | ||
| 207 | +/// with the full | ||
| 208 | +/// snackbar display, [SnackbarStatus.CLOSING] Starts with the closing animation | ||
| 209 | +/// and ends | ||
| 210 | +/// with the full snackbar dispose | ||
| 211 | +enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING } | ||
| 212 | + | ||
| 213 | +/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM] | ||
| 214 | +enum SnackPosition { TOP, BOTTOM } | ||
| 210 | 215 | ||
| 216 | +/// Indicates if snack will be attached to the edge of the screen or not | ||
| 217 | +enum SnackStyle { FLOATING, GROUNDED } | ||
| 218 | + | ||
| 219 | +class _GetSnackBarState extends State<GetSnackBar> | ||
| 220 | + with TickerProviderStateMixin { | ||
| 211 | AnimationController? _fadeController; | 221 | AnimationController? _fadeController; |
| 212 | late Animation<double> _fadeAnimation; | 222 | late Animation<double> _fadeAnimation; |
| 213 | 223 | ||
| @@ -223,6 +233,49 @@ class _GetBarState<K extends Object> extends State<GetBar> | @@ -223,6 +233,49 @@ class _GetBarState<K extends Object> extends State<GetBar> | ||
| 223 | FocusScopeNode? _focusNode; | 233 | FocusScopeNode? _focusNode; |
| 224 | late FocusAttachment _focusAttachment; | 234 | late FocusAttachment _focusAttachment; |
| 225 | 235 | ||
| 236 | + final Completer<Size> _boxHeightCompleter = Completer<Size>(); | ||
| 237 | + | ||
| 238 | + late VoidCallback _progressListener; | ||
| 239 | + | ||
| 240 | + late CurvedAnimation _progressAnimation; | ||
| 241 | + | ||
| 242 | + final _backgroundBoxKey = GlobalKey(); | ||
| 243 | + | ||
| 244 | + @override | ||
| 245 | + Widget build(BuildContext context) { | ||
| 246 | + return Align( | ||
| 247 | + heightFactor: 1.0, | ||
| 248 | + child: Material( | ||
| 249 | + color: widget.snackStyle == SnackStyle.FLOATING | ||
| 250 | + ? Colors.transparent | ||
| 251 | + : widget.backgroundColor, | ||
| 252 | + child: SafeArea( | ||
| 253 | + minimum: widget.snackPosition == SnackPosition.BOTTOM | ||
| 254 | + ? EdgeInsets.only( | ||
| 255 | + bottom: MediaQuery.of(context).viewInsets.bottom) | ||
| 256 | + : EdgeInsets.only(top: MediaQuery.of(context).padding.top), | ||
| 257 | + bottom: widget.snackPosition == SnackPosition.BOTTOM, | ||
| 258 | + top: widget.snackPosition == SnackPosition.TOP, | ||
| 259 | + left: false, | ||
| 260 | + right: false, | ||
| 261 | + child: _getSnack(), | ||
| 262 | + ), | ||
| 263 | + ), | ||
| 264 | + ); | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + @override | ||
| 268 | + void dispose() { | ||
| 269 | + _fadeController?.dispose(); | ||
| 270 | + | ||
| 271 | + widget.progressIndicatorController?.removeListener(_progressListener); | ||
| 272 | + widget.progressIndicatorController?.dispose(); | ||
| 273 | + | ||
| 274 | + _focusAttachment.detach(); | ||
| 275 | + _focusNode!.dispose(); | ||
| 276 | + super.dispose(); | ||
| 277 | + } | ||
| 278 | + | ||
| 226 | @override | 279 | @override |
| 227 | void initState() { | 280 | void initState() { |
| 228 | super.initState(); | 281 | super.initState(); |
| @@ -250,25 +303,31 @@ Set either a message or messageText"""); | @@ -250,25 +303,31 @@ Set either a message or messageText"""); | ||
| 250 | _focusAttachment = _focusNode!.attach(context); | 303 | _focusAttachment = _focusNode!.attach(context); |
| 251 | } | 304 | } |
| 252 | 305 | ||
| 253 | - @override | ||
| 254 | - void dispose() { | ||
| 255 | - _fadeController?.dispose(); | ||
| 256 | - | ||
| 257 | - widget.progressIndicatorController?.removeListener(_progressListener); | ||
| 258 | - widget.progressIndicatorController?.dispose(); | ||
| 259 | - | ||
| 260 | - _focusAttachment.detach(); | ||
| 261 | - _focusNode!.dispose(); | ||
| 262 | - super.dispose(); | 306 | + Widget _buildLeftBarIndicator() { |
| 307 | + if (widget.leftBarIndicatorColor != null) { | ||
| 308 | + return FutureBuilder<Size>( | ||
| 309 | + future: _boxHeightCompleter.future, | ||
| 310 | + builder: (buildContext, snapshot) { | ||
| 311 | + if (snapshot.hasData) { | ||
| 312 | + return Container( | ||
| 313 | + color: widget.leftBarIndicatorColor, | ||
| 314 | + width: 5.0, | ||
| 315 | + height: snapshot.data!.height, | ||
| 316 | + ); | ||
| 317 | + } else { | ||
| 318 | + return _emptyWidget; | ||
| 319 | + } | ||
| 320 | + }, | ||
| 321 | + ); | ||
| 322 | + } else { | ||
| 323 | + return _emptyWidget; | ||
| 324 | + } | ||
| 263 | } | 325 | } |
| 264 | 326 | ||
| 265 | - final Completer<Size> _boxHeightCompleter = Completer<Size>(); | ||
| 266 | - | ||
| 267 | void _configureLeftBarFuture() { | 327 | void _configureLeftBarFuture() { |
| 268 | SchedulerBinding.instance!.addPostFrameCallback( | 328 | SchedulerBinding.instance!.addPostFrameCallback( |
| 269 | (_) { | 329 | (_) { |
| 270 | - final keyContext = backgroundBoxKey.currentContext; | ||
| 271 | - | 330 | + final keyContext = _backgroundBoxKey.currentContext; |
| 272 | if (keyContext != null) { | 331 | if (keyContext != null) { |
| 273 | final box = keyContext.findRenderObject() as RenderBox; | 332 | final box = keyContext.findRenderObject() as RenderBox; |
| 274 | _boxHeightCompleter.complete(box.size); | 333 | _boxHeightCompleter.complete(box.size); |
| @@ -277,6 +336,19 @@ Set either a message or messageText"""); | @@ -277,6 +336,19 @@ Set either a message or messageText"""); | ||
| 277 | ); | 336 | ); |
| 278 | } | 337 | } |
| 279 | 338 | ||
| 339 | + void _configureProgressIndicatorAnimation() { | ||
| 340 | + if (widget.showProgressIndicator && | ||
| 341 | + widget.progressIndicatorController != null) { | ||
| 342 | + _progressListener = () { | ||
| 343 | + setState(() {}); | ||
| 344 | + }; | ||
| 345 | + widget.progressIndicatorController!.addListener(_progressListener); | ||
| 346 | + | ||
| 347 | + _progressAnimation = CurvedAnimation( | ||
| 348 | + curve: Curves.linear, parent: widget.progressIndicatorController!); | ||
| 349 | + } | ||
| 350 | + } | ||
| 351 | + | ||
| 280 | void _configurePulseAnimation() { | 352 | void _configurePulseAnimation() { |
| 281 | _fadeController = | 353 | _fadeController = |
| 282 | AnimationController(vsync: this, duration: _pulseAnimationDuration); | 354 | AnimationController(vsync: this, duration: _pulseAnimationDuration); |
| @@ -299,95 +371,9 @@ Set either a message or messageText"""); | @@ -299,95 +371,9 @@ Set either a message or messageText"""); | ||
| 299 | _fadeController!.forward(); | 371 | _fadeController!.forward(); |
| 300 | } | 372 | } |
| 301 | 373 | ||
| 302 | - late VoidCallback _progressListener; | ||
| 303 | - | ||
| 304 | - void _configureProgressIndicatorAnimation() { | ||
| 305 | - if (widget.showProgressIndicator && | ||
| 306 | - widget.progressIndicatorController != null) { | ||
| 307 | - _progressListener = () { | ||
| 308 | - setState(() {}); | ||
| 309 | - }; | ||
| 310 | - widget.progressIndicatorController!.addListener(_progressListener); | ||
| 311 | - | ||
| 312 | - _progressAnimation = CurvedAnimation( | ||
| 313 | - curve: Curves.linear, parent: widget.progressIndicatorController!); | ||
| 314 | - } | ||
| 315 | - } | ||
| 316 | - | ||
| 317 | - @override | ||
| 318 | - Widget build(BuildContext context) { | ||
| 319 | - return Align( | ||
| 320 | - heightFactor: 1.0, | ||
| 321 | - child: Material( | ||
| 322 | - color: widget.snackStyle == SnackStyle.FLOATING | ||
| 323 | - ? Colors.transparent | ||
| 324 | - : widget.backgroundColor, | ||
| 325 | - child: SafeArea( | ||
| 326 | - minimum: widget.snackPosition == SnackPosition.BOTTOM | ||
| 327 | - ? EdgeInsets.only( | ||
| 328 | - // bottom: (GetUtils.isGreaterThan( | ||
| 329 | - // MediaQuery.of(context).viewInsets.bottom, | ||
| 330 | - // MediaQuery.of(context).padding.bottom) | ||
| 331 | - // ? MediaQuery.of(context).viewInsets.bottom | ||
| 332 | - // : MediaQuery.of(context).padding.bottom)) | ||
| 333 | - bottom: MediaQuery.of(context).viewInsets.bottom) | ||
| 334 | - : EdgeInsets.only(top: MediaQuery.of(context).padding.top), | ||
| 335 | - bottom: widget.snackPosition == SnackPosition.BOTTOM, | ||
| 336 | - top: widget.snackPosition == SnackPosition.TOP, | ||
| 337 | - left: false, | ||
| 338 | - right: false, | ||
| 339 | - child: _getSnack(), | ||
| 340 | - ), | ||
| 341 | - ), | ||
| 342 | - ); | ||
| 343 | - } | ||
| 344 | - | ||
| 345 | - Widget _getSnack() { | ||
| 346 | - Widget snack; | ||
| 347 | - | ||
| 348 | - if (widget.userInputForm != null) { | ||
| 349 | - snack = _generateInputSnack(); | ||
| 350 | - } else { | ||
| 351 | - snack = _generateSnack(); | ||
| 352 | - } | ||
| 353 | - | ||
| 354 | - return Stack( | ||
| 355 | - children: [ | ||
| 356 | - FutureBuilder<Size>( | ||
| 357 | - future: _boxHeightCompleter.future, | ||
| 358 | - builder: (context, snapshot) { | ||
| 359 | - if (snapshot.hasData) { | ||
| 360 | - if (widget.barBlur == 0) { | ||
| 361 | - return _emptyWidget; | ||
| 362 | - } | ||
| 363 | - return ClipRRect( | ||
| 364 | - borderRadius: BorderRadius.circular(widget.borderRadius), | ||
| 365 | - child: BackdropFilter( | ||
| 366 | - filter: ImageFilter.blur( | ||
| 367 | - sigmaX: widget.barBlur!, sigmaY: widget.barBlur!), | ||
| 368 | - child: Container( | ||
| 369 | - height: snapshot.data!.height, | ||
| 370 | - width: snapshot.data!.width, | ||
| 371 | - decoration: BoxDecoration( | ||
| 372 | - color: Colors.transparent, | ||
| 373 | - borderRadius: BorderRadius.circular(widget.borderRadius), | ||
| 374 | - ), | ||
| 375 | - ), | ||
| 376 | - ), | ||
| 377 | - ); | ||
| 378 | - } else { | ||
| 379 | - return _emptyWidget; | ||
| 380 | - } | ||
| 381 | - }, | ||
| 382 | - ), | ||
| 383 | - snack, | ||
| 384 | - ], | ||
| 385 | - ); | ||
| 386 | - } | ||
| 387 | - | ||
| 388 | Widget _generateInputSnack() { | 374 | Widget _generateInputSnack() { |
| 389 | return Container( | 375 | return Container( |
| 390 | - key: backgroundBoxKey, | 376 | + key: _backgroundBoxKey, |
| 391 | constraints: widget.maxWidth != null | 377 | constraints: widget.maxWidth != null |
| 392 | ? BoxConstraints(maxWidth: widget.maxWidth!) | 378 | ? BoxConstraints(maxWidth: widget.maxWidth!) |
| 393 | : null, | 379 | : null, |
| @@ -412,12 +398,9 @@ Set either a message or messageText"""); | @@ -412,12 +398,9 @@ Set either a message or messageText"""); | ||
| 412 | ); | 398 | ); |
| 413 | } | 399 | } |
| 414 | 400 | ||
| 415 | - late CurvedAnimation _progressAnimation; | ||
| 416 | - GlobalKey backgroundBoxKey = GlobalKey(); | ||
| 417 | - | ||
| 418 | Widget _generateSnack() { | 401 | Widget _generateSnack() { |
| 419 | return Container( | 402 | return Container( |
| 420 | - key: backgroundBoxKey, | 403 | + key: _backgroundBoxKey, |
| 421 | constraints: widget.maxWidth != null | 404 | constraints: widget.maxWidth != null |
| 422 | ? BoxConstraints(maxWidth: widget.maxWidth!) | 405 | ? BoxConstraints(maxWidth: widget.maxWidth!) |
| 423 | : null, | 406 | : null, |
| @@ -611,25 +594,11 @@ Set either a message or messageText"""); | @@ -611,25 +594,11 @@ Set either a message or messageText"""); | ||
| 611 | } | 594 | } |
| 612 | } | 595 | } |
| 613 | 596 | ||
| 614 | - Widget _buildLeftBarIndicator() { | ||
| 615 | - if (widget.leftBarIndicatorColor != null) { | ||
| 616 | - return FutureBuilder<Size>( | ||
| 617 | - future: _boxHeightCompleter.future, | ||
| 618 | - builder: (buildContext, snapshot) { | ||
| 619 | - if (snapshot.hasData) { | ||
| 620 | - return Container( | ||
| 621 | - color: widget.leftBarIndicatorColor, | ||
| 622 | - width: 5.0, | ||
| 623 | - height: snapshot.data!.height, | ||
| 624 | - ); | ||
| 625 | - } else { | ||
| 626 | - return _emptyWidget; | ||
| 627 | - } | ||
| 628 | - }, | ||
| 629 | - ); | ||
| 630 | - } else { | ||
| 631 | - return _emptyWidget; | ||
| 632 | - } | 597 | + Text _getDefaultNotificationText() { |
| 598 | + return Text( | ||
| 599 | + widget.message ?? "", | ||
| 600 | + style: TextStyle(fontSize: 14.0, color: Colors.white), | ||
| 601 | + ); | ||
| 633 | } | 602 | } |
| 634 | 603 | ||
| 635 | Widget? _getIcon() { | 604 | Widget? _getIcon() { |
| @@ -645,6 +614,53 @@ Set either a message or messageText"""); | @@ -645,6 +614,53 @@ Set either a message or messageText"""); | ||
| 645 | } | 614 | } |
| 646 | } | 615 | } |
| 647 | 616 | ||
| 617 | + Widget? _getMainActionButton() { | ||
| 618 | + return widget.mainButton; | ||
| 619 | + } | ||
| 620 | + | ||
| 621 | + Widget _getSnack() { | ||
| 622 | + Widget snack; | ||
| 623 | + | ||
| 624 | + if (widget.userInputForm != null) { | ||
| 625 | + snack = _generateInputSnack(); | ||
| 626 | + } else { | ||
| 627 | + snack = _generateSnack(); | ||
| 628 | + } | ||
| 629 | + | ||
| 630 | + return Stack( | ||
| 631 | + children: [ | ||
| 632 | + FutureBuilder<Size>( | ||
| 633 | + future: _boxHeightCompleter.future, | ||
| 634 | + builder: (context, snapshot) { | ||
| 635 | + if (snapshot.hasData) { | ||
| 636 | + if (widget.barBlur == 0) { | ||
| 637 | + return _emptyWidget; | ||
| 638 | + } | ||
| 639 | + return ClipRRect( | ||
| 640 | + borderRadius: BorderRadius.circular(widget.borderRadius), | ||
| 641 | + child: BackdropFilter( | ||
| 642 | + filter: ImageFilter.blur( | ||
| 643 | + sigmaX: widget.barBlur!, sigmaY: widget.barBlur!), | ||
| 644 | + child: Container( | ||
| 645 | + height: snapshot.data!.height, | ||
| 646 | + width: snapshot.data!.width, | ||
| 647 | + decoration: BoxDecoration( | ||
| 648 | + color: Colors.transparent, | ||
| 649 | + borderRadius: BorderRadius.circular(widget.borderRadius), | ||
| 650 | + ), | ||
| 651 | + ), | ||
| 652 | + ), | ||
| 653 | + ); | ||
| 654 | + } else { | ||
| 655 | + return _emptyWidget; | ||
| 656 | + } | ||
| 657 | + }, | ||
| 658 | + ), | ||
| 659 | + snack, | ||
| 660 | + ], | ||
| 661 | + ); | ||
| 662 | + } | ||
| 663 | + | ||
| 648 | Widget _getTitleText() { | 664 | Widget _getTitleText() { |
| 649 | return widget.titleText ?? | 665 | return widget.titleText ?? |
| 650 | Text( | 666 | Text( |
| @@ -653,36 +669,4 @@ Set either a message or messageText"""); | @@ -653,36 +669,4 @@ Set either a message or messageText"""); | ||
| 653 | fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold), | 669 | fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold), |
| 654 | ); | 670 | ); |
| 655 | } | 671 | } |
| 656 | - | ||
| 657 | - Text _getDefaultNotificationText() { | ||
| 658 | - return Text( | ||
| 659 | - widget.message ?? "", | ||
| 660 | - style: TextStyle(fontSize: 14.0, color: Colors.white), | ||
| 661 | - ); | ||
| 662 | - } | ||
| 663 | - | ||
| 664 | - Widget? _getMainActionButton() { | ||
| 665 | - return widget.mainButton; | ||
| 666 | - } | ||
| 667 | } | 672 | } |
| 668 | - | ||
| 669 | -/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM] | ||
| 670 | -enum SnackPosition { TOP, BOTTOM } | ||
| 671 | - | ||
| 672 | -/// Indicates if snack will be attached to the edge of the screen or not | ||
| 673 | -enum SnackStyle { FLOATING, GROUNDED } | ||
| 674 | - | ||
| 675 | -/// Indicates the direction in which it is possible to dismiss | ||
| 676 | -/// If vertical, dismiss up will be allowed if [SnackPosition.TOP] | ||
| 677 | -/// If vertical, dismiss down will be allowed if [SnackPosition.BOTTOM] | ||
| 678 | -enum SnackDismissDirection { HORIZONTAL, VERTICAL } | ||
| 679 | - | ||
| 680 | -/// Indicates Status of snackbar | ||
| 681 | -/// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar | ||
| 682 | -/// has closed, | ||
| 683 | -/// [SnackbarStatus.OPENING] Starts with the opening animation and ends | ||
| 684 | -/// with the full | ||
| 685 | -/// snackbar display, [SnackbarStatus.CLOSING] Starts with the closing animation | ||
| 686 | -/// and ends | ||
| 687 | -/// with the full snackbar dispose | ||
| 688 | -enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING } |
| 1 | -import 'dart:async'; | ||
| 2 | -import 'dart:ui'; | ||
| 3 | -import 'package:flutter/widgets.dart'; | ||
| 4 | -import '../../../get_core/get_core.dart'; | ||
| 5 | -import '../../get_navigation.dart'; | ||
| 6 | -import 'snack.dart'; | ||
| 7 | - | ||
| 8 | -class SnackRoute<T> extends OverlayRoute<T> { | ||
| 9 | - late Animation<double> _filterBlurAnimation; | ||
| 10 | - late Animation<Color?> _filterColorAnimation; | ||
| 11 | - | ||
| 12 | - SnackRoute({ | ||
| 13 | - required this.snack, | ||
| 14 | - RouteSettings? settings, | ||
| 15 | - }) : super(settings: settings) { | ||
| 16 | - _builder = Builder(builder: (_) { | ||
| 17 | - return GestureDetector( | ||
| 18 | - child: snack, | ||
| 19 | - onTap: snack.onTap != null ? () => snack.onTap!(snack) : null, | ||
| 20 | - ); | ||
| 21 | - }); | ||
| 22 | - | ||
| 23 | - _configureAlignment(snack.snackPosition); | ||
| 24 | - _snackbarStatus = snack.snackbarStatus; | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - _configureAlignment(SnackPosition snackPosition) { | ||
| 28 | - switch (snack.snackPosition) { | ||
| 29 | - case SnackPosition.TOP: | ||
| 30 | - { | ||
| 31 | - _initialAlignment = Alignment(-1.0, -2.0); | ||
| 32 | - _endAlignment = Alignment(-1.0, -1.0); | ||
| 33 | - break; | ||
| 34 | - } | ||
| 35 | - case SnackPosition.BOTTOM: | ||
| 36 | - { | ||
| 37 | - _initialAlignment = Alignment(-1.0, 2.0); | ||
| 38 | - _endAlignment = Alignment(-1.0, 1.0); | ||
| 39 | - break; | ||
| 40 | - } | ||
| 41 | - } | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - GetBar snack; | ||
| 45 | - Builder? _builder; | ||
| 46 | - | ||
| 47 | - final Completer<T> _transitionCompleter = Completer<T>(); | ||
| 48 | - | ||
| 49 | - late SnackbarStatusCallback _snackbarStatus; | ||
| 50 | - Alignment? _initialAlignment; | ||
| 51 | - Alignment? _endAlignment; | ||
| 52 | - bool _wasDismissedBySwipe = false; | ||
| 53 | - bool _onTappedDismiss = false; | ||
| 54 | - | ||
| 55 | - Timer? _timer; | ||
| 56 | - | ||
| 57 | - bool get opaque => false; | ||
| 58 | - | ||
| 59 | - @override | ||
| 60 | - Iterable<OverlayEntry> createOverlayEntries() { | ||
| 61 | - return <OverlayEntry>[ | ||
| 62 | - if (snack.overlayBlur > 0.0) ...[ | ||
| 63 | - OverlayEntry( | ||
| 64 | - builder: (context) { | ||
| 65 | - return GestureDetector( | ||
| 66 | - onTap: () { | ||
| 67 | - if (snack.isDismissible && !_onTappedDismiss) { | ||
| 68 | - _onTappedDismiss = true; | ||
| 69 | - Get.back(); | ||
| 70 | - } | ||
| 71 | - }, | ||
| 72 | - child: AnimatedBuilder( | ||
| 73 | - animation: _filterBlurAnimation, | ||
| 74 | - builder: (context, child) { | ||
| 75 | - return BackdropFilter( | ||
| 76 | - filter: ImageFilter.blur( | ||
| 77 | - sigmaX: _filterBlurAnimation.value, | ||
| 78 | - sigmaY: _filterBlurAnimation.value), | ||
| 79 | - child: Container( | ||
| 80 | - constraints: BoxConstraints.expand(), | ||
| 81 | - color: _filterColorAnimation.value, | ||
| 82 | - ), | ||
| 83 | - ); | ||
| 84 | - }, | ||
| 85 | - ), | ||
| 86 | - ); | ||
| 87 | - }, | ||
| 88 | - maintainState: false, | ||
| 89 | - opaque: opaque, | ||
| 90 | - ), | ||
| 91 | - ], | ||
| 92 | - OverlayEntry( | ||
| 93 | - builder: (context) { | ||
| 94 | - final Widget annotatedChild = Semantics( | ||
| 95 | - child: AlignTransition( | ||
| 96 | - alignment: _animation!, | ||
| 97 | - child: snack.isDismissible | ||
| 98 | - ? _getDismissibleSnack(_builder) | ||
| 99 | - : _getSnack(), | ||
| 100 | - ), | ||
| 101 | - focused: false, | ||
| 102 | - container: true, | ||
| 103 | - explicitChildNodes: true, | ||
| 104 | - ); | ||
| 105 | - return annotatedChild; | ||
| 106 | - }, | ||
| 107 | - maintainState: false, | ||
| 108 | - opaque: opaque, | ||
| 109 | - ), | ||
| 110 | - ]; | ||
| 111 | - } | ||
| 112 | - | ||
| 113 | - String dismissibleKeyGen = ""; | ||
| 114 | - | ||
| 115 | - Widget _getDismissibleSnack(Widget? child) { | ||
| 116 | - return Dismissible( | ||
| 117 | - direction: _getDismissDirection(), | ||
| 118 | - resizeDuration: null, | ||
| 119 | - confirmDismiss: (_) { | ||
| 120 | - if (currentStatus == SnackbarStatus.OPENING || | ||
| 121 | - currentStatus == SnackbarStatus.CLOSING) { | ||
| 122 | - return Future.value(false); | ||
| 123 | - } | ||
| 124 | - return Future.value(true); | ||
| 125 | - }, | ||
| 126 | - key: Key(dismissibleKeyGen), | ||
| 127 | - onDismissed: (_) { | ||
| 128 | - dismissibleKeyGen += "1"; | ||
| 129 | - _cancelTimer(); | ||
| 130 | - _wasDismissedBySwipe = true; | ||
| 131 | - | ||
| 132 | - if (isCurrent) { | ||
| 133 | - navigator!.pop(); | ||
| 134 | - } else { | ||
| 135 | - navigator!.removeRoute(this); | ||
| 136 | - } | ||
| 137 | - }, | ||
| 138 | - child: _getSnack(), | ||
| 139 | - ); | ||
| 140 | - } | ||
| 141 | - | ||
| 142 | - Widget _getSnack() { | ||
| 143 | - return Container( | ||
| 144 | - margin: snack.margin, | ||
| 145 | - child: _builder, | ||
| 146 | - ); | ||
| 147 | - } | ||
| 148 | - | ||
| 149 | - DismissDirection _getDismissDirection() { | ||
| 150 | - if (snack.dismissDirection == SnackDismissDirection.HORIZONTAL) { | ||
| 151 | - return DismissDirection.horizontal; | ||
| 152 | - } else { | ||
| 153 | - if (snack.snackPosition == SnackPosition.TOP) { | ||
| 154 | - return DismissDirection.up; | ||
| 155 | - } | ||
| 156 | - return DismissDirection.down; | ||
| 157 | - } | ||
| 158 | - } | ||
| 159 | - | ||
| 160 | - @override | ||
| 161 | - bool get finishedWhenPopped => | ||
| 162 | - _controller!.status == AnimationStatus.dismissed; | ||
| 163 | - | ||
| 164 | - /// The animation that drives the route's transition and the previous route's | ||
| 165 | - /// forward transition. | ||
| 166 | - Animation<Alignment>? _animation; | ||
| 167 | - | ||
| 168 | - /// The animation controller that the route uses to drive the transitions. | ||
| 169 | - /// | ||
| 170 | - /// The animation itself is exposed by the [animation] property. | ||
| 171 | - AnimationController? _controller; | ||
| 172 | - | ||
| 173 | - /// Called to create the animation controller that will drive the transitions | ||
| 174 | - /// to this route from the previous one, and back to the previous route | ||
| 175 | - /// from this one. | ||
| 176 | - AnimationController createAnimationController() { | ||
| 177 | - assert(!_transitionCompleter.isCompleted, | ||
| 178 | - 'Cannot reuse a $runtimeType after disposing it.'); | ||
| 179 | - assert(snack.animationDuration >= Duration.zero); | ||
| 180 | - return AnimationController( | ||
| 181 | - duration: snack.animationDuration, | ||
| 182 | - debugLabel: debugLabel, | ||
| 183 | - vsync: navigator!, | ||
| 184 | - ); | ||
| 185 | - } | ||
| 186 | - | ||
| 187 | - /// Called to create the animation that exposes the current progress of | ||
| 188 | - /// the transition controlled by the animation controller created by | ||
| 189 | - /// `createAnimationController()`. | ||
| 190 | - Animation<Alignment> createAnimation() { | ||
| 191 | - assert(!_transitionCompleter.isCompleted, | ||
| 192 | - 'Cannot reuse a $runtimeType after disposing it.'); | ||
| 193 | - assert(_controller != null); | ||
| 194 | - return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate( | ||
| 195 | - CurvedAnimation( | ||
| 196 | - parent: _controller!, | ||
| 197 | - curve: snack.forwardAnimationCurve, | ||
| 198 | - reverseCurve: snack.reverseAnimationCurve, | ||
| 199 | - ), | ||
| 200 | - ); | ||
| 201 | - } | ||
| 202 | - | ||
| 203 | - Animation<double> createBlurFilterAnimation() { | ||
| 204 | - return Tween(begin: 0.0, end: snack.overlayBlur).animate( | ||
| 205 | - CurvedAnimation( | ||
| 206 | - parent: _controller!, | ||
| 207 | - curve: Interval( | ||
| 208 | - 0.0, | ||
| 209 | - 0.35, | ||
| 210 | - curve: Curves.easeInOutCirc, | ||
| 211 | - ), | ||
| 212 | - ), | ||
| 213 | - ); | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - Animation<Color?> createColorFilterAnimation() { | ||
| 217 | - return ColorTween(begin: Color(0x00000000), end: snack.overlayColor) | ||
| 218 | - .animate( | ||
| 219 | - CurvedAnimation( | ||
| 220 | - parent: _controller!, | ||
| 221 | - curve: Interval( | ||
| 222 | - 0.0, | ||
| 223 | - 0.35, | ||
| 224 | - curve: Curves.easeInOutCirc, | ||
| 225 | - ), | ||
| 226 | - ), | ||
| 227 | - ); | ||
| 228 | - } | ||
| 229 | - | ||
| 230 | - T? _result; | ||
| 231 | - SnackbarStatus? currentStatus; | ||
| 232 | - | ||
| 233 | - void _handleStatusChanged(AnimationStatus status) { | ||
| 234 | - switch (status) { | ||
| 235 | - case AnimationStatus.completed: | ||
| 236 | - currentStatus = SnackbarStatus.OPEN; | ||
| 237 | - _snackbarStatus(currentStatus); | ||
| 238 | - if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = opaque; | ||
| 239 | - | ||
| 240 | - break; | ||
| 241 | - case AnimationStatus.forward: | ||
| 242 | - currentStatus = SnackbarStatus.OPENING; | ||
| 243 | - _snackbarStatus(currentStatus); | ||
| 244 | - break; | ||
| 245 | - case AnimationStatus.reverse: | ||
| 246 | - currentStatus = SnackbarStatus.CLOSING; | ||
| 247 | - _snackbarStatus(currentStatus); | ||
| 248 | - if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = false; | ||
| 249 | - break; | ||
| 250 | - case AnimationStatus.dismissed: | ||
| 251 | - assert(!overlayEntries.first.opaque); | ||
| 252 | - // We might still be the current route if a subclass is controlling the | ||
| 253 | - // the transition and hits the dismissed status. For example, the iOS | ||
| 254 | - // back gesture drives this animation to the dismissed status before | ||
| 255 | - // popping the navigator. | ||
| 256 | - currentStatus = SnackbarStatus.CLOSED; | ||
| 257 | - _snackbarStatus(currentStatus); | ||
| 258 | - | ||
| 259 | - if (!isCurrent) { | ||
| 260 | - navigator!.finalizeRoute(this); | ||
| 261 | - // assert(overlayEntries.isEmpty); | ||
| 262 | - } | ||
| 263 | - break; | ||
| 264 | - } | ||
| 265 | - changedInternalState(); | ||
| 266 | - } | ||
| 267 | - | ||
| 268 | - @override | ||
| 269 | - void install() { | ||
| 270 | - assert(!_transitionCompleter.isCompleted, | ||
| 271 | - 'Cannot install a $runtimeType after disposing it.'); | ||
| 272 | - _controller = createAnimationController(); | ||
| 273 | - assert(_controller != null, | ||
| 274 | - '$runtimeType.createAnimationController() returned null.'); | ||
| 275 | - _filterBlurAnimation = createBlurFilterAnimation(); | ||
| 276 | - _filterColorAnimation = createColorFilterAnimation(); | ||
| 277 | - _animation = createAnimation(); | ||
| 278 | - assert(_animation != null, '$runtimeType.createAnimation() returned null.'); | ||
| 279 | - super.install(); | ||
| 280 | - } | ||
| 281 | - | ||
| 282 | - @override | ||
| 283 | - TickerFuture didPush() { | ||
| 284 | - super.didPush(); | ||
| 285 | - assert( | ||
| 286 | - _controller != null, | ||
| 287 | - // ignore: lines_longer_than_80_chars | ||
| 288 | - '$runtimeType.didPush called before calling install() or after calling dispose().', | ||
| 289 | - ); | ||
| 290 | - assert( | ||
| 291 | - !_transitionCompleter.isCompleted, | ||
| 292 | - 'Cannot reuse a $runtimeType after disposing it.', | ||
| 293 | - ); | ||
| 294 | - _animation!.addStatusListener(_handleStatusChanged); | ||
| 295 | - _configureTimer(); | ||
| 296 | - return _controller!.forward(); | ||
| 297 | - } | ||
| 298 | - | ||
| 299 | - @override | ||
| 300 | - void didReplace(Route<dynamic>? oldRoute) { | ||
| 301 | - assert( | ||
| 302 | - _controller != null, | ||
| 303 | - // ignore: lines_longer_than_80_chars | ||
| 304 | - '$runtimeType.didReplace called before calling install() or after calling dispose().', | ||
| 305 | - ); | ||
| 306 | - assert( | ||
| 307 | - !_transitionCompleter.isCompleted, | ||
| 308 | - 'Cannot reuse a $runtimeType after disposing it.', | ||
| 309 | - ); | ||
| 310 | - | ||
| 311 | - if (oldRoute is SnackRoute) { | ||
| 312 | - _controller!.value = oldRoute._controller!.value; | ||
| 313 | - } | ||
| 314 | - _animation!.addStatusListener(_handleStatusChanged); | ||
| 315 | - super.didReplace(oldRoute); | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - @override | ||
| 319 | - bool didPop(T? result) { | ||
| 320 | - assert( | ||
| 321 | - _controller != null, | ||
| 322 | - // ignore: lines_longer_than_80_chars | ||
| 323 | - '$runtimeType.didPop called before calling install() or after calling dispose().', | ||
| 324 | - ); | ||
| 325 | - assert( | ||
| 326 | - !_transitionCompleter.isCompleted, | ||
| 327 | - 'Cannot reuse a $runtimeType after disposing it.', | ||
| 328 | - ); | ||
| 329 | - | ||
| 330 | - _result = result; | ||
| 331 | - _cancelTimer(); | ||
| 332 | - | ||
| 333 | - if (_wasDismissedBySwipe) { | ||
| 334 | - Timer(Duration(milliseconds: 200), () { | ||
| 335 | - _controller!.reset(); | ||
| 336 | - }); | ||
| 337 | - | ||
| 338 | - _wasDismissedBySwipe = false; | ||
| 339 | - } else { | ||
| 340 | - _controller!.reverse(); | ||
| 341 | - } | ||
| 342 | - | ||
| 343 | - return super.didPop(result); | ||
| 344 | - } | ||
| 345 | - | ||
| 346 | - void _configureTimer() { | ||
| 347 | - if (snack.duration != null) { | ||
| 348 | - if (_timer != null && _timer!.isActive) { | ||
| 349 | - _timer!.cancel(); | ||
| 350 | - } | ||
| 351 | - _timer = Timer(snack.duration!, () { | ||
| 352 | - if (isCurrent) { | ||
| 353 | - navigator!.pop(); | ||
| 354 | - } else if (isActive) { | ||
| 355 | - navigator!.removeRoute(this); | ||
| 356 | - } | ||
| 357 | - }); | ||
| 358 | - } else { | ||
| 359 | - if (_timer != null) { | ||
| 360 | - _timer!.cancel(); | ||
| 361 | - } | ||
| 362 | - } | ||
| 363 | - } | ||
| 364 | - | ||
| 365 | - void _cancelTimer() { | ||
| 366 | - if (_timer != null && _timer!.isActive) { | ||
| 367 | - _timer!.cancel(); | ||
| 368 | - } | ||
| 369 | - } | ||
| 370 | - | ||
| 371 | - /// Whether this route can perform a transition to the given route. | ||
| 372 | - /// Subclasses can override this method to restrict the set of routes they | ||
| 373 | - /// need to coordinate transitions with. | ||
| 374 | - bool canTransitionTo(SnackRoute<dynamic> nextRoute) => true; | ||
| 375 | - | ||
| 376 | - /// Whether this route can perform a transition from the given route. | ||
| 377 | - /// | ||
| 378 | - /// Subclasses can override this method to restrict the set of routes they | ||
| 379 | - /// need to coordinate transitions with. | ||
| 380 | - bool canTransitionFrom(SnackRoute<dynamic> previousRoute) => true; | ||
| 381 | - | ||
| 382 | - @override | ||
| 383 | - void dispose() { | ||
| 384 | - assert(!_transitionCompleter.isCompleted, | ||
| 385 | - 'Cannot dispose a $runtimeType twice.'); | ||
| 386 | - _controller?.dispose(); | ||
| 387 | - _transitionCompleter.complete(_result); | ||
| 388 | - super.dispose(); | ||
| 389 | - } | ||
| 390 | - | ||
| 391 | - /// A short description of this route useful for debugging. | ||
| 392 | - String get debugLabel => '$runtimeType'; | ||
| 393 | -} |
| 1 | +import 'dart:async'; | ||
| 2 | +import 'dart:ui'; | ||
| 3 | + | ||
| 4 | +import 'package:flutter/material.dart'; | ||
| 5 | + | ||
| 6 | +import '../../../get.dart'; | ||
| 7 | + | ||
| 8 | +class SnackbarController { | ||
| 9 | + static final _snackBarQueue = _SnackBarQueue(); | ||
| 10 | + static bool get isSnackbarBeingShown => _snackBarQueue.isJobInProgress; | ||
| 11 | + | ||
| 12 | + late Animation<double> _filterBlurAnimation; | ||
| 13 | + late Animation<Color?> _filterColorAnimation; | ||
| 14 | + | ||
| 15 | + final GetSnackBar snack; | ||
| 16 | + final _transitionCompleter = Completer<SnackbarController>(); | ||
| 17 | + | ||
| 18 | + late SnackbarStatusCallback? _snackbarStatus; | ||
| 19 | + late final Alignment? _initialAlignment; | ||
| 20 | + late final Alignment? _endAlignment; | ||
| 21 | + | ||
| 22 | + bool _wasDismissedBySwipe = false; | ||
| 23 | + | ||
| 24 | + bool _onTappedDismiss = false; | ||
| 25 | + | ||
| 26 | + Timer? _timer; | ||
| 27 | + | ||
| 28 | + /// The animation that drives the route's transition and the previous route's | ||
| 29 | + /// forward transition. | ||
| 30 | + late final Animation<Alignment> _animation; | ||
| 31 | + | ||
| 32 | + /// The animation controller that the route uses to drive the transitions. | ||
| 33 | + /// | ||
| 34 | + /// The animation itself is exposed by the [animation] property. | ||
| 35 | + late final AnimationController _controller; | ||
| 36 | + | ||
| 37 | + SnackbarStatus? _currentStatus; | ||
| 38 | + | ||
| 39 | + final _overlayEntries = <OverlayEntry>[]; | ||
| 40 | + | ||
| 41 | + OverlayState? _overlayState; | ||
| 42 | + | ||
| 43 | + SnackbarController(this.snack); | ||
| 44 | + | ||
| 45 | + Future<SnackbarController> get future => _transitionCompleter.future; | ||
| 46 | + | ||
| 47 | + Future<void> close() async { | ||
| 48 | + _removeEntry(); | ||
| 49 | + await future; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + Future<void> show() { | ||
| 53 | + return _snackBarQueue.addJob(this); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + void _cancelTimer() { | ||
| 57 | + if (_timer != null && _timer!.isActive) { | ||
| 58 | + _timer!.cancel(); | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + // ignore: avoid_returning_this | ||
| 63 | + void _configureAlignment(SnackPosition snackPosition) { | ||
| 64 | + switch (snack.snackPosition) { | ||
| 65 | + case SnackPosition.TOP: | ||
| 66 | + { | ||
| 67 | + _initialAlignment = const Alignment(-1.0, -2.0); | ||
| 68 | + _endAlignment = const Alignment(-1.0, -1.0); | ||
| 69 | + break; | ||
| 70 | + } | ||
| 71 | + case SnackPosition.BOTTOM: | ||
| 72 | + { | ||
| 73 | + _initialAlignment = const Alignment(-1.0, 2.0); | ||
| 74 | + _endAlignment = const Alignment(-1.0, 1.0); | ||
| 75 | + break; | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + void _configureOverlay() { | ||
| 81 | + _overlayState = Overlay.of(Get.overlayContext!); | ||
| 82 | + _overlayEntries.clear(); | ||
| 83 | + _overlayEntries.addAll(_createOverlayEntries(_getBodyWidget())); | ||
| 84 | + _overlayState!.insertAll(_overlayEntries); | ||
| 85 | + _configureSnackBarDisplay(); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + void _configureSnackBarDisplay() { | ||
| 89 | + assert(!_transitionCompleter.isCompleted, | ||
| 90 | + 'Cannot configure a snackbar after disposing it.'); | ||
| 91 | + _controller = _createAnimationController(); | ||
| 92 | + _configureAlignment(snack.snackPosition); | ||
| 93 | + _snackbarStatus = snack.snackbarStatus; | ||
| 94 | + _filterBlurAnimation = _createBlurFilterAnimation(); | ||
| 95 | + _filterColorAnimation = _createColorOverlayColor(); | ||
| 96 | + _animation = _createAnimation(); | ||
| 97 | + _animation.addStatusListener(_handleStatusChanged); | ||
| 98 | + _configureTimer(); | ||
| 99 | + _controller.forward(); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + void _configureTimer() { | ||
| 103 | + if (snack.duration != null) { | ||
| 104 | + if (_timer != null && _timer!.isActive) { | ||
| 105 | + _timer!.cancel(); | ||
| 106 | + } | ||
| 107 | + _timer = Timer(snack.duration!, _removeEntry); | ||
| 108 | + } else { | ||
| 109 | + if (_timer != null) { | ||
| 110 | + _timer!.cancel(); | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /// Called to create the animation that exposes the current progress of | ||
| 116 | + /// the transition controlled by the animation controller created by | ||
| 117 | + /// `createAnimationController()`. | ||
| 118 | + Animation<Alignment> _createAnimation() { | ||
| 119 | + assert(!_transitionCompleter.isCompleted, | ||
| 120 | + 'Cannot create a animation from a disposed snackbar'); | ||
| 121 | + return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate( | ||
| 122 | + CurvedAnimation( | ||
| 123 | + parent: _controller, | ||
| 124 | + curve: snack.forwardAnimationCurve, | ||
| 125 | + reverseCurve: snack.reverseAnimationCurve, | ||
| 126 | + ), | ||
| 127 | + ); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /// Called to create the animation controller that will drive the transitions | ||
| 131 | + /// to this route from the previous one, and back to the previous route | ||
| 132 | + /// from this one. | ||
| 133 | + AnimationController _createAnimationController() { | ||
| 134 | + assert(!_transitionCompleter.isCompleted, | ||
| 135 | + 'Cannot create a animationController from a disposed snackbar'); | ||
| 136 | + assert(snack.animationDuration >= Duration.zero); | ||
| 137 | + return AnimationController( | ||
| 138 | + duration: snack.animationDuration, | ||
| 139 | + debugLabel: '$runtimeType', | ||
| 140 | + vsync: navigator!, | ||
| 141 | + ); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + Animation<double> _createBlurFilterAnimation() { | ||
| 145 | + return Tween(begin: 0.0, end: snack.overlayBlur).animate( | ||
| 146 | + CurvedAnimation( | ||
| 147 | + parent: _controller, | ||
| 148 | + curve: const Interval( | ||
| 149 | + 0.0, | ||
| 150 | + 0.35, | ||
| 151 | + curve: Curves.easeInOutCirc, | ||
| 152 | + ), | ||
| 153 | + ), | ||
| 154 | + ); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + Animation<Color?> _createColorOverlayColor() { | ||
| 158 | + return ColorTween(begin: const Color(0x00000000), end: snack.overlayColor) | ||
| 159 | + .animate( | ||
| 160 | + CurvedAnimation( | ||
| 161 | + parent: _controller, | ||
| 162 | + curve: const Interval( | ||
| 163 | + 0.0, | ||
| 164 | + 0.35, | ||
| 165 | + curve: Curves.easeInOutCirc, | ||
| 166 | + ), | ||
| 167 | + ), | ||
| 168 | + ); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + Iterable<OverlayEntry> _createOverlayEntries(Widget child) { | ||
| 172 | + return <OverlayEntry>[ | ||
| 173 | + if (snack.overlayBlur > 0.0) ...[ | ||
| 174 | + OverlayEntry( | ||
| 175 | + builder: (context) => GestureDetector( | ||
| 176 | + onTap: () { | ||
| 177 | + if (snack.isDismissible && !_onTappedDismiss) { | ||
| 178 | + _onTappedDismiss = true; | ||
| 179 | + Get.back(); | ||
| 180 | + } | ||
| 181 | + }, | ||
| 182 | + child: AnimatedBuilder( | ||
| 183 | + animation: _filterBlurAnimation, | ||
| 184 | + builder: (context, child) { | ||
| 185 | + return BackdropFilter( | ||
| 186 | + filter: ImageFilter.blur( | ||
| 187 | + sigmaX: _filterBlurAnimation.value, | ||
| 188 | + sigmaY: _filterBlurAnimation.value), | ||
| 189 | + child: Container( | ||
| 190 | + constraints: const BoxConstraints.expand(), | ||
| 191 | + color: _filterColorAnimation.value, | ||
| 192 | + ), | ||
| 193 | + ); | ||
| 194 | + }, | ||
| 195 | + ), | ||
| 196 | + ), | ||
| 197 | + maintainState: false, | ||
| 198 | + opaque: false, | ||
| 199 | + ), | ||
| 200 | + ], | ||
| 201 | + OverlayEntry( | ||
| 202 | + builder: (context) => Semantics( | ||
| 203 | + child: AlignTransition( | ||
| 204 | + alignment: _animation, | ||
| 205 | + child: snack.isDismissible | ||
| 206 | + ? _getDismissibleSnack(child) | ||
| 207 | + : _getSnackbarContainer(child), | ||
| 208 | + ), | ||
| 209 | + focused: false, | ||
| 210 | + container: true, | ||
| 211 | + explicitChildNodes: true, | ||
| 212 | + ), | ||
| 213 | + maintainState: false, | ||
| 214 | + opaque: false, | ||
| 215 | + ), | ||
| 216 | + ]; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + Widget _getBodyWidget() { | ||
| 220 | + return Builder(builder: (_) { | ||
| 221 | + return GestureDetector( | ||
| 222 | + child: snack, | ||
| 223 | + onTap: snack.onTap != null ? () => snack.onTap?.call(snack) : null, | ||
| 224 | + ); | ||
| 225 | + }); | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + DismissDirection _getDefaultDismissDirection() { | ||
| 229 | + if (snack.snackPosition == SnackPosition.TOP) { | ||
| 230 | + return DismissDirection.up; | ||
| 231 | + } | ||
| 232 | + return DismissDirection.down; | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + Widget _getDismissibleSnack(Widget child) { | ||
| 236 | + return Dismissible( | ||
| 237 | + direction: snack.dismissDirection ?? _getDefaultDismissDirection(), | ||
| 238 | + resizeDuration: null, | ||
| 239 | + confirmDismiss: (_) { | ||
| 240 | + if (_currentStatus == SnackbarStatus.OPENING || | ||
| 241 | + _currentStatus == SnackbarStatus.CLOSING) { | ||
| 242 | + return Future.value(false); | ||
| 243 | + } | ||
| 244 | + return Future.value(true); | ||
| 245 | + }, | ||
| 246 | + key: const Key('dismissible'), | ||
| 247 | + onDismissed: (_) { | ||
| 248 | + _onDismiss(); | ||
| 249 | + }, | ||
| 250 | + child: _getSnackbarContainer(child), | ||
| 251 | + ); | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + Widget _getSnackbarContainer(Widget child) { | ||
| 255 | + return Container( | ||
| 256 | + margin: snack.margin, | ||
| 257 | + child: child, | ||
| 258 | + ); | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + void _handleStatusChanged(AnimationStatus status) { | ||
| 262 | + switch (status) { | ||
| 263 | + case AnimationStatus.completed: | ||
| 264 | + _currentStatus = SnackbarStatus.OPEN; | ||
| 265 | + _snackbarStatus?.call(_currentStatus); | ||
| 266 | + if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false; | ||
| 267 | + | ||
| 268 | + break; | ||
| 269 | + case AnimationStatus.forward: | ||
| 270 | + _currentStatus = SnackbarStatus.OPENING; | ||
| 271 | + _snackbarStatus?.call(_currentStatus); | ||
| 272 | + break; | ||
| 273 | + case AnimationStatus.reverse: | ||
| 274 | + _currentStatus = SnackbarStatus.CLOSING; | ||
| 275 | + _snackbarStatus?.call(_currentStatus); | ||
| 276 | + if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false; | ||
| 277 | + break; | ||
| 278 | + case AnimationStatus.dismissed: | ||
| 279 | + assert(!_overlayEntries.first.opaque); | ||
| 280 | + _currentStatus = SnackbarStatus.CLOSED; | ||
| 281 | + _snackbarStatus?.call(_currentStatus); | ||
| 282 | + _removeOverlay(); | ||
| 283 | + break; | ||
| 284 | + } | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | + void _onDismiss() { | ||
| 288 | + _cancelTimer(); | ||
| 289 | + _wasDismissedBySwipe = true; | ||
| 290 | + _removeEntry(); | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + void _removeEntry() { | ||
| 294 | + assert( | ||
| 295 | + !_transitionCompleter.isCompleted, | ||
| 296 | + 'Cannot remove entry from a disposed snackbar', | ||
| 297 | + ); | ||
| 298 | + | ||
| 299 | + _cancelTimer(); | ||
| 300 | + | ||
| 301 | + if (_wasDismissedBySwipe) { | ||
| 302 | + Timer(const Duration(milliseconds: 200), _controller.reset); | ||
| 303 | + | ||
| 304 | + _wasDismissedBySwipe = false; | ||
| 305 | + } else { | ||
| 306 | + _controller.reverse(); | ||
| 307 | + } | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + void _removeOverlay() { | ||
| 311 | + for (var element in _overlayEntries) { | ||
| 312 | + element.remove(); | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + assert(!_transitionCompleter.isCompleted, 'Cannot remove overlay twice.'); | ||
| 316 | + _controller.dispose(); | ||
| 317 | + _overlayEntries.clear(); | ||
| 318 | + _transitionCompleter.complete(this); | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | + Future<void> _show() { | ||
| 322 | + _configureOverlay(); | ||
| 323 | + return future; | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + static void cancelAllSnackbars() { | ||
| 327 | + _snackBarQueue.cancelAllJobs(); | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + static void closeCurrentSnackbar() { | ||
| 331 | + _snackBarQueue.closeCurrentJob(); | ||
| 332 | + } | ||
| 333 | +} | ||
| 334 | + | ||
| 335 | +class _SnackBarQueue { | ||
| 336 | + final _queue = GetQueue(); | ||
| 337 | + | ||
| 338 | + bool _isJobInProgress = false; | ||
| 339 | + | ||
| 340 | + SnackbarController? _currentSnackbar; | ||
| 341 | + | ||
| 342 | + bool get isJobInProgress => _isJobInProgress; | ||
| 343 | + | ||
| 344 | + Future<void> addJob(SnackbarController job) async { | ||
| 345 | + _isJobInProgress = true; | ||
| 346 | + _currentSnackbar = job; | ||
| 347 | + final data = await _queue.add(job._show); | ||
| 348 | + _isJobInProgress = false; | ||
| 349 | + _currentSnackbar = null; | ||
| 350 | + return data; | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + void cancelAllJobs() { | ||
| 354 | + _currentSnackbar?.close(); | ||
| 355 | + _queue.cancelAllJobs(); | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + void closeCurrentJob() { | ||
| 359 | + _currentSnackbar?.close(); | ||
| 360 | + } | ||
| 361 | +} |
| @@ -4,8 +4,8 @@ class GetMicrotask { | @@ -4,8 +4,8 @@ class GetMicrotask { | ||
| 4 | int _version = 0; | 4 | int _version = 0; |
| 5 | int _microtask = 0; | 5 | int _microtask = 0; |
| 6 | 6 | ||
| 7 | - int get version => _version; | ||
| 8 | int get microtask => _microtask; | 7 | int get microtask => _microtask; |
| 8 | + int get version => _version; | ||
| 9 | 9 | ||
| 10 | void exec(Function callback) { | 10 | void exec(Function callback) { |
| 11 | if (_microtask == _version) { | 11 | if (_microtask == _version) { |
| @@ -23,6 +23,17 @@ class GetQueue { | @@ -23,6 +23,17 @@ class GetQueue { | ||
| 23 | final List<_Item> _queue = []; | 23 | final List<_Item> _queue = []; |
| 24 | bool _active = false; | 24 | bool _active = false; |
| 25 | 25 | ||
| 26 | + Future<T> add<T>(Function job) { | ||
| 27 | + var completer = Completer<T>(); | ||
| 28 | + _queue.add(_Item(completer, job)); | ||
| 29 | + _check(); | ||
| 30 | + return completer.future; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + void cancelAllJobs() { | ||
| 34 | + _queue.clear(); | ||
| 35 | + } | ||
| 36 | + | ||
| 26 | void _check() async { | 37 | void _check() async { |
| 27 | if (!_active && _queue.isNotEmpty) { | 38 | if (!_active && _queue.isNotEmpty) { |
| 28 | _active = true; | 39 | _active = true; |
| @@ -36,13 +47,6 @@ class GetQueue { | @@ -36,13 +47,6 @@ class GetQueue { | ||
| 36 | _check(); | 47 | _check(); |
| 37 | } | 48 | } |
| 38 | } | 49 | } |
| 39 | - | ||
| 40 | - Future<T> add<T>(Function job) { | ||
| 41 | - var completer = Completer<T>(); | ||
| 42 | - _queue.add(_Item(completer, job)); | ||
| 43 | - _check(); | ||
| 44 | - return completer.future; | ||
| 45 | - } | ||
| 46 | } | 50 | } |
| 47 | 51 | ||
| 48 | class _Item { | 52 | class _Item { |
-
Please register or login to post a comment