Line data Source code
1 : import 'package:flutter/foundation.dart'; 2 : import 'package:flutter/material.dart'; 3 : 4 : import 'destination.dart'; 5 : import 'navigation_controller.dart'; 6 : import 'navigation_scheme.dart'; 7 : import 'utils/utils.dart'; 8 : 9 : /// Implementation of [RouterDelegate]. 10 : /// 11 : /// Uses [navigationScheme] to build routes. 12 : /// 13 : /// See also: 14 : /// - [NavigationScheme] 15 : /// - [NavigationController] 16 : /// - [Destination] 17 : /// 18 : class TheseusRouterDelegate extends RouterDelegate<Destination> 19 : with ChangeNotifier 20 : { 21 : /// Creates router delegate. 22 : /// 23 3 : TheseusRouterDelegate({ 24 : required this.navigationScheme, 25 : }) { 26 6 : Log.d(runtimeType, 'TheseusRouterDelegate():'); 27 6 : _key = GlobalKey<NavigatorState>(debugLabel: 'TheseusNavigator'); 28 9 : navigationScheme.addListener(_onCurrentDestinationChanged); 29 : } 30 : 31 : /// A navigation scheme that contains destinations and navigators. 32 : /// 33 : /// This router delegate is listening the navigation scheme to identify if the 34 : /// current destination is changed, and in turn, notifies its listeners when this 35 : /// happens. 36 : /// 37 : final NavigationScheme navigationScheme; 38 : 39 : late final GlobalKey<NavigatorState> _key; 40 : 41 2 : @override 42 : Widget build(BuildContext context) { 43 10 : Log.d(runtimeType, 'build(): isResolving=${navigationScheme.isResolving}'); 44 2 : return Navigator( 45 2 : key: _key, 46 2 : pages: [ 47 2 : MaterialPage( 48 : key: const ValueKey('TheseusRootPage'), 49 6 : child: navigationScheme.rootNavigator.build(context), 50 : ), 51 4 : if (navigationScheme.isResolving) 52 2 : const MaterialPage( 53 : child: _TheseusWaitingOverlay( 54 : key: Key('_TheseusWaitingOverlay_'), 55 : ), 56 : ), 57 : ], 58 0 : onPopPage: (route, result) => route.didPop(result), 59 : ); 60 : } 61 : 62 : @override 63 2 : Future<bool> popRoute() async { 64 4 : Log.d(runtimeType, 'popRoute():'); 65 4 : navigationScheme.goBack(); 66 4 : if (navigationScheme.shouldClose) { 67 2 : if (Platform.isAndroid) { 68 : return false; 69 : } else { 70 8 : navigationScheme.goTo(navigationScheme.currentDestination); 71 : return true; 72 : } 73 : } 74 : return true; 75 : } 76 : 77 : @override 78 : // ignore: avoid_renaming_method_parameters 79 3 : Future<void> setNewRoutePath(destination) async { 80 9 : Log.d(runtimeType, 'setNewRoutePath(): destination=$destination'); 81 : // The current navigation controller stack remains when: 82 : // - The 'upwardDestinationBuilder' is not specified, so we shouldn't build a custom stack. 83 : // - New destination is an 'errorDestination', from which we should be able return back to previous destination. 84 : // Otherwise the stack is reset. 85 3 : final reset = (destination.hasUpwardDestinationBuilder && 86 6 : destination != navigationScheme.errorDestination); 87 9 : return SynchronousFuture(navigationScheme.goTo(destination 88 9 : .withConfiguration(destination.configuration.copyWith(reset: reset)))); 89 : } 90 : 91 3 : @override 92 6 : Destination get currentConfiguration => navigationScheme.currentDestination; 93 : 94 2 : @override 95 : void dispose() { 96 6 : navigationScheme.removeListener(_onCurrentDestinationChanged); 97 2 : super.dispose(); 98 : } 99 : 100 3 : Future<void> _onCurrentDestinationChanged() async { 101 6 : final destination = navigationScheme.currentDestination; 102 6 : Log.d(runtimeType, 103 3 : 'onCurrentDestinationChanged(): destination=$destination'); 104 : // Ignore closing app request here. It is processed in the 'popRoute()' method. 105 6 : if (navigationScheme.shouldClose) { 106 : return; 107 : } 108 3 : notifyListeners(); 109 : } 110 : } 111 : 112 : class _TheseusWaitingOverlay extends StatelessWidget { 113 9 : const _TheseusWaitingOverlay({ 114 : Key? key, 115 0 : }) : super(key: key); 116 : 117 2 : @override 118 : Widget build(BuildContext context) { 119 2 : return Stack( 120 2 : children: [ 121 2 : ModalBarrier( 122 2 : color: Colors.black.withAlpha(128), 123 : dismissible: false, 124 : ), 125 : const Center(child: CircularProgressIndicator(),), 126 : ], 127 : ); 128 : } 129 : }