Jonny Borges

add RouterListener, a widget that can inform its descendants about route changes…

…. Useful for nested navigation, to prevent unnecessary Rebuilds involving RouterOutlet.builder on all widgets.
@@ -10,31 +10,21 @@ class RootView extends GetView<RootController> { @@ -10,31 +10,21 @@ class RootView extends GetView<RootController> {
10 10
11 @override 11 @override
12 Widget build(BuildContext context) { 12 Widget build(BuildContext context) {
13 - return RouterOutlet.builder(  
14 - delegate: Get.nestedKey(null),  
15 - builder: (context) {  
16 - final title = context.location;  
17 - return Scaffold(  
18 - drawer: const DrawerWidget(),  
19 - appBar: AppBar(  
20 - title: Text(title),  
21 - centerTitle: true,  
22 - ),  
23 - //body: HomeView(), 13 + return Scaffold(
  14 + drawer: const DrawerWidget(),
  15 + appBar: AppBar(
  16 + title: RouterListener(builder: (context) {
  17 + final title = context.location;
  18 + return Text(title);
  19 + }),
  20 + centerTitle: true,
  21 + ),
  22 + //body: HomeView(),
24 23
25 - body: GetRouterOutlet(  
26 - initialRoute: Routes.home,  
27 - delegate: Get.nestedKey(null),  
28 - anchorRoute: '/',  
29 - filterPages: (afterAnchor) {  
30 - // print(afterAnchor);  
31 - // print('dddddddddddddddddd');  
32 - // print(afterAnchor.take(1));  
33 - return afterAnchor.take(1);  
34 - },  
35 - ),  
36 - );  
37 - }, 24 + body: GetRouterOutlet(
  25 + initialRoute: Routes.home,
  26 + anchorRoute: '/',
  27 + ),
38 ); 28 );
39 } 29 }
40 } 30 }
@@ -160,34 +160,19 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> { @@ -160,34 +160,19 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
160 } 160 }
161 161
162 extension PagesListExt on List<GetPage> { 162 extension PagesListExt on List<GetPage> {
163 - Iterable<GetPage> pickAtRoute(String route) {  
164 - return skipWhile((value) {  
165 - return value.name != route;  
166 - }); 163 + /// Returns the route and all following routes after the given route.
  164 + Iterable<GetPage> pickFromRoute(String route) {
  165 + return skipWhile((value) => value.name != route);
167 } 166 }
168 167
  168 + /// Returns the routes after the given route.
169 Iterable<GetPage> pickAfterRoute(String route) { 169 Iterable<GetPage> pickAfterRoute(String route) {
170 - return pickAtRoute(route).skip(1);  
171 - }  
172 -}  
173 -  
174 -class GetRouterOutletInherited extends InheritedWidget {  
175 - final String anchorRoute;  
176 -  
177 - const GetRouterOutletInherited({  
178 - super.key,  
179 - required this.anchorRoute,  
180 - required Widget child,  
181 - }) : super(child: child);  
182 -  
183 - static GetRouterOutletInherited? of(BuildContext context) {  
184 - return context  
185 - .dependOnInheritedWidgetOfExactType<GetRouterOutletInherited>();  
186 - }  
187 -  
188 - @override  
189 - bool updateShouldNotify(covariant InheritedWidget oldWidget) {  
190 - return true; 170 + // If the provided route is root, we take the first route after root.
  171 + if (route == '/') {
  172 + return pickFromRoute(route).skip(1).take(1);
  173 + }
  174 + // Otherwise, we skip the route and take all routes after it.
  175 + return pickFromRoute(route).skip(1);
191 } 176 }
192 } 177 }
193 178
@@ -221,3 +206,92 @@ class IndexedRouteBuilder<T> extends StatelessWidget { @@ -221,3 +206,92 @@ class IndexedRouteBuilder<T> extends StatelessWidget {
221 return builder(context, routes, index); 206 return builder(context, routes, index);
222 } 207 }
223 } 208 }
  209 +
  210 +mixin RouterListenerMixin<T extends StatefulWidget> on State<T> {
  211 + RouterDelegate? delegate;
  212 +
  213 + void _listener() {
  214 + setState(() {});
  215 + }
  216 +
  217 + VoidCallback? disposer;
  218 +
  219 + @override
  220 + void didChangeDependencies() {
  221 + super.didChangeDependencies();
  222 + disposer?.call();
  223 + final router = Router.of(context);
  224 + delegate ??= router.routerDelegate;
  225 + delegate?.addListener(_listener);
  226 + disposer = () => delegate?.removeListener(_listener);
  227 + }
  228 +
  229 + @override
  230 + void dispose() {
  231 + super.dispose();
  232 + disposer?.call();
  233 + }
  234 +}
  235 +
  236 +class RouterListenerInherited extends InheritedWidget {
  237 + const RouterListenerInherited({
  238 + super.key,
  239 + required Widget child,
  240 + }) : super(child: child);
  241 +
  242 + static RouterListenerInherited? of(BuildContext context) {
  243 + return context
  244 + .dependOnInheritedWidgetOfExactType<RouterListenerInherited>();
  245 + }
  246 +
  247 + @override
  248 + bool updateShouldNotify(covariant InheritedWidget oldWidget) {
  249 + return true;
  250 + }
  251 +}
  252 +
  253 +class RouterListener extends StatefulWidget {
  254 + const RouterListener({
  255 + Key? key,
  256 + required this.builder,
  257 + }) : super(key: key);
  258 + final WidgetBuilder builder;
  259 +
  260 + @override
  261 + State<RouterListener> createState() => RouteListenerState();
  262 +}
  263 +
  264 +class RouteListenerState extends State<RouterListener>
  265 + with RouterListenerMixin {
  266 + @override
  267 + Widget build(BuildContext context) {
  268 + return RouterListenerInherited(child: Builder(builder: widget.builder));
  269 + }
  270 +}
  271 +
  272 +class BackButtonCallback extends StatefulWidget {
  273 + const BackButtonCallback({Key? key, required this.builder}) : super(key: key);
  274 + final WidgetBuilder builder;
  275 +
  276 + @override
  277 + State<BackButtonCallback> createState() => RouterListenerState();
  278 +}
  279 +
  280 +class RouterListenerState extends State<BackButtonCallback>
  281 + with RouterListenerMixin {
  282 + late ChildBackButtonDispatcher backButtonDispatcher;
  283 +
  284 + @override
  285 + void didChangeDependencies() {
  286 + super.didChangeDependencies();
  287 + final router = Router.of(context);
  288 + backButtonDispatcher =
  289 + router.backButtonDispatcher!.createChildBackButtonDispatcher();
  290 + }
  291 +
  292 + @override
  293 + Widget build(BuildContext context) {
  294 + backButtonDispatcher.takePriority();
  295 + return widget.builder(context);
  296 + }
  297 +}