Skip to content

Commit

Permalink
Merge pull request #3182 from jonataslaw/fix-route-observer
Browse files Browse the repository at this point in the history
Fix route observer
  • Loading branch information
jonataslaw authored Aug 16, 2024
2 parents 8059044 + 1c85ae6 commit f7a6330
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 52 deletions.
33 changes: 31 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class MyApp extends StatelessWidget {
name: '/third',
page: () => const Third(),
),
GetPage(
name: '/fourth',
page: () => const Fourth(),
),
],
debugShowCheckedModeBanner: false,
);
Expand Down Expand Up @@ -172,8 +176,7 @@ class Third extends StatelessWidget {
width: 300,
child: ElevatedButton(
onPressed: () {
Get.until((route) {
print(Get.currentRoute);
Get.offNamedUntil('/fourth', (route) {
return Get.currentRoute == '/first';
});
},
Expand All @@ -184,3 +187,29 @@ class Third extends StatelessWidget {
);
}
}

class Fourth extends StatelessWidget {
const Fourth({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
title: const Text('page four'),
),
body: Center(
child: SizedBox(
height: 300,
width: 300,
child: ElevatedButton(
onPressed: () {
Get.back();
},
child: const Text('go to first screen'),
),
),
),
);
}
}
4 changes: 2 additions & 2 deletions lib/get_navigation/src/routes/get_router_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -528,11 +528,11 @@ class GetDelegate extends RouterDelegate<RouteDecoder>

final newPredicate = predicate ?? (route) => false;

while (_activePages.length > 1 && newPredicate(_activePages.last.route!)) {
while (_activePages.length > 1 && !newPredicate(_activePages.last.route!)) {
_activePages.removeLast();
}

return _replaceNamed(route);
return _push(route);
}

@override
Expand Down
22 changes: 3 additions & 19 deletions lib/get_navigation/src/routes/observers/route_observer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ class GetObserver extends NavigatorObserver {
final currentRoute = _RouteData.ofRoute(route);
final newRoute = _RouteData.ofRoute(previousRoute);

// if (currentRoute.isSnackbar) {
// // Get.log("CLOSE SNACKBAR ${currentRoute.name}");
// Get.log("CLOSE SNACKBAR");
// } else

if (currentRoute.isBottomSheet || currentRoute.isDialog) {
Get.log("CLOSE ${currentRoute.name}");
} else if (currentRoute.isGetPageRoute) {
Expand All @@ -71,13 +66,10 @@ class GetObserver extends NavigatorObserver {
value.route = previousRoute;
value.isBack = true;
value.removed = '';
// value.isSnackbar = newRoute.isSnackbar;
value.isBottomSheet = newRoute.isBottomSheet;
value.isDialog = newRoute.isDialog;
});

// print('currentRoute.isDialog ${currentRoute.isDialog}');

routing?.call(_routeSend);
}

Expand All @@ -86,11 +78,6 @@ class GetObserver extends NavigatorObserver {
super.didPush(route, previousRoute);
final newRoute = _RouteData.ofRoute(route);

// if (newRoute.isSnackbar) {
// // Get.log("OPEN SNACKBAR ${newRoute.name}");
// Get.log("OPEN SNACKBAR");
// } else

if (newRoute.isBottomSheet || newRoute.isDialog) {
Get.log("OPEN ${newRoute.name}");
} else if (newRoute.isGetPageRoute) {
Expand All @@ -99,7 +86,6 @@ class GetObserver extends NavigatorObserver {

RouterReportManager.instance.reportCurrentRoute(route);
_routeSend!.update((value) {
// Only PageRoute is allowed to change current value
if (route is PageRoute) {
value.current = newRoute.name ?? '';
}
Expand Down Expand Up @@ -127,15 +113,16 @@ class GetObserver extends NavigatorObserver {
super.didRemove(route, previousRoute);
final routeName = _extractRouteName(route);
final currentRoute = _RouteData.ofRoute(route);
final previousRouteName = _extractRouteName(previousRoute);

Get.log("REMOVING ROUTE $routeName");
Get.log("PREVIOUS ROUTE $previousRouteName");

_routeSend?.update((value) {
value.route = previousRoute;
value.isBack = false;
value.removed = routeName ?? '';
value.previous = routeName ?? '';
// value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;
value.previous = previousRouteName ?? '';
value.isBottomSheet =
currentRoute.isBottomSheet ? false : value.isBottomSheet;
value.isDialog = currentRoute.isDialog ? false : value.isDialog;
Expand Down Expand Up @@ -172,7 +159,6 @@ class GetObserver extends NavigatorObserver {
value.isBack = false;
value.removed = '';
value.previous = '$oldName';
// value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;
value.isBottomSheet =
currentRoute.isBottomSheet ? false : value.isBottomSheet;
value.isDialog = currentRoute.isDialog ? false : value.isDialog;
Expand All @@ -193,7 +179,6 @@ class Routing {
String removed;
Route<dynamic>? route;
bool? isBack;
// bool? isSnackbar;
bool? isBottomSheet;
bool? isDialog;

Expand All @@ -204,7 +189,6 @@ class Routing {
this.removed = '',
this.route,
this.isBack,
// this.isSnackbar,
this.isBottomSheet,
this.isDialog,
});
Expand Down
67 changes: 38 additions & 29 deletions lib/get_navigation/src/routes/route_middleware.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import '../../../get.dart';
abstract class GetMiddleware {
GetMiddleware({this.priority = 0});

final bool _wasInitiated = false;

/// The Order of the Middlewares to run.
///
/// {@tool snippet}
Expand Down Expand Up @@ -99,60 +101,67 @@ abstract class GetMiddleware {
}

class MiddlewareRunner {
MiddlewareRunner(this._middlewares);
MiddlewareRunner(List<GetMiddleware>? middlewares)
: _middlewares = middlewares != null
? (List.of(middlewares)..sort(_compareMiddleware))
: const [] {
// for (final middleware in _middlewares) {
// if (middleware._wasInitiated) continue;
// middleware._wasInitiated = true;
// }
}

final List<GetMiddleware>? _middlewares;
final List<GetMiddleware> _middlewares;

List<GetMiddleware> _getMiddlewares() {
final newMiddleware = _middlewares ?? <GetMiddleware>[];
return List.of(newMiddleware)
..sort(
(a, b) => (a.priority).compareTo(b.priority),
);
}
static int _compareMiddleware(GetMiddleware a, GetMiddleware b) =>
a.priority.compareTo(b.priority);

GetPage? runOnPageCalled(GetPage? page) {
_getMiddlewares().forEach((element) {
page = element.onPageCalled(page);
});
for (final middleware in _middlewares) {
if (middleware._wasInitiated) {
_middlewares.remove(middleware);
continue;
}
page = middleware.onPageCalled(page);
}
return page;
}

RouteSettings? runRedirect(String? route) {
RouteSettings? to;
for (final element in _getMiddlewares()) {
to = element.redirect(route);
if (to != null) {
break;
for (final middleware in _middlewares) {
final redirectTo = middleware.redirect(route);
if (redirectTo != null) {
return redirectTo;
}
}

return to;
return null;
}

List<R>? runOnBindingsStart<R>(List<R>? bindings) {
_getMiddlewares().forEach((element) {
bindings = element.onBindingsStart(bindings);
});
for (final middleware in _middlewares) {
bindings = middleware.onBindingsStart(bindings);
}
return bindings;
}

GetPageBuilder? runOnPageBuildStart(GetPageBuilder? page) {
_getMiddlewares().forEach((element) {
page = element.onPageBuildStart(page);
});
for (final middleware in _middlewares) {
page = middleware.onPageBuildStart(page);
}
return page;
}

Widget runOnPageBuilt(Widget page) {
_getMiddlewares().forEach((element) {
page = element.onPageBuilt(page);
});
for (final middleware in _middlewares) {
page = middleware.onPageBuilt(page);
}
return page;
}

void runOnPageDispose() {
_getMiddlewares().forEach((element) => element.onPageDispose());
for (final middleware in _middlewares) {
middleware.onPageDispose();
}
}
}

Expand Down
114 changes: 114 additions & 0 deletions test/navigation/get_main_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,120 @@ void main() {
expect(find.byType(FirstScreen), findsOneWidget);
});

group('Get.offNamedUntil Tests', () {
testWidgets("Navigates to provided route", (tester) async {
await tester.pumpWidget(WrapperNamed(
initialRoute: '/first',
namedRoutes: [
GetPage(page: () => const FirstScreen(), name: '/first'),
GetPage(page: () => const SecondScreen(), name: '/second'),
GetPage(page: () => const ThirdScreen(), name: '/third')
],
));

Get.offNamedUntil('/second', (route) => route.name == '/first');
await tester.pumpAndSettle();

expect(find.byType(SecondScreen), findsOneWidget);
expect(Get.currentRoute, '/second');
});

testWidgets("Removes routes that don't match predicate", (tester) async {
await tester.pumpWidget(WrapperNamed(
initialRoute: '/first',
namedRoutes: [
GetPage(page: () => const FirstScreen(), name: '/first'),
GetPage(page: () => const SecondScreen(), name: '/second'),
GetPage(page: () => const ThirdScreen(), name: '/third')
],
));

Get.toNamed('/second');
await tester.pumpAndSettle();
Get.offNamedUntil('/third', (route) => route.name == '/first');
await tester.pumpAndSettle();

expect(find.byType(ThirdScreen), findsOneWidget);
expect(Get.currentRoute, '/third');
expect(Get.previousRoute, '/first');
});

testWidgets("Keeps routes that match predicate", (tester) async {
await tester.pumpWidget(WrapperNamed(
initialRoute: '/first',
namedRoutes: [
GetPage(page: () => const FirstScreen(), name: '/first'),
GetPage(page: () => const SecondScreen(), name: '/second'),
GetPage(page: () => const ThirdScreen(), name: '/third'),
],
));

Get.toNamed('/second');
await tester.pumpAndSettle();
Get.offNamedUntil('/third', (route) => route.name == '/first');
await tester.pumpAndSettle();
Get.back();
await tester.pumpAndSettle();

expect(find.byType(FirstScreen), findsOneWidget);
expect(Get.currentRoute, '/first');
});

testWidgets("Handles predicate that never returns true", (tester) async {
await tester.pumpWidget(WrapperNamed(
initialRoute: '/first',
namedRoutes: [
GetPage(page: () => const FirstScreen(), name: '/first'),
GetPage(page: () => const SecondScreen(), name: '/second'),
GetPage(page: () => const ThirdScreen(), name: '/third'),
GetPage(page: () => const FourthScreen(), name: '/fourth'),
],
));

Get.toNamed('/second');
await tester.pumpAndSettle();

Get.toNamed('/third');
await tester.pumpAndSettle();

Get.offNamedUntil('/fourth', (route) => false);
await tester.pumpAndSettle();

expect(find.byType(FourthScreen), findsOneWidget);
expect(Get.currentRoute, '/fourth');
expect(Get.previousRoute, '/first');
});

testWidgets("Handles complex navigation scenario", (tester) async {
await tester.pumpWidget(WrapperNamed(
initialRoute: '/first',
namedRoutes: [
GetPage(page: () => const FirstScreen(), name: '/first'),
GetPage(page: () => const SecondScreen(), name: '/second'),
GetPage(page: () => const ThirdScreen(), name: '/third'),
GetPage(page: () => const FourthScreen(), name: '/fourth'),
],
));

Get.toNamed('/second');
await tester.pumpAndSettle();
Get.toNamed('/third');
await tester.pumpAndSettle();
Get.offNamedUntil('/fourth', (route) => route.name == '/first');
await tester.pumpAndSettle();

expect(find.byType(FourthScreen), findsOneWidget);
expect(Get.currentRoute, '/fourth');
expect(Get.previousRoute, '/first');

Get.back();
await tester.pumpAndSettle();

expect(find.byType(FirstScreen), findsOneWidget);
expect(Get.currentRoute, '/first');
});
});

testWidgets("Get.offNamedUntil navigates to provided route", (tester) async {
await tester.pumpWidget(WrapperNamed(
initialRoute: '/first',
Expand Down

0 comments on commit f7a6330

Please sign in to comment.