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> {
@override
Widget build(BuildContext context) {
return RouterOutlet.builder(
delegate: Get.nestedKey(null),
builder: (context) {
final title = context.location;
return Scaffold(
drawer: const DrawerWidget(),
appBar: AppBar(
title: Text(title),
centerTitle: true,
),
//body: HomeView(),
return Scaffold(
drawer: const DrawerWidget(),
appBar: AppBar(
title: RouterListener(builder: (context) {
final title = context.location;
return Text(title);
}),
centerTitle: true,
),
//body: HomeView(),
body: GetRouterOutlet(
initialRoute: Routes.home,
delegate: Get.nestedKey(null),
anchorRoute: '/',
filterPages: (afterAnchor) {
// print(afterAnchor);
// print('dddddddddddddddddd');
// print(afterAnchor.take(1));
return afterAnchor.take(1);
},
),
);
},
body: GetRouterOutlet(
initialRoute: Routes.home,
anchorRoute: '/',
),
);
}
}
... ...
... ... @@ -160,34 +160,19 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
}
extension PagesListExt on List<GetPage> {
Iterable<GetPage> pickAtRoute(String route) {
return skipWhile((value) {
return value.name != route;
});
/// Returns the route and all following routes after the given route.
Iterable<GetPage> pickFromRoute(String route) {
return skipWhile((value) => value.name != route);
}
/// Returns the routes after the given route.
Iterable<GetPage> pickAfterRoute(String route) {
return pickAtRoute(route).skip(1);
}
}
class GetRouterOutletInherited extends InheritedWidget {
final String anchorRoute;
const GetRouterOutletInherited({
super.key,
required this.anchorRoute,
required Widget child,
}) : super(child: child);
static GetRouterOutletInherited? of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<GetRouterOutletInherited>();
}
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return true;
// If the provided route is root, we take the first route after root.
if (route == '/') {
return pickFromRoute(route).skip(1).take(1);
}
// Otherwise, we skip the route and take all routes after it.
return pickFromRoute(route).skip(1);
}
}
... ... @@ -221,3 +206,92 @@ class IndexedRouteBuilder<T> extends StatelessWidget {
return builder(context, routes, index);
}
}
mixin RouterListenerMixin<T extends StatefulWidget> on State<T> {
RouterDelegate? delegate;
void _listener() {
setState(() {});
}
VoidCallback? disposer;
@override
void didChangeDependencies() {
super.didChangeDependencies();
disposer?.call();
final router = Router.of(context);
delegate ??= router.routerDelegate;
delegate?.addListener(_listener);
disposer = () => delegate?.removeListener(_listener);
}
@override
void dispose() {
super.dispose();
disposer?.call();
}
}
class RouterListenerInherited extends InheritedWidget {
const RouterListenerInherited({
super.key,
required Widget child,
}) : super(child: child);
static RouterListenerInherited? of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<RouterListenerInherited>();
}
@override
bool updateShouldNotify(covariant InheritedWidget oldWidget) {
return true;
}
}
class RouterListener extends StatefulWidget {
const RouterListener({
Key? key,
required this.builder,
}) : super(key: key);
final WidgetBuilder builder;
@override
State<RouterListener> createState() => RouteListenerState();
}
class RouteListenerState extends State<RouterListener>
with RouterListenerMixin {
@override
Widget build(BuildContext context) {
return RouterListenerInherited(child: Builder(builder: widget.builder));
}
}
class BackButtonCallback extends StatefulWidget {
const BackButtonCallback({Key? key, required this.builder}) : super(key: key);
final WidgetBuilder builder;
@override
State<BackButtonCallback> createState() => RouterListenerState();
}
class RouterListenerState extends State<BackButtonCallback>
with RouterListenerMixin {
late ChildBackButtonDispatcher backButtonDispatcher;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final router = Router.of(context);
backButtonDispatcher =
router.backButtonDispatcher!.createChildBackButtonDispatcher();
}
@override
Widget build(BuildContext context) {
backButtonDispatcher.takePriority();
return widget.builder(context);
}
}
... ...