Line data Source code
1 : import 'package:flutter/material.dart';
2 : import 'package:flutter/scheduler.dart';
3 : import 'package:get/get.dart';
4 : import 'bottomsheet/bottomsheet.dart';
5 : import 'platform/platform.dart';
6 : import 'root/root_controller.dart';
7 : import 'root/smart_management.dart';
8 : import 'routes/bindings_interface.dart';
9 : import 'routes/default_route.dart';
10 : import 'routes/observers/route_observer.dart';
11 : import 'routes/transitions_type.dart';
12 : import 'rx/rx_interface.dart';
13 : import 'snackbar/snack.dart';
14 :
15 : ///Use Get.to instead of Navigator.push, Get.off instead of Navigator.pushReplacement,
16 : ///Get.offAll instead of Navigator.pushAndRemoveUntil. For named routes just add "named"
17 : ///after them. Example: Get.toNamed, Get.offNamed, and Get.AllNamed.
18 : ///To return to the previous screen, use Get.back().
19 : ///No need to pass any context to Get, just put the name of the route inside
20 : ///the parentheses and the magic will occur.
21 : class Get {
22 8 : factory Get() {
23 8 : if (GetImpl == null) GetImpl = Get._();
24 : return GetImpl;
25 : }
26 :
27 : bool _enableLog = true;
28 : bool _defaultPopGesture = GetPlatform.isIOS;
29 : bool _defaultOpaqueRoute = true;
30 : Transition _defaultTransition =
31 : (GetPlatform.isIOS ? Transition.cupertino : Transition.fade);
32 : Duration _defaultDurationTransition = Duration(milliseconds: 400);
33 : bool _defaultGlobalState = true;
34 : RouteSettings _settings;
35 : SmartManagement smartManagement = SmartManagement.full;
36 :
37 : ///Use Get.to instead of Navigator.push, Get.off instead of Navigator.pushReplacement,
38 : ///Get.offAll instead of Navigator.pushAndRemoveUntil. For named routes just add "named"
39 : ///after them. Example: Get.toNamed, Get.offNamed, and Get.AllNamed.
40 : ///To return to the previous screen, use Get.back().
41 : ///No need to pass any context to Get, just put the name of the route inside
42 : ///the parentheses and the magic will occur.
43 8 : Get._();
44 :
45 : static Get GetImpl;
46 :
47 : GlobalKey<NavigatorState> _key;
48 :
49 : /// It replaces Navigator.push, but needs no context, and it doesn't have the Navigator.push
50 : /// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior
51 : /// of rebuilding every app after a route, use opaque = true as the parameter.
52 1 : static Future<T> to<T>(Widget page,
53 : {bool opaque,
54 : Transition transition,
55 : Duration duration,
56 : int id,
57 : bool fullscreenDialog = false,
58 : Object arguments,
59 : Bindings binding,
60 : bool popGesture}) {
61 4 : return GetImpl.global(id).currentState.push(GetRouteBase(
62 : opaque: opaque ?? true,
63 : page: page,
64 1 : settings: RouteSettings(
65 3 : name: '/' + page.toString().toLowerCase(), arguments: arguments),
66 1 : popGesture: popGesture ?? GetImpl._defaultPopGesture,
67 1 : transition: transition ?? GetImpl._defaultTransition,
68 : fullscreenDialog: fullscreenDialog,
69 : binding: binding,
70 1 : transitionDuration: duration ?? GetImpl._defaultDurationTransition));
71 : }
72 :
73 : /// It replaces Navigator.pushNamed, but needs no context, and it doesn't have the Navigator.pushNamed
74 : /// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior
75 : /// of rebuilding every app after a route, use opaque = true as the parameter.
76 1 : static Future<T> toNamed<T>(String page, {Object arguments, int id}) {
77 : // if (key.currentState.mounted) // add this if appear problems on future with route navigate
78 : // when widget don't mounted
79 3 : return GetImpl.global(id).currentState.pushNamed(page, arguments: arguments);
80 : }
81 :
82 : /// It replaces Navigator.pushReplacementNamed, but needs no context.
83 1 : static Future<T> offNamed<T>(String page, {Object arguments, int id}) {
84 : // if (key.currentState.mounted) // add this if appear problems on future with route navigate
85 : // when widget don't mounted
86 : return GetImpl
87 1 : .global(id)
88 1 : .currentState
89 1 : .pushReplacementNamed(page, arguments: arguments);
90 : }
91 :
92 : /// It replaces Navigator.popUntil, but needs no context.
93 0 : static void until(RoutePredicate predicate, {int id}) {
94 : // if (key.currentState.mounted) // add this if appear problems on future with route navigate
95 : // when widget don't mounted
96 0 : return GetImpl.global(id).currentState.popUntil(predicate);
97 : }
98 :
99 : /// It replaces Navigator.pushAndRemoveUntil, but needs no context.
100 1 : static Future<T> offUntil<T>(Route<T> page, RoutePredicate predicate,
101 : {int id}) {
102 : // if (key.currentState.mounted) // add this if appear problems on future with route navigate
103 : // when widget don't mounted
104 3 : return GetImpl.global(id).currentState.pushAndRemoveUntil(page, predicate);
105 : }
106 :
107 : /// It replaces Navigator.pushNamedAndRemoveUntil, but needs no context.
108 1 : static Future<T> offNamedUntil<T>(String page, RoutePredicate predicate,
109 : {int id, Object arguments}) {
110 : return GetImpl
111 1 : .global(id)
112 1 : .currentState
113 1 : .pushNamedAndRemoveUntil(page, predicate, arguments: arguments);
114 : }
115 :
116 : /// It replaces Navigator.popAndPushNamed, but needs no context.
117 1 : static Future<T> offAndToNamed<T>(String page,
118 : {Object arguments, int id, dynamic result}) {
119 : return GetImpl
120 1 : .global(id)
121 1 : .currentState
122 1 : .popAndPushNamed(page, arguments: arguments, result: result);
123 : }
124 :
125 : /// It replaces Navigator.removeRoute, but needs no context.
126 0 : static void removeRoute(Route<dynamic> route, {int id}) {
127 0 : return GetImpl.global(id).currentState.removeRoute(route);
128 : }
129 :
130 : /// It replaces Navigator.pushNamedAndRemoveUntil, but needs no context.
131 1 : static Future<T> offAllNamed<T>(String newRouteName,
132 : {RoutePredicate predicate, Object arguments, int id}) {
133 1 : var route = (Route<dynamic> rota) => false;
134 :
135 3 : return GetImpl.global(id).currentState.pushNamedAndRemoveUntil(
136 : newRouteName, predicate ?? route,
137 : arguments: arguments);
138 : }
139 :
140 0 : static bool get isOverlaysOpen =>
141 0 : (isSnackbarOpen || isDialogOpen || isBottomSheetOpen);
142 :
143 0 : static bool get isOverlaysClosed =>
144 0 : (!Get.isSnackbarOpen && !Get.isDialogOpen && !Get.isBottomSheetOpen);
145 :
146 : /// It replaces Navigator.pop, but needs no context.
147 3 : static void back({dynamic result, bool closeOverlays = false, int id}) {
148 0 : if (closeOverlays && isOverlaysOpen) {
149 0 : navigator.popUntil((route) {
150 0 : return (isOverlaysClosed);
151 : });
152 : }
153 9 : GetImpl.global(id).currentState.pop(result);
154 : }
155 :
156 : /// It will close as many screens as you define. Times must be> 0;
157 0 : static void close(int times, [int id]) {
158 0 : if ((times == null) || (times < 1)) {
159 : times = 1;
160 : }
161 : int count = 0;
162 0 : void back = GetImpl.global(id).currentState.popUntil((route) {
163 0 : return count++ == times;
164 : });
165 : return back;
166 : }
167 :
168 : /// It replaces Navigator.pushReplacement, but needs no context, and it doesn't have the Navigator.pushReplacement
169 : /// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior
170 : /// of rebuilding every app after a route, use opaque = true as the parameter.
171 1 : static Future<T> off<T>(Widget page,
172 : {bool opaque = false,
173 : Transition transition,
174 : bool popGesture,
175 : int id,
176 : Object arguments,
177 : Bindings binding,
178 : bool fullscreenDialog = false,
179 : Duration duration}) {
180 4 : return GetImpl.global(id).currentState.pushReplacement(GetRouteBase(
181 : opaque: opaque ?? true,
182 : page: page,
183 : binding: binding,
184 1 : settings: RouteSettings(
185 3 : name: '/' + page.toString().toLowerCase(), arguments: arguments),
186 : fullscreenDialog: fullscreenDialog,
187 1 : popGesture: popGesture ?? GetImpl._defaultPopGesture,
188 1 : transition: transition ?? GetImpl._defaultTransition,
189 1 : transitionDuration: duration ?? GetImpl._defaultDurationTransition));
190 : }
191 :
192 : /// It replaces Navigator.pushAndRemoveUntil, but needs no context
193 1 : static Future<T> offAll<T>(Widget page,
194 : {RoutePredicate predicate,
195 : bool opaque = false,
196 : bool popGesture,
197 : int id,
198 : Object arguments,
199 : Bindings binding,
200 : bool fullscreenDialog = false,
201 : Transition transition}) {
202 1 : var route = (Route<dynamic> rota) => false;
203 :
204 3 : return GetImpl.global(id).currentState.pushAndRemoveUntil(
205 1 : GetRouteBase(
206 : opaque: opaque ?? true,
207 1 : popGesture: popGesture ?? GetImpl._defaultPopGesture,
208 : page: page,
209 : binding: binding,
210 1 : settings: RouteSettings(
211 3 : name: '/' + page.toString().toLowerCase(), arguments: arguments),
212 : fullscreenDialog: fullscreenDialog,
213 1 : transition: transition ?? GetImpl._defaultTransition,
214 : ),
215 : predicate ?? route);
216 : }
217 :
218 : /// Show a dialog
219 1 : static Future<T> dialog<T>(
220 : Widget child, {
221 : bool barrierDismissible = true,
222 : bool useRootNavigator = true,
223 : // RouteSettings routeSettings
224 : }) {
225 1 : return showDialog(
226 : barrierDismissible: barrierDismissible,
227 : useRootNavigator: useRootNavigator,
228 1 : routeSettings: RouteSettings(name: 'dialog'),
229 1 : context: overlayContext,
230 1 : builder: (_) {
231 : return child;
232 : },
233 : );
234 : }
235 :
236 : /// Api from showGeneralDialog with no context
237 0 : static Future<T> generalDialog<T>({
238 : @required RoutePageBuilder pageBuilder,
239 : String barrierLabel = "Dismiss",
240 : bool barrierDismissible = true,
241 : Color barrierColor = const Color(0x80000000),
242 : Duration transitionDuration = const Duration(milliseconds: 200),
243 : RouteTransitionsBuilder transitionBuilder,
244 : bool useRootNavigator = true,
245 : RouteSettings routeSettings,
246 : }) {
247 0 : return showGeneralDialog(
248 : pageBuilder: pageBuilder,
249 : barrierDismissible: barrierDismissible,
250 : barrierLabel: barrierLabel,
251 : barrierColor: barrierColor,
252 : transitionDuration: transitionDuration,
253 : transitionBuilder: transitionBuilder,
254 : useRootNavigator: useRootNavigator,
255 0 : routeSettings: RouteSettings(name: 'dialog'),
256 0 : context: overlayContext,
257 : );
258 : }
259 :
260 1 : static Future<T> defaultDialog<T>({
261 : String title = "Alert",
262 : Widget content,
263 : VoidCallback onConfirm,
264 : VoidCallback onCancel,
265 : VoidCallback onCustom,
266 : Color cancelTextColor,
267 : Color confirmTextColor,
268 : String textConfirm,
269 : String textCancel,
270 : String textCustom,
271 : Widget confirm,
272 : Widget cancel,
273 : Widget custom,
274 : Color backgroundColor,
275 : Color buttonColor,
276 : String middleText = "Dialog made in 3 lines of code",
277 : double radius = 20.0,
278 : List<Widget> actions,
279 : }) {
280 : bool leanCancel = onCancel != null || textCancel != null;
281 : bool leanConfirm = onConfirm != null || textConfirm != null;
282 1 : actions ??= [];
283 :
284 : if (cancel != null) {
285 0 : actions.add(cancel);
286 : } else {
287 : if (leanCancel) {
288 0 : actions.add(FlatButton(
289 : materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
290 0 : onPressed: () {
291 0 : onCancel?.call();
292 0 : Get.back();
293 : },
294 0 : padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
295 0 : child: Text(
296 : textCancel ?? "Cancel",
297 0 : style: TextStyle(color: cancelTextColor ?? theme.accentColor),
298 : ),
299 0 : shape: RoundedRectangleBorder(
300 0 : side: BorderSide(
301 0 : color: buttonColor ?? Get.theme.accentColor,
302 : width: 2,
303 : style: BorderStyle.solid),
304 0 : borderRadius: BorderRadius.circular(100)),
305 : ));
306 : }
307 : }
308 : if (confirm != null) {
309 0 : actions.add(confirm);
310 : } else {
311 : if (leanConfirm) {
312 2 : actions.add(FlatButton(
313 : materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
314 2 : color: buttonColor ?? Get.theme.accentColor,
315 1 : shape: RoundedRectangleBorder(
316 1 : borderRadius: BorderRadius.circular(100)),
317 1 : child: Text(
318 : textConfirm ?? "Ok",
319 3 : style: TextStyle(color: confirmTextColor ?? theme.primaryColor),
320 : ),
321 0 : onPressed: () {
322 0 : onConfirm?.call();
323 : }));
324 : }
325 : }
326 2 : return Get.dialog(AlertDialog(
327 1 : titlePadding: EdgeInsets.all(8),
328 1 : contentPadding: EdgeInsets.all(8),
329 2 : backgroundColor: backgroundColor ?? Get.theme.dialogBackgroundColor,
330 1 : shape: RoundedRectangleBorder(
331 2 : borderRadius: BorderRadius.all(Radius.circular(radius))),
332 1 : title: Text(title, textAlign: TextAlign.center),
333 1 : content: Column(
334 : crossAxisAlignment: CrossAxisAlignment.center,
335 : mainAxisSize: MainAxisSize.min,
336 1 : children: [
337 1 : content ?? Text(middleText ?? "", textAlign: TextAlign.center),
338 1 : SizedBox(height: 16),
339 1 : ButtonTheme(
340 : minWidth: 78.0,
341 : height: 34.0,
342 1 : child: Wrap(
343 : alignment: WrapAlignment.center,
344 : spacing: 8,
345 : runSpacing: 8,
346 : children: actions,
347 : ),
348 : )
349 : ],
350 : ),
351 : // actions: actions, // ?? <Widget>[cancelButton, confirmButton],
352 : buttonPadding: EdgeInsets.zero,
353 : ));
354 : }
355 :
356 1 : static Future<T> bottomSheet<T>(
357 : Widget bottomsheet, {
358 : Color backgroundColor,
359 : double elevation,
360 : ShapeBorder shape,
361 : Clip clipBehavior,
362 : Color barrierColor,
363 : bool ignoreSafeArea,
364 : bool isScrollControlled = false,
365 : bool useRootNavigator = false,
366 : bool isDismissible = true,
367 : bool enableDrag = true,
368 : }) {
369 0 : assert(bottomsheet != null);
370 1 : assert(isScrollControlled != null);
371 0 : assert(useRootNavigator != null);
372 1 : assert(isDismissible != null);
373 1 : assert(enableDrag != null);
374 :
375 2 : return Navigator.of(overlayContext, rootNavigator: useRootNavigator)
376 2 : .push(GetModalBottomSheetRoute<T>(
377 1 : builder: (_) => bottomsheet,
378 3 : theme: Theme.of(Get.key.currentContext, shadowThemeOnly: true),
379 : isScrollControlled: isScrollControlled,
380 3 : barrierLabel: MaterialLocalizations.of(Get.key.currentContext)
381 1 : .modalBarrierDismissLabel,
382 : backgroundColor: backgroundColor ?? Colors.transparent,
383 : elevation: elevation,
384 : shape: shape,
385 : removeTop: ignoreSafeArea ?? true,
386 : clipBehavior: clipBehavior,
387 : isDismissible: isDismissible,
388 : modalBarrierColor: barrierColor,
389 1 : settings: RouteSettings(name: "bottomsheet"),
390 : enableDrag: enableDrag,
391 : ));
392 : }
393 :
394 1 : static void rawSnackbar(
395 : {String title,
396 : String message,
397 : Widget titleText,
398 : Widget messageText,
399 : Widget icon,
400 : bool instantInit = false,
401 : bool shouldIconPulse = true,
402 : double maxWidth,
403 : EdgeInsets margin = const EdgeInsets.all(0.0),
404 : EdgeInsets padding = const EdgeInsets.all(16),
405 : double borderRadius = 0.0,
406 : Color borderColor,
407 : double borderWidth = 1.0,
408 : Color backgroundColor = const Color(0xFF303030),
409 : Color leftBarIndicatorColor,
410 : List<BoxShadow> boxShadows,
411 : Gradient backgroundGradient,
412 : FlatButton mainButton,
413 : OnTap onTap,
414 : Duration duration = const Duration(seconds: 3),
415 : bool isDismissible = true,
416 : SnackDismissDirection dismissDirection = SnackDismissDirection.VERTICAL,
417 : bool showProgressIndicator = false,
418 : AnimationController progressIndicatorController,
419 : Color progressIndicatorBackgroundColor,
420 : Animation<Color> progressIndicatorValueColor,
421 : SnackPosition snackPosition = SnackPosition.BOTTOM,
422 : SnackStyle snackStyle = SnackStyle.FLOATING,
423 : Curve forwardAnimationCurve = Curves.easeOutCirc,
424 : Curve reverseAnimationCurve = Curves.easeOutCirc,
425 : Duration animationDuration = const Duration(seconds: 1),
426 : SnackStatusCallback onStatusChanged,
427 : double barBlur = 0.0,
428 : double overlayBlur = 0.0,
429 : Color overlayColor = Colors.transparent,
430 : Form userInputForm}) {
431 1 : GetBar getBar = GetBar(
432 : title: title,
433 : message: message,
434 : titleText: titleText,
435 : messageText: messageText,
436 : snackPosition: snackPosition,
437 : borderRadius: borderRadius,
438 : margin: margin,
439 : duration: duration,
440 : barBlur: barBlur,
441 : backgroundColor: backgroundColor,
442 : icon: icon,
443 : shouldIconPulse: shouldIconPulse,
444 : maxWidth: maxWidth,
445 : padding: padding,
446 : borderColor: borderColor,
447 : borderWidth: borderWidth,
448 : leftBarIndicatorColor: leftBarIndicatorColor,
449 : boxShadows: boxShadows,
450 : backgroundGradient: backgroundGradient,
451 : mainButton: mainButton,
452 : onTap: onTap,
453 : isDismissible: isDismissible,
454 : dismissDirection: dismissDirection,
455 : showProgressIndicator: showProgressIndicator ?? false,
456 : progressIndicatorController: progressIndicatorController,
457 : progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
458 : progressIndicatorValueColor: progressIndicatorValueColor,
459 : snackStyle: snackStyle,
460 : forwardAnimationCurve: forwardAnimationCurve,
461 : reverseAnimationCurve: reverseAnimationCurve,
462 : animationDuration: animationDuration,
463 : overlayBlur: overlayBlur,
464 : overlayColor: overlayColor,
465 : userInputForm: userInputForm);
466 :
467 : if (instantInit) {
468 1 : getBar.show();
469 : } else {
470 0 : SchedulerBinding.instance.addPostFrameCallback((_) {
471 0 : getBar.show();
472 : });
473 : }
474 : }
475 :
476 1 : static void snackbar(title, message,
477 : {Color colorText,
478 : Duration duration,
479 :
480 : /// with instantInit = false you can put Get.snackbar on initState
481 : bool instantInit = false,
482 : SnackPosition snackPosition,
483 : Widget titleText,
484 : Widget messageText,
485 : Widget icon,
486 : bool shouldIconPulse,
487 : double maxWidth,
488 : EdgeInsets margin,
489 : EdgeInsets padding,
490 : double borderRadius,
491 : Color borderColor,
492 : double borderWidth,
493 : Color backgroundColor,
494 : Color leftBarIndicatorColor,
495 : List<BoxShadow> boxShadows,
496 : Gradient backgroundGradient,
497 : FlatButton mainButton,
498 : OnTap onTap,
499 : bool isDismissible,
500 : bool showProgressIndicator,
501 : SnackDismissDirection dismissDirection,
502 : AnimationController progressIndicatorController,
503 : Color progressIndicatorBackgroundColor,
504 : Animation<Color> progressIndicatorValueColor,
505 : SnackStyle snackStyle,
506 : Curve forwardAnimationCurve,
507 : Curve reverseAnimationCurve,
508 : Duration animationDuration,
509 : double barBlur,
510 : double overlayBlur,
511 : Color overlayColor,
512 : Form userInputForm}) {
513 1 : GetBar getBar = GetBar(
514 : titleText: (title == null)
515 : ? null
516 : : titleText ??
517 1 : Text(
518 : title,
519 1 : style: TextStyle(
520 3 : color: colorText ?? theme.iconTheme.color,
521 : fontWeight: FontWeight.w800,
522 : fontSize: 16),
523 : ),
524 : messageText: messageText ??
525 1 : Text(
526 : message,
527 1 : style: TextStyle(
528 3 : color: colorText ?? theme.iconTheme.color,
529 : fontWeight: FontWeight.w300,
530 : fontSize: 14),
531 : ),
532 : snackPosition: snackPosition ?? SnackPosition.TOP,
533 : borderRadius: borderRadius ?? 15,
534 1 : margin: margin ?? EdgeInsets.symmetric(horizontal: 10),
535 0 : duration: duration ?? Duration(seconds: 3),
536 : barBlur: barBlur ?? 7.0,
537 1 : backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2),
538 : icon: icon,
539 : shouldIconPulse: shouldIconPulse ?? true,
540 : maxWidth: maxWidth,
541 1 : padding: padding ?? EdgeInsets.all(16),
542 : borderColor: borderColor,
543 : borderWidth: borderWidth,
544 : leftBarIndicatorColor: leftBarIndicatorColor,
545 : boxShadows: boxShadows,
546 : backgroundGradient: backgroundGradient,
547 : mainButton: mainButton,
548 : onTap: onTap,
549 : isDismissible: isDismissible ?? true,
550 : dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL,
551 : showProgressIndicator: showProgressIndicator ?? false,
552 : progressIndicatorController: progressIndicatorController,
553 : progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
554 : progressIndicatorValueColor: progressIndicatorValueColor,
555 : snackStyle: snackStyle ?? SnackStyle.FLOATING,
556 : forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,
557 : reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,
558 1 : animationDuration: animationDuration ?? Duration(seconds: 1),
559 : overlayBlur: overlayBlur ?? 0.0,
560 : overlayColor: overlayColor ?? Colors.transparent,
561 : userInputForm: userInputForm);
562 :
563 : if (instantInit) {
564 1 : getBar.show();
565 : } else {
566 0 : Get._routing.isSnackbar = true;
567 0 : SchedulerBinding.instance.addPostFrameCallback((_) {
568 0 : getBar.show();
569 : });
570 : }
571 : }
572 :
573 : /// change default config of Get
574 3 : Get.config(
575 : {bool enableLog,
576 : bool defaultPopGesture,
577 : bool defaultOpaqueRoute,
578 : Duration defaultDurationTransition,
579 : bool defaultGlobalState,
580 : Transition defaultTransition}) {
581 : if (enableLog != null) {
582 6 : Get._enableLog = enableLog;
583 : }
584 : if (defaultPopGesture != null) {
585 6 : Get._defaultPopGesture = defaultPopGesture;
586 : }
587 : if (defaultOpaqueRoute != null) {
588 6 : Get._defaultOpaqueRoute = defaultOpaqueRoute;
589 : }
590 : if (defaultTransition != null) {
591 6 : Get._defaultTransition = defaultTransition;
592 : }
593 :
594 : if (defaultDurationTransition != null) {
595 6 : Get._defaultDurationTransition = defaultDurationTransition;
596 : }
597 :
598 : if (defaultGlobalState != null) {
599 6 : Get._defaultGlobalState = defaultGlobalState;
600 : }
601 : }
602 :
603 : GetMaterialController GetImplController = GetMaterialController();
604 :
605 6 : GetMaterialController get getController => GetImplController;
606 :
607 0 : Get.changeTheme(ThemeData theme) {
608 0 : Get.GetImplController.setTheme(theme);
609 : }
610 :
611 0 : Get.changeThemeMode(ThemeMode themeMode) {
612 0 : Get.GetImplController.setThemeMode(themeMode);
613 : }
614 :
615 0 : static GlobalKey<NavigatorState> addKey(GlobalKey<NavigatorState> newKey) {
616 0 : Get._key = newKey;
617 0 : return Get._key;
618 : }
619 :
620 3 : static GlobalKey<NavigatorState> get key {
621 : // GetImpl start empty, is mandatory key be static to prevent errors like "key was called null"
622 6 : if (Get._key == null) {
623 9 : Get._key = GlobalKey<NavigatorState>();
624 : }
625 6 : return Get._key;
626 : }
627 :
628 : Map<int, GlobalKey<NavigatorState>> _keys = {};
629 : UniqueKey mKey = UniqueKey();
630 0 : static GlobalKey<NavigatorState> nestedKey(int key) {
631 0 : Get._keys.putIfAbsent(key, () => GlobalKey<NavigatorState>());
632 0 : return Get._keys[key];
633 : }
634 :
635 3 : GlobalKey<NavigatorState> global(int k) {
636 : if (k == null) {
637 3 : return key;
638 : }
639 0 : if (!_keys.containsKey(k)) {
640 : throw 'route id not found';
641 : }
642 0 : return _keys[k];
643 : }
644 :
645 : //////////// INSTANCE MANAGER
646 : Map<dynamic, dynamic> _singl = {};
647 :
648 : Map<dynamic, _FcBuilderFunc> _factory = {};
649 :
650 3 : static void lazyPut<S>(_FcBuilderFunc builder, {String tag}) {
651 3 : String key = GetImplKey(S, tag);
652 12 : Get._factory.putIfAbsent(key, () => builder);
653 : }
654 :
655 1 : static Future<S> putAsync<S>(_FcBuilderFuncAsync<S> builder,
656 : {String tag}) async {
657 1 : WidgetsFlutterBinding.ensureInitialized();
658 3 : return Get.put<S>(await builder(), tag: tag);
659 : }
660 :
661 : /// Inject class on Get Instance Manager
662 8 : static S put<S>(
663 : S dependency, {
664 : String tag,
665 : bool permanent = false,
666 : bool overrideAbstract = false,
667 : _FcBuilderFunc<S> builder,
668 : }) {
669 8 : _insert(
670 : isSingleton: true,
671 : replace: overrideAbstract,
672 : //?? (("$S" == "${dependency.runtimeType}") == false),
673 : name: tag,
674 : permanent: permanent,
675 8 : builder: builder ?? (() => dependency));
676 8 : return find<S>(tag: tag);
677 : }
678 :
679 : /// Create a new instance from builder class
680 : /// Example
681 : /// Get.create(() => Repl());
682 : /// Repl a = Get.find();
683 : /// Repl b = Get.find();
684 : /// print(a==b); (false)
685 0 : static void create<S>(
686 : _FcBuilderFunc<S> builder, {
687 : String name,
688 : }) {
689 0 : _insert(isSingleton: false, name: name, builder: builder);
690 : }
691 :
692 8 : static void _insert<S>({
693 : bool isSingleton,
694 : String name,
695 : bool replace = true,
696 : bool permanent = false,
697 : _FcBuilderFunc<S> builder,
698 : }) {
699 0 : assert(builder != null);
700 8 : String key = GetImplKey(S, name);
701 : if (replace) {
702 0 : Get._singl[key] = _FcBuilder<S>(isSingleton, builder, permanent);
703 : } else {
704 24 : Get._singl.putIfAbsent(
705 16 : key, () => _FcBuilder<S>(isSingleton, builder, permanent));
706 : }
707 : }
708 :
709 : Map<String, String> routesKey = {};
710 :
711 3 : void removeDependencyByRoute(String routeName) async {
712 3 : List<String> keysToRemove = [];
713 12 : Get.routesKey.forEach((key, value) {
714 : // if (value == routeName && value != null) {
715 3 : if (value == routeName) {
716 0 : keysToRemove.add(key);
717 : }
718 : });
719 3 : keysToRemove.forEach((element) async {
720 0 : await Get.delete(key: element);
721 : });
722 3 : keysToRemove.forEach((element) {
723 0 : Get.routesKey?.remove(element);
724 : });
725 3 : keysToRemove.clear();
726 : }
727 :
728 0 : static bool isRouteDependecyNull<S>({String name}) {
729 0 : return (Get.routesKey[GetImplKey(S, name)] == null);
730 : }
731 :
732 8 : static bool isDependencyInit<S>({String name}) {
733 8 : String key = GetImplKey(S, name);
734 24 : return Get.routesKey.containsKey(key);
735 : }
736 :
737 8 : void registerRouteInstance<S>({String tag}) {
738 : // print("Register route [$S] as ${Get.currentRoute}");
739 48 : Get.routesKey.putIfAbsent(GetImplKey(S, tag), () => Get.currentRoute);
740 : }
741 :
742 0 : static S findByType<S>(Type type, {String tag}) {
743 0 : String key = GetImplKey(type, tag);
744 0 : return Get._singl[key].getSependency();
745 : }
746 :
747 8 : void initController<S>({String tag}) {
748 8 : String key = GetImplKey(S, tag);
749 32 : final i = Get._singl[key].getSependency();
750 :
751 8 : if (i is DisposableInterface) {
752 7 : i.onStart();
753 21 : if (isLogEnable) print('[GET] $key has been initialized');
754 : }
755 : }
756 :
757 : /// Find a instance from required class
758 8 : static S find<S>({String tag, _FcBuilderFunc<S> instance}) {
759 8 : String key = GetImplKey(S, tag);
760 : bool callInit = false;
761 8 : if (Get.isRegistred<S>(tag: tag)) {
762 8 : if (!isDependencyInit<S>() &&
763 24 : Get.smartManagement != SmartManagement.onlyBuilder) {
764 16 : Get.registerRouteInstance<S>(tag: tag);
765 : callInit = true;
766 : }
767 :
768 24 : _FcBuilder builder = Get._singl[key];
769 : if (builder == null) {
770 : if (tag == null) {
771 0 : throw "class ${S.toString()} is not register";
772 : } else {
773 0 : throw "class ${S.toString()} with tag '$tag' is not register";
774 : }
775 : }
776 : if (callInit) {
777 16 : Get.initController<S>(tag: tag);
778 : }
779 :
780 32 : return Get._singl[key].getSependency();
781 : } else {
782 9 : if (!Get._factory.containsKey(key))
783 0 : throw " $S not found. You need call Get.put<$S>($S()) before";
784 :
785 9 : if (isLogEnable) print('[GET] $S instance was created at that time');
786 15 : S _value = Get.put<S>(Get._factory[key].call() as S);
787 :
788 3 : if (!isDependencyInit<S>() &&
789 0 : Get.smartManagement != SmartManagement.onlyBuilder) {
790 0 : Get.registerRouteInstance<S>(tag: tag);
791 : callInit = true;
792 : }
793 :
794 9 : if (Get.smartManagement != SmartManagement.keepFactory) {
795 9 : Get._factory.remove(key);
796 : }
797 :
798 : if (callInit) {
799 0 : Get.initController<S>(tag: tag);
800 : }
801 : return _value;
802 : }
803 : }
804 :
805 : /// Remove dependency of [S] on dependency abstraction. For concrete class use Get.delete
806 0 : static void remove<S>({String tag}) {
807 0 : String key = GetImplKey(S, tag);
808 0 : _FcBuilder builder = Get._singl[key];
809 0 : final i = builder.dependency;
810 :
811 0 : if (i is DisposableInterface || i is GetController) {
812 0 : i.onClose();
813 0 : if (isLogEnable) print('[GET] onClose of $key called');
814 : }
815 0 : if (builder != null) builder.dependency = null;
816 0 : if (Get._singl.containsKey(key)) {
817 0 : print('error on remove $key');
818 : } else {
819 0 : if (isLogEnable) print('[GET] $key removed from memory');
820 : }
821 : }
822 :
823 8 : static String GetImplKey(Type type, String name) {
824 8 : return name == null ? type.toString() : type.toString() + name;
825 : }
826 :
827 1 : static bool reset(
828 : {bool clearFactory = true, bool clearRouteBindings = true}) {
829 3 : if (clearFactory) Get._factory.clear();
830 3 : if (clearRouteBindings) Get.routesKey.clear();
831 3 : Get._singl.clear();
832 : return true;
833 : }
834 :
835 : /// Delete class instance on [S] and clean memory
836 6 : static Future<bool> delete<S>({String tag, String key}) async {
837 : String newKey;
838 : if (key == null) {
839 6 : newKey = GetImplKey(S, tag);
840 : } else {
841 : newKey = key;
842 : }
843 :
844 18 : if (!Get._singl.containsKey(newKey)) {
845 0 : print('Instance $newKey not found');
846 : return false;
847 : }
848 :
849 18 : _FcBuilder builder = Get._singl[newKey];
850 6 : if (builder.permanent) {
851 : (key == null)
852 0 : ? print(
853 0 : '[GET] [$newKey] has been marked as permanent, SmartManagement is not authorized to delete it.')
854 0 : : print(
855 0 : '[GET] [$newKey] has been marked as permanent, SmartManagement is not authorized to delete it.');
856 : return false;
857 : }
858 6 : final i = builder.dependency;
859 :
860 6 : if (i is DisposableInterface || i is GetController) {
861 12 : await i.onClose();
862 18 : if (isLogEnable) print('[GET] onClose of $newKey called');
863 : }
864 :
865 30 : Get._singl.removeWhere((oldkey, value) => (oldkey == newKey));
866 18 : if (Get._singl.containsKey(newKey)) {
867 0 : print('[GET] error on remove object $newKey');
868 : } else {
869 18 : if (isLogEnable) print('[GET] $newKey deleted from memory');
870 : }
871 : // Get.routesKey?.remove(key);
872 : return true;
873 : }
874 :
875 : /// check if instance is registred
876 8 : static bool isRegistred<S>({String tag}) =>
877 32 : Get._singl.containsKey(GetImplKey(S, tag));
878 :
879 6 : static bool isPrepared<S>({String tag}) =>
880 24 : Get._factory.containsKey(GetImplKey(S, tag));
881 :
882 : /// give access to Routing API from GetObserver
883 0 : static Routing get routing => Get._routing;
884 :
885 0 : static RouteSettings get routeSettings => Get._settings;
886 :
887 : Routing _routing = Routing();
888 :
889 : Map<String, String> _parameters = {};
890 :
891 1 : Get.setParameter(Map<String, String> param) {
892 2 : Get._parameters = param;
893 : }
894 :
895 3 : Get.setRouting(Routing rt) {
896 6 : Get._routing = rt;
897 : }
898 :
899 1 : Get.setSettings(RouteSettings settings) {
900 2 : Get._settings = settings;
901 : }
902 :
903 : /// give current arguments
904 0 : static Object get arguments => Get._routing.args;
905 :
906 : /// give current arguments
907 0 : static Map<String, String> get parameters => Get._parameters;
908 :
909 : /// give name from current route
910 32 : static get currentRoute => Get._routing.current;
911 :
912 : /// give name from previous route
913 0 : static get previousRoute => Get._routing.previous;
914 :
915 : /// check if snackbar is open
916 4 : static bool get isSnackbarOpen => Get._routing.isSnackbar;
917 :
918 : /// check if dialog is open
919 4 : static bool get isDialogOpen => Get._routing.isDialog;
920 :
921 : /// check if bottomsheet is open
922 4 : static bool get isBottomSheetOpen => Get._routing.isBottomSheet;
923 :
924 : /// check a raw current route
925 0 : static Route<dynamic> get rawRoute => Get._routing.route;
926 :
927 : /// check if log is enable
928 24 : static bool get isLogEnable => Get._enableLog;
929 :
930 : /// default duration of transition animation
931 : /// default duration work only API 2.0
932 3 : static Duration get defaultDurationTransition =>
933 6 : Get._defaultDurationTransition;
934 :
935 : /// give global state of all GetState by default
936 9 : static bool get defaultGlobalState => Get._defaultGlobalState;
937 :
938 : /// check if popGesture is enable
939 9 : static bool get isPopGestureEnable => Get._defaultPopGesture;
940 :
941 : /// check if default opaque route is enable
942 9 : static bool get isOpaqueRouteDefault => Get._defaultOpaqueRoute;
943 :
944 9 : static Transition get defaultTransition => Get._defaultTransition;
945 :
946 : /// give access to currentContext
947 6 : static BuildContext get context => key.currentContext;
948 :
949 : /// give access to current Overlay Context
950 10 : static BuildContext get overlayContext => key.currentState.overlay.context;
951 :
952 : /// give access to Theme.of(context)
953 6 : static ThemeData get theme => Theme.of(context);
954 :
955 : /// give access to TextTheme.of(context)
956 0 : static TextTheme get textTheme => Theme.of(context).textTheme;
957 :
958 : /// give access to Mediaquery.of(context)
959 0 : static MediaQueryData get mediaQuery => MediaQuery.of(context);
960 :
961 : /// Check if dark mode theme is enable
962 0 : static get isDarkMode => (theme.brightness == Brightness.dark);
963 :
964 : /// Check if dark mode theme is enable on platform on android Q+
965 0 : static get isPlatformDarkMode =>
966 0 : (mediaQuery.platformBrightness == Brightness.dark);
967 :
968 : /// give access to Theme.of(context).iconTheme.color
969 0 : static Color get iconColor => Theme.of(context).iconTheme.color;
970 :
971 : /// give access to Focus.of(context).iconTheme.color
972 0 : static FocusScopeNode get focusScope => FocusScope.of(context);
973 :
974 : /// give access to MediaQuery.of(context).size.height
975 0 : static double get height => MediaQuery.of(context).size.height;
976 :
977 : /// give access to MediaQuery.of(context).size.width
978 0 : static double get width => MediaQuery.of(context).size.width;
979 : }
980 :
981 : /// It replaces the Flutter Navigator, but needs no context.
982 : /// You can to use navigator.push(YourRoute()) rather Navigator.push(context, YourRoute());
983 0 : NavigatorState get navigator => Get.key.currentState;
984 :
985 : class _FcBuilder<S> {
986 : bool isSingleton;
987 : _FcBuilderFunc builderFunc;
988 : S dependency;
989 : bool permanent = false;
990 :
991 8 : _FcBuilder(this.isSingleton, this.builderFunc, this.permanent);
992 :
993 8 : S getSependency() {
994 8 : if (isSingleton) {
995 8 : if (dependency == null) {
996 24 : dependency = builderFunc() as S;
997 : }
998 8 : return dependency;
999 : } else {
1000 0 : return builderFunc() as S;
1001 : }
1002 : }
1003 : }
1004 :
1005 : typedef _FcBuilderFunc<S> = S Function();
1006 :
1007 : typedef _FcBuilderFuncAsync<S> = Future<S> Function();
|