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/r_ripple.dart';
11 : import 'package:nav/route/r_slide.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 : @Deprecated(
21 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
22 : static const RESULT = "result";
23 :
24 : @Deprecated(
25 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
26 : static const SUCCESS = "success";
27 : @Deprecated(
28 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
29 : static const FAIL = "fail";
30 : @Deprecated(
31 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
32 : static const CANCEL = "cancel";
33 : @Deprecated(
34 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
35 : static const DELETED = "deleted";
36 : @Deprecated(
37 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
38 : static const REFRESH = "refresh";
39 :
40 : GlobalKey<NavigatorState> get navigatorKey;
41 :
42 3 : static late GlobalKey<NavigatorState> _globalKey;
43 : static NavSetting? navSetting;
44 :
45 5 : @override
46 : void initState() {
47 5 : super.initState();
48 5 : _globalKey = navigatorKey;
49 : }
50 :
51 : ///some library package need to change global key for some purpose.
52 : ///It is not recommended to change globalKey because it will reset all the navigation states.
53 1 : void setGlobalKey(GlobalKey<NavigatorState> key) {
54 : _globalKey = key;
55 : }
56 :
57 1 : static void initialize(NavSetting navSetting) {
58 : Nav.navSetting = navSetting;
59 : }
60 :
61 : /// Get navigator state
62 1 : static NavigatorState? navigatorState(BuildContext? context) {
63 : NavigatorState? state;
64 : try {
65 : if (context != null) {
66 1 : state = Navigator.of(context);
67 : return state;
68 : } else {
69 2 : return _globalKey.currentState;
70 : }
71 : } catch (e) {
72 2 : return _globalKey.currentState;
73 : }
74 : }
75 :
76 9 : static BuildContext get globalContext => _globalKey.currentContext!;
77 :
78 : /// Push screen from right to left
79 : ///
80 : /// On ios "Swipe back gesture" is default
81 : /// Set prohibitSwipeBack true if you don't want allow swipe back.
82 : /// If you provide context, you can nest navigate in your specific context
83 1 : static Future<T?> pushFromRight<T>(
84 : Widget? screen, {
85 : bool prohibitSwipeBack = false,
86 : BuildContext? context,
87 : }) async {
88 : if (screen == null) {
89 : return null;
90 : }
91 2 : return navigatorState(context)?.push(
92 1 : getPushRightRoute(screen, prohibitSwipeBack: prohibitSwipeBack, context: context) as Route<T>,
93 : );
94 : }
95 :
96 1 : static Route<T> getPushRightRoute<T>(Widget screen,
97 : {bool prohibitSwipeBack = false,
98 : BuildContext? context,
99 : int durationMs = Nav.defaultDurationMs}) {
100 2 : return TargetPlatform.iOS == defaultTargetPlatform && !prohibitSwipeBack
101 2 : ? CupertinoPageRoute<T>(builder: (context) => screen)
102 1 : : SlideFromRightRoute<T>(screen, durationMs: durationMs);
103 : }
104 :
105 : /// Push screen from left to right
106 : ///
107 : /// If you provide context, you can nest navigate in your specific context
108 0 : static Future<T?> pushFromLeft<T>(Widget? screen, {BuildContext? context}) async {
109 : if (screen == null) {
110 : return null;
111 : }
112 0 : return navigatorState(context)?.push(
113 0 : SlideFromLeftRoute(screen),
114 : );
115 : }
116 :
117 : /// Push screen from bottom to top
118 : ///
119 : /// If you provide context, you can nest navigate in your specific context
120 0 : static Future<T?> pushFromBottom<T>(Widget screen, {BuildContext? context}) async =>
121 0 : navigatorState(context)?.push(
122 0 : SlideFromBottomRoute(screen),
123 : );
124 :
125 : /// Push screen from top to bottom
126 : ///
127 : /// If you provide context, you can nest navigate in your specific context
128 0 : static Future<T?> pushFromTop<T>(Widget screen, {BuildContext? context}) async =>
129 0 : navigatorState(context)?.push(
130 0 : SlideFromTopRoute(screen),
131 : );
132 :
133 : /// Push screen with Ripple Effect (Default: bottomRight to topLeft, You can change the alignment and offset)
134 : ///
135 : /// If you provide context, you can nest navigate in your specific context
136 1 : static Future<T?> pushWithRippleEffect<T>(
137 : Widget? screen, {
138 : BuildContext? context,
139 : AlignmentGeometry? alignment,
140 : Offset offset = const Offset(0, 0),
141 : int durationMs = Nav.defaultDurationMs,
142 : }) async {
143 : if (screen == null) {
144 : return null;
145 : }
146 :
147 5 : final height = MediaQuery.of(navigatorState(context)!.context).size.height;
148 5 : final width = MediaQuery.of(navigatorState(context)!.context).size.width;
149 :
150 2 : return navigatorState(context)?.push(
151 1 : RoundRevealRoute(screen,
152 2 : maxRadius: height + width / 2,
153 1 : centerAlignment: (alignment == null && offset == const Offset(0, 0))
154 : ? Alignment.bottomRight
155 : : alignment,
156 : centerOffset: offset,
157 : minRadius: 10,
158 : durationMs: durationMs),
159 : );
160 : }
161 :
162 : /// Push screen with NavAni param
163 : ///
164 : /// If you provide context, you can nest navigate in your specific context
165 1 : static Future<T?> push<T>(Widget? screen,
166 : {NavAni navAni = NavAni.Right,
167 : BuildContext? context,
168 : int durationMs = defaultDurationMs}) async {
169 : if (screen == null) {
170 : return null;
171 : }
172 1 : return navigatorState(context)
173 4 : ?.push(navAni.createRoute(screen, navigatorState(context)!.context, durationMs));
174 : }
175 :
176 : /// Push Replacement screen
177 : ///
178 : /// If you provide context, you can nest navigate in your specific context
179 1 : static Future<T?> pushReplacement<T, TO extends Object>(Widget? screen,
180 : {BuildContext? context,
181 : NavAni navAni = NavAni.Fade,
182 : TO? result,
183 : int durationMs = defaultDurationMs}) async {
184 : if (screen == null) {
185 : return null;
186 : }
187 2 : return navigatorState(context)?.pushReplacement(
188 3 : navAni.createRoute(screen, navigatorState(context)!.context, durationMs),
189 : result: result);
190 : }
191 :
192 : /// Clear All screen on navigator state and push the new one.
193 : ///
194 : /// If you provide context, you can nest navigate in your specific context
195 1 : static Future<T?> clearAllAndPush<T>(Widget? screen,
196 : {BuildContext? context,
197 : NavAni navAni = NavAni.Fade,
198 : int durationMs = defaultDurationMs}) async {
199 : if (screen == null) {
200 : return null;
201 : }
202 2 : return navigatorState(context)?.pushAndRemoveUntil(
203 3 : navAni.createRoute(screen, navigatorState(context)!.context, durationMs),
204 1 : (Route<dynamic> route) => false);
205 : }
206 :
207 1 : static Future<Result?> pushResult<Result>(NavScreen<Result> screen,
208 : {NavAni navAni = NavAni.Right,
209 : BuildContext? context,
210 : int durationMs = defaultDurationMs}) async {
211 1 : return push<Result>(screen, navAni: navAni, context: context, durationMs: durationMs);
212 : }
213 :
214 : /// Check result is success
215 0 : @Deprecated(
216 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
217 : static bool isSuccess(result) {
218 0 : return result != null && result[RESULT] == SUCCESS;
219 : }
220 :
221 : /// Check result is fail
222 0 : @Deprecated(
223 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
224 : static bool isFail(result) {
225 0 : return result != null && result[RESULT] == FAIL;
226 : }
227 :
228 : /// Check result is cancel
229 0 : @Deprecated(
230 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
231 : static bool isCancel(result) {
232 0 : return result != null && result[RESULT] == CANCEL;
233 : }
234 :
235 : /// Check result is deleted
236 0 : @Deprecated(
237 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
238 : static bool isDeleted(result) {
239 0 : return result != null && result[RESULT] == DELETED;
240 : }
241 :
242 : /// Check result is refresh
243 0 : @Deprecated(
244 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
245 : static bool isRefresh(result) {
246 0 : return result != null && result[RESULT] == REFRESH;
247 : }
248 :
249 : /// pop screen with result
250 1 : static void pop<T>(BuildContext context, {T? result}) {
251 : if (result == null) {
252 2 : Navigator.of(context).pop();
253 : } else {
254 2 : Navigator.of(context).pop(result);
255 : }
256 : }
257 :
258 : /// simple pop with success result
259 0 : @Deprecated(
260 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
261 : static void popResultSuccess(BuildContext context) {
262 0 : pop(context, result: {RESULT: SUCCESS});
263 : }
264 :
265 : /// simple pop with fail result
266 0 : @Deprecated(
267 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
268 : static void popResultFail(BuildContext context) {
269 0 : pop(context, result: {RESULT: FAIL});
270 : }
271 :
272 : /// simple pop with cancel result
273 0 : @Deprecated(
274 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
275 : static void popResultCancel(BuildContext context) {
276 0 : pop(context, result: {RESULT: CANCEL});
277 : }
278 :
279 : /// simple pop with delete result
280 0 : @Deprecated(
281 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
282 : static void popResultDelete(BuildContext context) {
283 0 : pop(context, result: {RESULT: DELETED});
284 : }
285 :
286 : /// simple pop with refresh result
287 0 : @Deprecated(
288 : 'It will be removed on Nav 2025 - 3.0. Please use pushForResult Method with Generic instead of comparing string and dynamic')
289 : static void popResultRefresh(BuildContext context) {
290 0 : pop(context, result: {RESULT: REFRESH});
291 : }
292 :
293 : /// Check if can pop
294 1 : static Future<bool> canPop({BuildContext? context}) async {
295 3 : return navigatorState(context)?.canPop() == true;
296 : }
297 :
298 1 : static void clearAll({BuildContext? context}) {
299 1 : final state = navigatorState(context);
300 2 : while (state?.canPop() == true) {
301 1 : state?.pop();
302 : }
303 : }
304 : }
|