Skip to content

Commit

Permalink
feat(navigator): add navigation observer to sync active tab
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-the-shark committed Sep 19, 2024
1 parent 69832ca commit a492cf7
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 31 deletions.
25 changes: 8 additions & 17 deletions lib/features/navigator/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,13 @@ import "../parkings_view/parkings_view.dart";
import "../science_club_detail_view/science_club_detail_view.dart";
import "../science_clubs_view/science_clubs_view.dart";
import "root_view.dart";
import "utils/no_transition_route.dart";

part "app_router.g.dart";
part "app_router.gr.dart";

class _NoTransitionRoute extends CustomRoute {
_NoTransitionRoute({
required super.path,
required super.page,
}) : super(
reverseDurationInMilliseconds: 0,
durationInMilliseconds: 0,
);
}

@AutoRouterConfig(replaceInRouteName: "View,Route")
class AppRouter extends _$AppRouter {
class AppRouter extends RootStackRouter {
final Ref ref;

AppRouter({required this.ref});
Expand All @@ -40,35 +31,35 @@ class AppRouter extends _$AppRouter {
path: "/",
page: RootRoute.page,
children: [
_NoTransitionRoute(
NoTransitionRoute(
path: "",
page: HomeRoute.page,
),
_NoTransitionRoute(
NoTransitionRoute(
path: "buildings",
page: BuildingsRoute.page,
),
_NoTransitionRoute(
NoTransitionRoute(
path: "parkings",
page: ParkingsRoute.page,
),
_NoTransitionRoute(
NoTransitionRoute(
path: "departments",
page: DepartmentsRoute.page,
),
AutoRoute(
path: "departments/:id",
page: DepartmentDetailRoute.page,
),
_NoTransitionRoute(
NoTransitionRoute(
path: "sci-clubs",
page: ScienceClubsRoute.page,
),
AutoRoute(
path: "sci-clubs/:id",
page: ScienceClubDetailRoute.page,
),
_NoTransitionRoute(
NoTransitionRoute(
path: "guide",
page: GuideRoute.page,
),
Expand Down
23 changes: 11 additions & 12 deletions lib/features/navigator/navigation_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import "../../config/nav_bar_config.dart";

part "navigation_controller.g.dart";

typedef TRoute = PageRouteInfo<dynamic>;
typedef TRoute<T> = PageRouteInfo<T>;

typedef NavigationState = ({
bool isStackPoppable,
NavBarEnum activeTab,
});

@riverpod
@Riverpod(keepAlive: true)
class NavigationController extends _$NavigationController {
final navigatorKey = GlobalKey<AutoRouterState>();

Expand All @@ -25,15 +25,8 @@ class NavigationController extends _$NavigationController {
Iterable<TRoute> get _stack =>
_router?.stackData.map((e) => e.route.toPageRouteInfo()) ?? [];

Future<void> push(TRoute route) async {
final popFutureResults = _router?.push(route); // push the route
await Future.delayed(
Duration.zero,
refreshState, // refresh the state after the push
);
// await the route's pop
if (popFutureResults != null) await popFutureResults;
refreshState(); // refresh the state after the pop
Future<T?> push<T>(TRoute<T> route) async {
return _router?.push(route);
}

/// this is called only when you actually **click** in the nav tab bar
Expand All @@ -60,11 +53,17 @@ class NavigationController extends _$NavigationController {
}

void refreshState() {
state = build();
// async func is used to make sure the state is updated after the next frame
Future.microtask(() {
print("last: rebuildd");
state = build();
});
}

@override
NavigationState build() {
final s = _stack.lastWhereOrNull((element) => element.isTabView);
print("last: $s");
return (
isStackPoppable: _stack.length > 1,
activeTab:
Expand Down
51 changes: 51 additions & 0 deletions lib/features/navigator/navigation_observer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import "dart:async";

import "package:auto_route/auto_route.dart";
import "package:flutter/widgets.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:riverpod_annotation/riverpod_annotation.dart";

import "navigation_controller.dart";

part "navigation_observer.g.dart";

/// so this just listens to navigation events and notifies the [NavigationController] to refresh its state
/// we do not even use all of these callbacks, but they're for future-proofing
class _NavigationObserver extends AutoRouterObserver {
final Ref ref;

_NavigationObserver(this.ref);

void _notifyController() {
ref.read(navigationControllerProvider.notifier).refreshState();
}

@override
void didPush(Route route, Route? previousRoute) {
_notifyController();
super.didPush(route, previousRoute);
}

@override
void didPop(Route route, Route? previousRoute) {
_notifyController();
super.didPop(route, previousRoute);
}

@override
void didRemove(Route route, Route? previousRoute) {
_notifyController();
super.didRemove(route, previousRoute);
}

@override
void didReplace({Route? newRoute, Route? oldRoute}) {
_notifyController();
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
}
}

@riverpod
AutoRouterObserver navigationObserver(NavigationObserverRef ref) {
return _NavigationObserver(ref);
}
4 changes: 4 additions & 0 deletions lib/features/navigator/root_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "package:flutter_riverpod/flutter_riverpod.dart";

import "../bottom_nav_bar/bottom_nav_bar.dart";
import "navigation_controller.dart";
import "navigation_observer.dart";
import "utils/android_pop_bug_workaround.dart";

@RoutePage()
Expand All @@ -21,6 +22,9 @@ class RootView extends ConsumerWidget {
body: AutoRouter(
// this widget act as nested [Navigator] for the app
key: ref.watch(navigationControllerProvider.notifier).navigatorKey,
navigatorObservers: () => [
ref.watch(navigationObserverProvider),
],
),
bottomNavigationBar: const BottomNavBar(),
),
Expand Down
11 changes: 11 additions & 0 deletions lib/features/navigator/utils/no_transition_route.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import "package:auto_route/auto_route.dart";

class NoTransitionRoute extends CustomRoute {
NoTransitionRoute({
required super.path,
required super.page,
}) : super(
reverseDurationInMilliseconds: 0,
durationInMilliseconds: 0,
);
}
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ dependencies:
html: ^0.15.4
google_maps_flutter_android: ^2.12.0
google_maps_flutter_platform_interface: ^2.8.0
auto_route: ^8.3.0
auto_route: ^9.2.2
separate: ^1.0.3
fast_immutable_collections: ^10.2.4
anim_search_bar:
Expand Down Expand Up @@ -89,7 +89,7 @@ dev_dependencies:
graphql_codegen: ^0.14.0
flutter_gen_runner: ^5.6.0
total_lints: ^3.4.0
auto_route_generator: ^8.1.0
auto_route_generator: ^9.0.0
svg_optimizer: ^0.0.1+1

dependency_overrides:
Expand Down

0 comments on commit a492cf7

Please sign in to comment.