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