LCOV - code coverage report
Current view: top level - src/navigation/router - contextless_navigator.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 90 90 100.0 %
Date: 2022-11-04 14:47:16 Functions: 0 0 -

          Line data    Source code
       1             : // ignore_for_file: public_member_api_docs
       2             : 
       3             : import 'package:flutter/cupertino.dart';
       4             : import 'package:flutter/material.dart';
       5             : 
       6             : import '../navigator/navigator.dart';
       7             : import '../navigator_observer.dart';
       8             : import '../transitions/transition.dart';
       9             : import 'meedu_page_route.dart';
      10             : 
      11          24 : ContextlessNavigator get router => ContextlessNavigator.i;
      12             : 
      13             : ///this class has the navigator state and the transition configuration
      14             : class ContextlessNavigator {
      15          12 :   ContextlessNavigator._();
      16             : 
      17             :   /// expose the MeeduNavigator soingleton
      18          36 :   static final ContextlessNavigator i = ContextlessNavigator._();
      19             : 
      20             :   GlobalKey<NavigatorState>? _navigatorKey;
      21             :   GlobalKey? _appKey;
      22             : 
      23             :   RouteSettings? _currentRouteSettings;
      24             : 
      25             :   /// store the current route settings
      26           2 :   RouteSettings? get routeSettings => _currentRouteSettings;
      27             : 
      28             :   /// the observer to listen the changes in the stack route
      29          10 :   MeeduNavigatorObserver get observer => MeeduNavigatorObserver();
      30             : 
      31             :   /// a GlobalKey<NavigatorState> to navigate without BuildContext
      32             :   /// ```dart
      33             :   ///import 'package:flutter_meedu/router.dart';
      34             :   ///class MyApp extends StatelessWidget {
      35             :   ///  @override
      36             :   ///  Widget build(BuildContext context) {
      37             :   ///    return MaterialApp(
      38             :   ///      navigatorKey: router.navigatorKey, // add the navigator key
      39             :   ///      home: HomePage(),
      40             :   ///      routes: {YOUR_ROUTES},
      41             :   ///    );
      42             :   ///  }
      43             :   ///}
      44             :   ///```
      45          10 :   GlobalKey<NavigatorState> get navigatorKey {
      46          20 :     _navigatorKey ??= GlobalKey<NavigatorState>();
      47          10 :     return _navigatorKey!;
      48             :   }
      49             : 
      50             :   /// GlobalKey to detenrminate if a MaterialApp or CupertinoApp
      51             :   /// is using the `onGenerateRoute` paremeter or for custom transitions
      52             :   /// using named routes we need to now the value of `routes` parameter
      53             :   ///
      54             :   ///```dart
      55             :   ///import 'package:flutter_meedu/router.dart';
      56             :   ///class MyApp extends StatelessWidget {
      57             :   ///  @override
      58             :   ///  Widget build(BuildContext context) {
      59             :   ///    return MaterialApp(
      60             :   ///      key: router.appKey,
      61             :   ///      navigatorKey: router.navigatorKey, // add the navigator key
      62             :   ///      home: HomePage(),
      63             :   ///      routes: {YOUR_ROUTES},
      64             :   ///    );
      65             :   ///  }
      66             :   ///}
      67             :   ///```
      68           7 :   GlobalKey get appKey {
      69          14 :     _appKey ??= GlobalKey();
      70           7 :     return _appKey!;
      71             :   }
      72             : 
      73             :   /// use material transition as default transition
      74             :   Transition _transition = Transition.material;
      75           8 :   Transition get transition => _transition;
      76             : 
      77             :   /// default transition duration
      78             :   Duration _transitionDuration = const Duration(milliseconds: 300);
      79          10 :   Duration get transitionDuration => _transitionDuration;
      80             : 
      81             :   /// current state of navigatorKey to be used to navigate without BuildContext
      82          30 :   NavigatorState? get _state => navigatorKey.currentState;
      83             : 
      84             :   /// create a navigator 1.0 to use push, pushReplacement, pushAndRemoveUntil and all pop methods
      85          32 :   Navigator1 get _navigator => Navigator1(_state!.context);
      86             : 
      87             :   /// set the current route settings data
      88           5 :   void setRouteSettings(
      89             :     RouteSettings settings, {
      90             :     bool isOverrride = false,
      91             :   }) {
      92           5 :     _currentRouteSettings = settings;
      93             :   }
      94             : 
      95             :   /// validate if the navigator key was assigned to one MaterialApp or CupertinoApp
      96          10 :   void _validateRouterState() {
      97             :     assert(
      98          10 :       _state != null,
      99             :       'Invalid navigator state, make sure that you has been set the navigator key in your MaterialApp',
     100             :     );
     101             :   }
     102             : 
     103             :   /// use this method to destroy the current navigatorKey attached to the app
     104             :   ///
     105             :   /// useful for widget testing
     106           8 :   void dispose() {
     107           8 :     _appKey = null;
     108           9 :     _navigatorKey?.currentState?.dispose();
     109           8 :     _navigatorKey = null;
     110             :   }
     111             : 
     112             :   /// set the default transition for all pages
     113             :   ///
     114             :   /// [duration] set the transition duration for all pages
     115             :   /// by default duration is 300 milliseconds
     116           4 :   void setDefaultTransition(Transition transition, {Duration? duration}) {
     117           4 :     _transition = transition;
     118             :     if (duration != null) {
     119           2 :       _transitionDuration = duration;
     120             :     }
     121             :   }
     122             : 
     123             :   /// return null if default transition must be used
     124             :   ///
     125             :   /// [transitionDuration] is ignored when transition is equals to Transition.material or Transition.cupertino
     126             :   ///
     127             :   /// [backGestureEnabled] not works on Android if transition is Transition.material
     128           6 :   MeeduPageRoute<T>? _buildNamedRoute<T>({
     129             :     required String routeName,
     130             :     required Object? arguments,
     131             :     required bool backGestureEnabled,
     132             :     required Transition? transition,
     133             :     required Duration? transitionDuration,
     134             :   }) {
     135           6 :     _validateRouterState();
     136          12 :     if (appKey.currentWidget == null) {
     137             :       return null;
     138             :     }
     139           6 :     final app = appKey.currentWidget;
     140             :     Route<dynamic>? Function(RouteSettings)? onGenerateRoute;
     141           3 :     if (app is MaterialApp) {
     142           2 :       onGenerateRoute = app.onGenerateRoute;
     143           1 :     } else if (app is CupertinoApp) {
     144           1 :       onGenerateRoute = app.onGenerateRoute;
     145             :     }
     146             : 
     147             :     // if the MaterialApp or CupertinoApp is using onGenerateRoute custom
     148             :     // transitions are not allowed
     149             :     if (onGenerateRoute != null) {
     150             :       return null;
     151             :     }
     152             : 
     153           3 :     final mtransition = transition ?? _transition;
     154           3 :     if (mtransition == Transition.material ||
     155           2 :         mtransition == Transition.cupertino) {
     156             :       return null;
     157             :     }
     158           2 :     final mtransitionDuration = transitionDuration ?? _transitionDuration;
     159             : 
     160             :     // create a custom route with a custom transition
     161           2 :     return MeeduPageRoute<T>(
     162             :       routeName: routeName,
     163           2 :       settings: RouteSettings(
     164             :         name: routeName,
     165             :         arguments: arguments,
     166             :       ),
     167             :       maintainState: true,
     168             :       transitionDuration:
     169           2 :           mtransition == Transition.none ? Duration.zero : mtransitionDuration,
     170             :       fullscreenDialog: false,
     171             :       transition: mtransition,
     172             :       backGestureEnabled: backGestureEnabled,
     173           2 :     )..build();
     174             :   }
     175             : 
     176             :   /// Push the given [page] onto the navigator.
     177             :   ///
     178             :   /// [transitionDuration] will be [Duration.zero] when [transition] is equals to [Transition.none]
     179             :   ///
     180             :   /// [backGestureEnabled] ignored when [transition] is equals to [Transition.material] or [Transition.cupertino]
     181           5 :   Future<T?> push<T>(
     182             :     Widget page, {
     183             :     Object? arguments,
     184             :     bool maintainState = true,
     185             :     bool fullscreenDialog = false,
     186             :     Transition? transition,
     187             :     Duration? transitionDuration,
     188             :     bool backGestureEnabled = false,
     189             :   }) {
     190           5 :     _validateRouterState();
     191          10 :     return _navigator.push<T>(
     192             :       page,
     193             :       arguments: arguments,
     194             :       maintainState: maintainState,
     195             :       fullscreenDialog: fullscreenDialog,
     196             :       transition: transition,
     197             :       transitionDuration: transitionDuration,
     198             :       backGestureEnabled: backGestureEnabled,
     199             :     );
     200             :   }
     201             : 
     202             :   /// Replace the current [page] of the navigator by pushing the given [page] and then
     203             :   ///  disposing the previous route once the new route has finished animating in.
     204             :   ///
     205             :   /// [transitionDuration] will be [Duration.zero] when [transition] is equals to [Transition.none]
     206             :   ///
     207             :   /// [backGestureEnabled] ignored when [transition] is [Transition.material] or [Transition.cupertino]
     208           1 :   Future<T?> pushReplacement<T extends Object?, TO extends Object?>(
     209             :     Widget page, {
     210             :     Object? arguments,
     211             :     bool maintainState = true,
     212             :     bool fullscreenDialog = false,
     213             :     Transition? transition,
     214             :     Duration transitionDuration = const Duration(milliseconds: 300),
     215             :     bool backGestureEnabled = false,
     216             :     TO? result,
     217             :   }) {
     218           1 :     _validateRouterState();
     219           2 :     return _navigator.pushReplacement<T, TO>(
     220             :       page,
     221             :       arguments: arguments,
     222             :       maintainState: maintainState,
     223             :       fullscreenDialog: fullscreenDialog,
     224             :       transition: transition,
     225             :       transitionDuration: transitionDuration,
     226             :       backGestureEnabled: backGestureEnabled,
     227             :       result: result,
     228             :     );
     229             :   }
     230             : 
     231             :   /// navigates to a new pages and remove until
     232             :   ///
     233             :   /// [transitionDuration] is ignored when transition is equals to Transition.material or Transition.cupertino
     234             :   ///
     235             :   /// [backGestureEnabled] not works on Android if transition is Transition.material
     236           1 :   Future<T?> pushAndRemoveUntil<T>(
     237             :     Widget page, {
     238             :     bool Function(Route<dynamic>)? predicate,
     239             :     Object? arguments,
     240             :     bool backGestureEnabled = true,
     241             :     bool maintainState = true,
     242             :     bool fullscreenDialog = false,
     243             :     Transition? transition,
     244             :     Duration? transitionDuration,
     245             :   }) {
     246           1 :     _validateRouterState();
     247           2 :     return _navigator.pushAndRemoveUntil<T>(
     248             :       page,
     249             :       arguments: arguments,
     250             :       maintainState: maintainState,
     251             :       fullscreenDialog: fullscreenDialog,
     252             :       transition: transition,
     253             :       transitionDuration: transitionDuration,
     254             :       backGestureEnabled: backGestureEnabled,
     255           1 :       predicate: predicate ?? (_) => false,
     256             :     );
     257             :   }
     258             : 
     259             :   /// Push a named route onto the navigator.
     260             :   ///
     261             :   /// [transitionDuration] is ignored when transition is equals to Transition.material or Transition.cupertino
     262             :   ///
     263             :   /// [backGestureEnabled] not works on Android if transition is Transition.material
     264           3 :   Future<T?> pushNamed<T>(
     265             :     String routeName, {
     266             :     Object? arguments,
     267             :     bool backGestureEnabled = true,
     268             :     Transition? transition,
     269             :     Duration? transitionDuration,
     270             :   }) {
     271           3 :     final route = _buildNamedRoute<T>(
     272             :       routeName: routeName,
     273             :       arguments: arguments,
     274             :       backGestureEnabled: backGestureEnabled,
     275             :       transition: transition,
     276             :       transitionDuration: transitionDuration,
     277             :     );
     278             :     if (route == null) {
     279           4 :       return _state!.pushNamed<T>(routeName, arguments: arguments);
     280             :     }
     281           2 :     return _state!.push<T>(route);
     282             :   }
     283             : 
     284             :   /// Pop the current route off the navigator and push a named route in its place
     285             :   ///
     286             :   /// [transitionDuration] is ignored when transition is equals to Transition.material or Transition.cupertino
     287             :   ///
     288             :   /// [backGestureEnabled] not works on Android if transition is Transition.material
     289           2 :   Future<T?> popAndPushNamed<T extends Object?, TO extends Object?>(
     290             :     String routeName, {
     291             :     Object? arguments,
     292             :     bool backGestureEnabled = true,
     293             :     Transition? transition,
     294             :     Duration? transitionDuration,
     295             :     TO? result,
     296             :   }) {
     297           2 :     final route = _buildNamedRoute<T>(
     298             :       routeName: routeName,
     299             :       arguments: arguments,
     300             :       backGestureEnabled: backGestureEnabled,
     301             :       transition: transition,
     302             :       transitionDuration: transitionDuration,
     303             :     );
     304             :     if (route == null) {
     305           2 :       return _state!.popAndPushNamed<T, TO>(
     306             :         routeName,
     307             :         arguments: arguments,
     308             :         result: result,
     309             :       );
     310             :     }
     311           2 :     _state!.pop<TO>(result);
     312           2 :     return _state!.push<T>(route);
     313             :   }
     314             : 
     315             :   /// replace the current page with a new route name
     316             :   ///
     317             :   /// [transitionDuration] is ignored when transition is equals to Transition.material or Transition.cupertino
     318             :   ///
     319             :   /// [backGestureEnabled] not works on Android if transition is Transition.material
     320           3 :   Future<T?> pushReplacementNamed<T extends Object?, TO extends Object?>(
     321             :     String routeName, {
     322             :     Object? arguments,
     323             :     bool backGestureEnabled = true,
     324             :     Transition? transition,
     325             :     Duration? transitionDuration,
     326             :     TO? result,
     327             :   }) {
     328           3 :     final route = _buildNamedRoute<T>(
     329             :       routeName: routeName,
     330             :       arguments: arguments,
     331             :       backGestureEnabled: backGestureEnabled,
     332             :       transition: transition,
     333             :       transitionDuration: transitionDuration,
     334             :     );
     335             :     if (route == null) {
     336           4 :       return _state!.pushReplacementNamed<T, TO>(
     337             :         routeName,
     338             :         arguments: arguments,
     339             :         result: result,
     340             :       );
     341             :     }
     342           2 :     return _state!.pushReplacement<T, TO>(route);
     343             :   }
     344             : 
     345             :   /// navigates to a new pages and remove until
     346             :   ///
     347             :   /// [transitionDuration] is ignored when transition is equals to Transition.material or Transition.cupertino
     348             :   ///
     349             :   /// [backGestureEnabled] not works on Android if transition is Transition.material
     350           5 :   Future<T?> pushNamedAndRemoveUntil<T>(
     351             :     String routeName, {
     352             :     bool Function(Route<dynamic>)? predicate,
     353             :     Object? arguments,
     354             :     bool backGestureEnabled = true,
     355             :     Transition? transition,
     356             :     Duration? transitionDuration,
     357             :   }) {
     358           5 :     final route = _buildNamedRoute<T>(
     359             :       routeName: routeName,
     360             :       arguments: arguments,
     361             :       backGestureEnabled: backGestureEnabled,
     362             :       transition: transition,
     363             :       transitionDuration: transitionDuration,
     364             :     );
     365             :     if (route == null) {
     366           8 :       return _state!.pushNamedAndRemoveUntil<T>(
     367             :         routeName,
     368           4 :         predicate ?? (_) => false,
     369             :         arguments: arguments,
     370             :       );
     371             :     }
     372           2 :     return _state!.pushAndRemoveUntil<T>(
     373             :       route,
     374           1 :       predicate ?? (_) => false,
     375             :     );
     376             :   }
     377             : 
     378             :   /// Consults the current route's [Route.willPop] method,
     379             :   ///  and acts accordingly, potentially popping the route as a result;
     380             :   ///
     381             :   ///  returns whether the pop request should be considered handled.
     382           1 :   Future<bool> maybePop<T>([T? result]) {
     383           1 :     _validateRouterState();
     384           2 :     return _navigator.maybePop(result);
     385             :   }
     386             : 
     387             :   /// remove the current page or dialog from the stack until `predicate`
     388           3 :   void pop<T>([T? result]) {
     389           3 :     _validateRouterState();
     390           6 :     _navigator.pop(result);
     391             :   }
     392             : 
     393             :   /// remove all pages in the stack until [predicate]
     394           1 :   void popUntil([bool Function(Route<dynamic>)? predicate]) {
     395           1 :     _validateRouterState();
     396           2 :     _navigator.popUntil(predicate ?? (_) => false);
     397             :   }
     398             : 
     399             :   /// return true if we can do pop
     400           3 :   bool canPop() {
     401           3 :     _validateRouterState();
     402           6 :     return _navigator.canPop();
     403             :   }
     404             : 
     405             :   /// return the arguments of the current page
     406           1 :   Object? get arguments {
     407           2 :     return settings.arguments;
     408             :   }
     409             : 
     410             :   /// return the current route settings
     411           1 :   RouteSettings get settings {
     412             :     assert(
     413           3 :       ContextlessNavigator.i.routeSettings != null,
     414             :       '''
     415             :     you need to define the navigator observer to allow
     416             :     flutter_meedu store the settings of the current route
     417             : 
     418             :       MaterialApp(
     419             :         key: router.appKey,
     420             :         initialRoute: '/',
     421             :         navigatorKey: router.navigatorKey,
     422             :         navigatorObservers: [
     423             :           router.observer, //<-- ADD THIS LINE
     424             :         ],
     425             :         routes: YOUR_ROUTES,
     426             :       ),
     427             : 
     428             :     ''',
     429             :     );
     430           2 :     return ContextlessNavigator.i.routeSettings!;
     431             :   }
     432             : 
     433             :   /// return the current context linked to the global navigatorKey
     434           1 :   BuildContext? get context {
     435           2 :     return navigatorKey.currentContext;
     436             :   }
     437             : }

Generated by: LCOV version 1.16