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