Line data Source code
1 : // ignore_for_file: constant_identifier_names
2 :
3 : library nav;
4 :
5 : import 'dart:async';
6 :
7 : import 'package:flutter/cupertino.dart';
8 : import 'package:flutter/foundation.dart';
9 : import 'package:nav/enum/enum_nav_ani.dart';
10 : import 'package:nav/route/ripple_route_builder.dart';
11 : import 'package:nav/route/slide_route_builder.dart';
12 : import 'package:nav/screen/nav_screen.dart';
13 : import 'package:nav/setting/nav_setting.dart';
14 :
15 : export 'package:nav/enum/enum_nav_ani.dart';
16 :
17 : mixin Nav<T extends StatefulWidget> on State<T> {
18 : static const int defaultDurationMs = 200;
19 :
20 : GlobalKey<NavigatorState> get navigatorKey;
21 :
22 3 : static late GlobalKey<NavigatorState> _globalKey;
23 : static NavSetting? navSetting;
24 :
25 5 : @override
26 : void initState() {
27 5 : super.initState();
28 5 : _globalKey = navigatorKey;
29 : }
30 :
31 : ///some library package need to change global key for some purpose.
32 : ///It is not recommended to change globalKey because it will reset all the navigation states.
33 1 : void setGlobalKey(GlobalKey<NavigatorState> key) {
34 : _globalKey = key;
35 : }
36 :
37 1 : static void initialize(NavSetting navSetting) {
38 : Nav.navSetting = navSetting;
39 : }
40 :
41 : /// Get navigator state
42 1 : static NavigatorState? navigatorState(BuildContext? context) {
43 : NavigatorState? state;
44 : try {
45 : if (context != null) {
46 1 : state = Navigator.of(context);
47 : return state;
48 : } else {
49 2 : return _globalKey.currentState;
50 : }
51 : } catch (e) {
52 2 : return _globalKey.currentState;
53 : }
54 : }
55 :
56 9 : static BuildContext get globalContext => _globalKey.currentContext!;
57 :
58 : /// Push screen from right to left
59 : ///
60 : /// On ios "Swipe back gesture" is default
61 : /// Set prohibitSwipeBack true if you don't want allow swipe back.
62 : /// If you provide context, you can nest navigate in your specific context
63 1 : static Future<T?> pushFromRight<T>(
64 : Widget? screen, {
65 : bool prohibitSwipeBack = false,
66 : BuildContext? context,
67 : }) async {
68 : if (screen == null) {
69 : return null;
70 : }
71 2 : return navigatorState(context)?.push(
72 1 : getPushRightRoute(screen, prohibitSwipeBack: prohibitSwipeBack, context: context) as Route<T>,
73 : );
74 : }
75 :
76 1 : static Route<T> getPushRightRoute<T>(Widget screen,
77 : {bool prohibitSwipeBack = false,
78 : BuildContext? context,
79 : int durationMs = Nav.defaultDurationMs}) {
80 2 : return TargetPlatform.iOS == defaultTargetPlatform && !prohibitSwipeBack
81 2 : ? CupertinoPageRoute<T>(builder: (context) => screen)
82 1 : : SlideFromRightRouteBuilder<T>(screen, durationMs: durationMs);
83 : }
84 :
85 : /// Push screen with Ripple Effect (Default: bottomRight to topLeft, You can change the alignment and offset)
86 : ///
87 : /// If you provide context, you can nest navigate in your specific context
88 1 : static Future<T?> pushWithRippleEffect<T>(
89 : Widget? screen, {
90 : BuildContext? context,
91 : AlignmentGeometry? alignment,
92 : Offset offset = const Offset(0, 0),
93 : int durationMs = Nav.defaultDurationMs,
94 : }) async {
95 : if (screen == null) {
96 : return null;
97 : }
98 :
99 5 : final height = MediaQuery.of(navigatorState(context)!.context).size.height;
100 5 : final width = MediaQuery.of(navigatorState(context)!.context).size.width;
101 :
102 2 : return navigatorState(context)?.push(
103 1 : RippleRouteBuilder(screen,
104 2 : maxRadius: height + width / 2,
105 1 : centerAlignment: (alignment == null && offset == const Offset(0, 0))
106 : ? Alignment.bottomRight
107 : : alignment,
108 : centerOffset: offset,
109 : minRadius: 10,
110 : durationMs: durationMs),
111 : );
112 : }
113 :
114 : /// Push screen with NavAni param
115 : ///
116 : /// If you provide context, you can nest navigate in your specific context
117 1 : static Future<T?> push<T>(Widget? screen,
118 : {NavAni navAni = NavAni.Right,
119 : BuildContext? context,
120 : int durationMs = defaultDurationMs}) async {
121 : if (screen == null) {
122 : return null;
123 : }
124 1 : return navigatorState(context)
125 4 : ?.push(navAni.createRoute(screen, navigatorState(context)!.context, durationMs));
126 : }
127 :
128 : /// Push Replacement screen
129 : ///
130 : /// If you provide context, you can nest navigate in your specific context
131 1 : static Future<T?> pushReplacement<T, TO extends Object>(Widget? screen,
132 : {BuildContext? context,
133 : NavAni navAni = NavAni.Fade,
134 : TO? result,
135 : int durationMs = defaultDurationMs}) async {
136 : if (screen == null) {
137 : return null;
138 : }
139 2 : return navigatorState(context)?.pushReplacement(
140 3 : navAni.createRoute(screen, navigatorState(context)!.context, durationMs),
141 : result: result);
142 : }
143 :
144 : /// Clear All screen on navigator state and push the new one.
145 : ///
146 : /// If you provide context, you can nest navigate in your specific context
147 1 : static Future<T?> clearAllAndPush<T>(Widget? screen,
148 : {BuildContext? context,
149 : NavAni navAni = NavAni.Fade,
150 : int durationMs = defaultDurationMs}) async {
151 : if (screen == null) {
152 : return null;
153 : }
154 2 : return navigatorState(context)?.pushAndRemoveUntil(
155 3 : navAni.createRoute(screen, navigatorState(context)!.context, durationMs),
156 1 : (Route<dynamic> route) => false);
157 : }
158 :
159 1 : static Future<Result?> pushResult<Result>(NavScreen<Result> screen,
160 : {NavAni navAni = NavAni.Right,
161 : BuildContext? context,
162 : int durationMs = defaultDurationMs}) async {
163 1 : return push<Result>(screen, navAni: navAni, context: context, durationMs: durationMs);
164 : }
165 :
166 : /// pop screen with result
167 2 : static void pop<T>(BuildContext context, {T? result}) {
168 : if (result == null) {
169 4 : Navigator.of(context).pop();
170 : } else {
171 2 : Navigator.of(context).pop(result);
172 : }
173 : }
174 :
175 : /// Check if can pop
176 1 : static Future<bool> canPop({BuildContext? context}) async {
177 3 : return navigatorState(context)?.canPop() == true;
178 : }
179 :
180 1 : static void clearAll({BuildContext? context}) {
181 1 : final state = navigatorState(context);
182 2 : while (state?.canPop() == true) {
183 1 : state?.pop();
184 : }
185 : }
186 : }
187 : //move coverage tests brew install lcov flutter test --coverage genhtml -o coverage coverage/lcov.info 005d78f Bansook Nam <short88@naver.com> Feb 3, 2024 11:08 AM
|