### ZenRouter Example Project Setup and Build Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter_file_generator/README.md Provides command-line instructions to set up and build the example project for ZenRouter. This includes navigating to the example directory, fetching dependencies, running the build runner, and starting the Flutter application. ```bash cd example flutter pub get dart run build_runner build flutter run ``` -------------------------------- ### Install ZenRouter Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Add the zenrouter package to your project's pubspec.yaml file and run 'flutter pub get' to install it. ```yaml dependencies: zenrouter: ^0.1.0 # Check pub.dev for latest version ``` ```bash flutter pub get ``` -------------------------------- ### Basic AppCoordinator Setup for MaterialApp (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Illustrates a minimal setup for an AppCoordinator to be used with MaterialApp.router. It defines how to parse URIs into HomeRoute and ProfileRoute, with a fallback for other paths. ```dart class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => HomeRoute(), ['profile'] => ProfileRoute(), _ => NotFoundRoute(), }; } } MaterialApp.router( routerDelegate: coordinator.routerDelegate, routeInformationParser: coordinator.routeInformationParser, ) ``` -------------------------------- ### Example HomeRoute Implementing RouteUnique (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Provides an example of a HomeRoute class that extends RouteTarget and mixes in RouteUnique. It implements the toUri method to return the root path and the build method to render a simple Scaffold with a welcome message. ```dart class HomeRoute extends RouteTarget with RouteUnique { @override Uri toUri() => Uri.parse('/'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: const Center(child: Text('Welcome!')), ); } } ``` -------------------------------- ### Setup AppCoordinator and parseRouteFromUri Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Demonstrates the basic structure of an AppCoordinator class that extends Coordinator and overrides the parseRouteFromUri method to convert URIs to AppRoute objects. ```dart /// file: lib/routes/coordinator.dart import 'app_route.dart'; class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { ... } } ``` -------------------------------- ### Basic Routing: go_router Example (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/migration/from-go-router.md Demonstrates a basic routing setup using go_router in Dart. It defines routes with path strings and shows how to navigate using context.go and context.push. ```dart final router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const HomePage(), ), GoRoute( path: '/products/:id', builder: (context, state) { final id = state.pathParameters['id']!; return ProductPage(id: id); }, ), GoRoute( path: '/profile', builder: (context, state) => const ProfilePage(), ), ], ); // In MaterialApp MaterialApp.router( routerConfig: router, ); // Navigation context.go('/products/123'); context.push('/profile'); ``` -------------------------------- ### Navigate with Coordinator Methods Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Provides examples of basic navigation actions using the ZenRouter Coordinator in Dart. It shows how to push a new route onto the navigation stack, pop the current route, and replace the entire navigation stack with a new route. ```dart // Push a route coordinator.push(ProfileRoute()); // Pop back coordinator.pop(); // Replace stack coordinator.replace(HomeRoute()); ``` -------------------------------- ### Dart Auth Flow Navigation Example Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter_file_generator/README.md Provides an example of managing authentication flow using ZenRouter's navigation methods. It demonstrates checking login status on app start and navigating accordingly using replace and recover. ```dart // On app start - check auth and recover appropriate state if (isLoggedIn) { coordinator.recoverIndex(); // Restore to home with full stack } else { coordinator.replaceLogin(); // Show login, no back navigation } // After successful login coordinator.replaceIndex(); // Replace login with home // User taps profile coordinator.pushProfileId('current-user'); // Can go back to home ``` -------------------------------- ### Mixing Navigation Paradigms Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Illustrates how to combine different navigation paradigms within a single Flutter application using ZenRouter. It shows examples of using the Coordinator for main navigation, declarative navigation for tab bars, and imperative navigation for modal flows. ```dart // Use coordinator for main navigation (deep linking) class AppCoordinator extends Coordinator { ... } // Use declarative for a tab bar (state-driven) NavigationStack.declarative( routes: [ for (final tab in tabs) TabRoute(tab), ], resolver: resolver, ) // Use imperative for a modal flow (event-driven) final modalPath = NavigationPath.create(); modalPath.push(Step1Route()); ``` -------------------------------- ### Implement NavigationStack Layout (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Example of creating a HomeLayout using RouteLayout for NavigationStack style navigation. It defines the path using `homeStack` and builds a Scaffold with an AppBar. Routes like DetailRoute can specify HomeLayout as their parent layout. ```dart class HomeLayout extends AppRoute with RouteLayout { @override NavigationPath resolvePath(AppCoordinator coordinator) => coordinator.homeStack; @override Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: buildPath(coordinator), ); } } // Routes specify layout using Type reference class DetailRoute extends AppRoute { @override Type? get layout => HomeLayout; } // Register in Coordinator class AppCoordinator extends Coordinator { @override void defineLayout() { RouteLayout.defineLayout(HomeLayout, () => HomeLayout()); } } ``` -------------------------------- ### Complete ZenRouter Application Example Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/api/coordinator.md A full example showcasing the definition of custom AppRoute, HomeRoute, and ProfileRoute, along with an AppCoordinator and main application setup using MaterialApp.router. This demonstrates a typical ZenRouter integration. ```dart // Define routes sealed class AppRoute extends RouteTarget with RouteUnique {} class HomeRoute extends AppRoute { @override Uri toUri() => Uri.parse('/'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () => coordinator.push(ProfileRoute()), child: const Text('Go to Profile'), ), ), ); } } class ProfileRoute extends AppRoute { @override Uri toUri() => Uri.parse('/profile'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile')), body: const Center(child: Text('Profile Page')), ); } } // Create coordinator class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => HomeRoute(), ['profile'] => ProfileRoute(), _ => HomeRoute(), }; } } // Use in app void main() { runApp(const MyApp()); } final coordinator = AppCoordinator(); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerDelegate: coordinator.routerDelegate, routeInformationParser: coordinator.routeInformationParser, ); } } ``` -------------------------------- ### Dart Route Setup with Query Parameters Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/query-parameters.md Demonstrates how to set up a Dart route using the RouteQueryParameters mixin. This involves extending a base route class and initializing a ValueNotifier for query parameters. It requires the route to also implement RouteUnique. ```dart import 'package:zenrouter/zenrouter.dart'; // Example implementation class CollectionListRoute extends AppRoute with RouteQueryParameters { @override late final ValueNotifier> queryNotifier; CollectionListRoute({Map queries = const {}}) : queryNotifier = ValueNotifier(queries); // ... other route implementation } ``` -------------------------------- ### auto_route Basic Routing Example Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/migration/from-auto-route.md This Dart code demonstrates a basic routing setup using `auto_route`. It defines `HomePage` and `ProductPage` with annotations and configures the `AppRouter` for navigation. This serves as a reference for the migration process. ```dart // Route definition with annotation @RoutePage() class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: ElevatedButton( onPressed: () { context.router.push(ProductRoute(id: '123')); }, child: const Text('Go to Product'), ), ), ); } } @RoutePage() class ProductPage extends StatelessWidget { final String id; const ProductPage({ super.key, @PathParam('id') required this.id, }); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Product $id')), body: Center(child: Text('Viewing product: $id')), ); } } // Router configuration @AutoRouterConfig() class AppRouter extends RootStackRouter { @override List get routes => [ AutoRoute(page: HomeRoute.page, initial: true), AutoRoute(page: ProductRoute.page, path: '/products/:id'), ]; } // In main.dart final _appRouter = AppRouter(); MaterialApp.router( routerConfig: _appRouter.config(), ); ``` -------------------------------- ### Implement Custom Deep Link Strategy (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Example of a ProductRoute implementing RouteDeepLink with the 'custom' strategy. The `deeplinkHandler` method includes logic to navigate to a specific tab, load product data, push the product route, and log analytics. ```dart class ProductRoute extends AppRoute with RouteDeepLink { final String productId; ProductRoute(this.productId); @override Uri toUri() => Uri.parse('/product/$productId'); @override DeeplinkStrategy get deeplinkStrategy => DeeplinkStrategy.custom; @override Future deeplinkHandler(AppCoordinator coordinator, Uri uri) async { // Custom logic: ensure we're in the right tab coordinator.replace(ShopTab()); // Load product data final product = await loadProduct(productId); // Then navigate to this route coordinator.push(this); // Log analytics analytics.logDeepLink(uri); } } ``` -------------------------------- ### Complete Example Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/api/coordinator.md A full example demonstrating how to define routes, create a coordinator, and integrate it into a Flutter application. ```APIDOC ## Complete Example ### Description This example shows the complete setup for routes, coordinator, and application integration. ### Code ```dart // Define routes sealed class AppRoute extends RouteTarget with RouteUnique {} class HomeRoute extends AppRoute { @override Uri toUri() => Uri.parse('/'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () => coordinator.push(ProfileRoute()), child: const Text('Go to Profile'), ), ), ); } } class ProfileRoute extends AppRoute { @override Uri toUri() => Uri.parse('/profile'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile')), body: const Center(child: Text('Profile Page')), ); } } // Create coordinator class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => HomeRoute(), ['profile'] => ProfileRoute(), _ => HomeRoute(), }; } } // Use in app void main() { runApp(const MyApp()); } final coordinator = AppCoordinator(); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerDelegate: coordinator.routerDelegate, routeInformationParser: coordinator.routeInformationParser, ); } } ``` ``` -------------------------------- ### Dart Multi-Step Deep Link Setup with RouteDeepLink Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/api/mixins.md An example of implementing a product detail route using RouteDeepLink with a 'custom' strategy. It demonstrates a multi-step deep link flow involving navigating to a tab, loading data, navigating to a category, and then the product detail, followed by analytics tracking. ```dart class ProductDetailRoute extends RouteTarget with RouteUnique, RouteDeepLink { final String productId; ProductDetailRoute(this.productId); @override Uri toUri() => Uri.parse('/product/$productId'); @override DeeplinkStrategy get deeplinkStrategy => DeeplinkStrategy.custom; @override Future deeplinkHandler( AppCoordinator coordinator, Uri uri, ) async { // Step 1: Navigate to the correct tab coordinator.replace(ShopTab()); // Step 2: Load product data asynchronously final product = await productService.loadProduct(productId); // Step 3: Navigate to category if available if (product.category != null) { coordinator.push(CategoryRoute(product.category!)); } // Step 4: Finally navigate to the product detail coordinator.push(this); // Step 5: Track deep link analytics analytics.logDeepLink(uri, { 'product_id': productId, 'source': uri.queryParameters['source'], }); } @override Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Product $productId')), body: ProductDetailView(productId: productId), ); } } ``` -------------------------------- ### Implement Indexed Navigation Layout (Tabs) (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Example of creating a TabLayout using RouteLayout for an indexed navigation layout (like tabs). It resolves the path using `tabPath` and builds a Scaffold with a BottomNavigationBar. Tab routes specify TabLayout as their layout. ```dart class TabLayout extends AppRoute with RouteLayout { @override IndexedStackPath resolvePath(AppCoordinator coordinator) => coordinator.tabPath; @override Widget build(AppCoordinator coordinator, BuildContext context) { final path = coordinator.tabPath; return Scaffold( body: buildPath(coordinator), bottomNavigationBar: BottomNavigationBar( currentIndex: path.activePathIndex, onTap: (index) => coordinator.push(tabs[index]), items: [...], ), ); } } // Tab routes use Type reference class HomeTab extends AppRoute { @override Type? get layout => TabLayout; } ``` -------------------------------- ### Implement Custom Deep Link Strategy for Checkout (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Example of a CheckoutRoute using the 'custom' deep link strategy. The handler checks for user login, sets up the navigation stack by replacing the current route and pushing others, and tracks analytics. ```dart class CheckoutRoute extends AppRoute with RouteDeepLink { @override DeeplinkStrategy get deeplinkStrategy => DeeplinkStrategy.custom; @override Future deeplinkHandler(AppCoordinator coordinator, Uri uri) async { // 1. Ensure user is logged in if (!await auth.isLoggedIn()) { coordinator.replace(LoginRoute( redirectTo: uri.toString(), )); return; } // 2. Set up the navigation stack coordinator.replace(HomeRoute()); coordinator.push(CartRoute()); coordinator.push(this); // 3. Track analytics analytics.logDeepLink(uri); } } ``` -------------------------------- ### Parse URIs to Routes in AppCoordinator (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Shows how to implement the parseRouteFromUri method within an AppCoordinator to map different URI path segments to specific application routes. This example handles the root path, 'post', 'post/{id}', 'profile', 'settings', and a fallback for not found routes. ```dart class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => IndexRoute(), ['post'] => PostList(), ['post', final id] => PostDetail(id: id), ['profile'] => Profile(), ['settings'] => Settings(), _ => NotFoundRoute(uri: uri), }; } } ``` -------------------------------- ### Install Application Executable Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter_docs/linux/CMakeLists.txt Installs the main application executable to the root of the installation prefix. This makes the binary available in the installed bundle. ```cmake install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) ``` -------------------------------- ### Recipe: Multi-Step Form with Imperative Navigation Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Provides a recipe for implementing multi-step forms in Flutter using ZenRouter's imperative navigation. It demonstrates how to chain navigation steps by pushing subsequent form steps onto a `NavigationPath` after passing updated form data from one step to the next. ```dart // Step 1 path.push(PersonalInfoStep(data: FormData())); // Step 2 (in PersonalInfoStep) path.push(PreferencesStep(data: updatedData)); // Step 3 (in PreferencesStep) path.push(ReviewStep(data: updatedData)); ``` -------------------------------- ### Use MaterialApp.router with Coordinator Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Demonstrates how to integrate ZenRouter's Coordinator with Flutter's `MaterialApp.router`. This setup involves providing the coordinator's `routerDelegate` and `routeInformationParser` to the `MaterialApp.router` widget, enabling deep linking and web URL support. ```dart void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerDelegate: coordinator.routerDelegate, routeInformationParser: coordinator.routeInformationParser, ); } } ``` -------------------------------- ### Clean Build Bundle Directory on Install Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter_docs/linux/CMakeLists.txt An installation rule that removes the build bundle directory before installation. This ensures a clean installation by starting with an empty directory. ```cmake install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) ``` -------------------------------- ### ZenRouter Quick Examples (Dart) Source: https://github.com/definev/zenrouter/blob/main/README.md Demonstrates the basic usage of ZenRouter across its three paradigms: Imperative for direct navigation control, Declarative for state-driven routing, and Coordinator for handling deep links and web URIs. ```dart // Imperative: Direct control final path = NavigationPath.create(); path.push(ProfileRoute()); // Declarative: State-driven NavigationStack.declarative( routes: [ for (final page in pages) PageRoute(page), ], resolver: (route) => StackTransition.material(...), ) // Coordinator: Web & deep linking class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) => ...; } ``` -------------------------------- ### Create Home and PostDetail Routes in Dart Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Illustrates how to create concrete route classes, Home and PostDetail, by extending the abstract AppRoute. Home has no parameters, while PostDetail includes a required 'id' parameter and overrides 'props' for correct equality checks. ```dart /// file: lib/routes/app_route.dart class Home extends AppRoute { Uri toUri() => Uri.parse('/'); Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: Center( child: FilledButton( onPressed: () => coordinator.push(PostDetail(id: 1)), child: const Text('Go to Post Detail'), ), ), ); } } class PostDetail extends AppRoute { PostDetail({ required this.id, }); final String id; /// If the params has involved in `toUri` function, you must add it to `props` List get props => [id]; Uri toUri() => Uri.parse('/post/$id'); Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Post $id Detail'), ), body: Center( child: Text('Post ID: $id'), ), ); } } ``` -------------------------------- ### Handling Root Path Redirection Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Demonstrates how to use the `RouteRedirect` mixin to redirect the root path '/' to a specific route, such as `PostList`. ```APIDOC ### Handling Root Path Sometimes you want to redirect the root path `/` to a specific route, like `PostList`. You can use `RouteRedirect` mixin to achieve this. ```dart class IndexRoute extends AppRoute with RouteRedirect { @override Uri toUri() => Uri.parse('/'); @override FutureOr redirect() { return PostList(); } @override Widget build(AppCoordinator coordinator, BuildContext context) { return const SizedBox.shrink(); } } ``` Now let's update `parseRouteFromUri`: ```dart class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => IndexRoute(), ['post'] => PostList(), ['post', final id] => PostDetail(id: id), ['profile'] => Profile(), ['settings'] => Settings(), _ => NotFoundRoute(uri: uri), }; } } ``` ``` -------------------------------- ### Create Flutter Project with ZenRouter Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Commands to create a new Flutter project and add the zenrouter dependency. This sets up the basic structure for using ZenRouter. ```bash flutter create --empty coordinator_example cd coordinator_example ``` -------------------------------- ### Example: AnalyticsObserver for didPush Event (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/navigator-observers.md This example defines a custom NavigatorObserver, AnalyticsObserver, that logs screen view events. It overrides the didPush method to print a message to the console when a new route is pushed onto the navigator. This observer can then be integrated into the AppCoordinator. ```dart class AnalyticsObserver extends NavigatorObserver { @override void didPush(Route route, Route? previousRoute) { print('Analytics: User navigated to ${route.settings.name}'); } } class AppCoordinator extends Coordinator with CoordinatorNavigatorObserver { @override List get observers => [AnalyticsObserver()]; // ... } ``` -------------------------------- ### Test Deep Links on Android Emulator (Bash) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Command to test deep links on an Android emulator using `adb`. This command starts an activity to view a specific URI, with your application's package name. ```bash adb shell am start -W -a android.intent.action.VIEW \ -d "myapp://home/feed/123" com.example.myapp ``` -------------------------------- ### Test Deep Links on iOS Simulator (Bash) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Command to test deep links on an iOS Simulator using `simctl`. This command opens a specified URL in the booted simulator. ```bash xcrun simctl openurl booted "myapp://home/feed/123" ``` -------------------------------- ### Declarative Route Definition with Equality Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Define declarative routes by extending 'RouteTarget' and implementing the 'props' getter. This is crucial for Myers diff algorithm to efficiently update the UI. ```dart import 'package:zenrouter/zenrouter.dart'; class PageRoute extends RouteTarget { final int pageNumber; PageRoute(this.pageNumber); // IMPORTANT: Implement equality for Myers diff! @override List get props => [pageNumber]; } ``` -------------------------------- ### Imperative Navigation Actions Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Perform navigation actions like navigating to a route, pushing a new route, popping the current route, or replacing the entire navigation stack. ```dart // Navigate to a specific route (Pop to the route if it's already in the stack or push it otherwise) path.navigate(ProfileRoute()); // Push a route path.push(ProfileRoute()); // Pop back path.pop(); // Replace entire stack path.replace([HomeRoute()]); ``` -------------------------------- ### Coordinator API Reference - Quick Reference Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Provides a quick overview of the methods and properties available for the Coordinator class in ZenRouter. ```APIDOC ## Coordinator API Reference ### Methods | Method | Description | |---|---| | `parseRouteFromUri(Uri)` | Abstract method to parse URLs into routes | | `push(T)` | Push route onto appropriate path | | `pop()` | Pop from nearest dynamic path | | `replace(T)` | Wipe stack and replace with route | | `pushOrMoveToTop(T)` | Push or move route to top | | `recoverRouteFromUri(Uri)` | Handle deep link URI | ### Properties | Property | Description | |---|---| | `root` | Main navigation path (always present) | | `paths` | All navigation paths managed by coordinator | | `routerDelegate` | Router delegate for MaterialApp.router | | `routeInformationParser` | Route information parser | ### Example ```dart class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => HomeRoute(), ['profile'] => ProfileRoute(), _ => NotFoundRoute(), }; } } MaterialApp.router( routerDelegate: coordinator.routerDelegate, routeInformationParser: coordinator.routeInformationParser, ) ``` ``` -------------------------------- ### Imperative Navigation Path and Rendering Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Create a NavigationPath instance and use NavigationStack to render your application. The resolver function maps routes to stack transitions, and the defaultRoute is displayed initially. ```dart final path = NavigationPath.create(); void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: NavigationStack( path: path, defaultRoute: HomeRoute(), resolver: (route) => StackTransition.material( route.build(context), ), ), ); } } ``` -------------------------------- ### Basic Route Setup with Dart Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/api/mixins.md Demonstrates how to set up basic routes using Dart with ZenRouter. It includes defining a base route class, concrete route implementations for Home and Profile, and a coordinator to parse URIs into routes. ```dart abstract class AppRoute extends RouteTarget with RouteUnique {} class HomeRoute extends AppRoute { @override Uri toUri() => Uri.parse('/'); @override Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () => coordinator.push(ProfileRoute()), child: const Text('Go to Profile'), ), ), ); } } class ProfileRoute extends AppRoute { @override Uri toUri() => Uri.parse('/profile'); @override Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile')), body: const Center(child: Text('Profile Page')), ); } } class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => HomeRoute(), ['profile'] => ProfileRoute(), _ => NotFoundRoute(), }; } } ``` -------------------------------- ### Imperative Route Definition Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Define your application routes by extending the 'RouteTarget' class and implementing a 'build' method to return the corresponding Widget. Ensure routes are sealed classes for type safety. ```dart import 'package:zenrouter/zenrouter.dart'; // Base class sealed class AppRoute extends RouteTarget { Widget build(BuildContext context); } class HomeRoute extends AppRoute { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () => path.push(ProfileRoute()), child: const Text('Go to Profile'), ), ), ); } } class ProfileRoute extends AppRoute { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile')), body: const Center(child: Text('Profile Page')), ); } } ``` -------------------------------- ### Configure AppCoordinator Layouts (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Sets up the `AppCoordinator` by defining layout mappings using `RouteLayout.defineLayout`. This associates specific `RouteLayout` types with their corresponding factory functions for instantiation. ```dart /// file: lib/routes/coordinator.dart class AppCoordinator extends Coordinator { // ... other properties ... @override void defineLayout() { RouteLayout.defineLayout(HomeLayout, HomeLayout.new); RouteLayout.defineLayout(FeedLayout, FeedLayout.new); RouteLayout.defineLayout(ProfileLayout, ProfileLayout.new); } // ... rest of the class ... } ``` -------------------------------- ### Implement Push Deep Link Strategy (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Demonstrates implementing the 'push' deep link strategy. When a deep link is received for a route with this strategy, the route is pushed onto the current navigation stack, preserving the existing routes. ```dart class MyRoute extends AppRoute with RouteDeepLink { @override DeeplinkStrategy get deeplinkStrategy => DeeplinkStrategy.push; } ``` -------------------------------- ### Implement Protected Routes with Authentication Flow (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md This recipe demonstrates how to create protected routes that redirect unauthenticated users to a login page. It utilizes the `RouteRedirect` mixin to check authentication status before allowing access to a route. ```dart class ProtectedRoute extends AppRoute with RouteRedirect { @override Future redirect() async { final isAuthed = await auth.check(); return isAuthed ? ProtectedRoute() : LoginRoute(); } } ``` -------------------------------- ### Dart Programmatically Updating Route Query Parameters Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/query-parameters.md Provides examples in Dart for updating query parameters using the updateQueries method. This method not only updates the internal queryNotifier for UI rebuilds but also synchronizes the browser URL. ```dart // Update 'page' to 2, keeping other existing queries updateQueries( coordinator, queries: {...queries, 'page': '2'}, ); // clear all and set 'filter' to 'active' updateQueries( coordinator, queries: {'filter': 'active'}, ); ``` -------------------------------- ### Per-Tab Navigation Stacks Example Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/recipes/bottom-navigation.md This advanced example shows how to create separate `NavigationPath` instances for each tab, allowing for independent navigation stacks within each tab. It then integrates these into an `IndexedStackPath`. ```dart class AppCoordinator extends Coordinator { // Separate NavigationPath for each tab late final homeStack = NavigationPath.createWith( coordinator: this, label: 'home', ); late final searchStack = NavigationPath.createWith( coordinator: this, label: 'search', ); late final profileStack = NavigationPath.createWith( coordinator: this, label: 'profile', ); late final tabPath = IndexedStackPath.createWith( coordinator: this, label: 'tab', [ HomeTabRoute(), SearchTabRoute(), ProfileTabRoute(), ], ); int _currentTab = 0; @override List> get paths => [ ...super.paths, tabPath, homeStack, searchStack, profileStack, ]; void switchToTab(int index) { _currentTab = index; tabPath.activeIndex = index; } } ``` -------------------------------- ### Implement HomeLayout with Navigation in Dart Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Implements the HomeLayout class, extending AppRoute and RouteLayout. It defines how to resolve the navigation path using the coordinator and builds the scaffold for the home view, including a BottomNavigationBar for switching between feed and profile sections. ```dart /// file: lib/routes/app_route.dart class HomeLayout extends AppRoute with RouteLayout { @override IndexedStackPath resolvePath(AppCoordinator coordinator) => coordinator.homeIndexed; Widget build(AppCoordinator coordinator, BuildContext context) { final path = resolvePath(coordinator); return Scaffold( body: buildPath(coordinator), bottomNavigationBar: BottomNavigationBar( items: [ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.person), label: 'Profile', ``` -------------------------------- ### Nested Routes: go_router ShellRoute Example (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/migration/from-go-router.md Illustrates how to implement nested routes and layouts using go_router's ShellRoute in Dart. This setup allows for a persistent UI structure, like a navigation bar, across different child routes. ```dart GoRouter( routes: [ ShellRoute( builder: (context, state, child) { return ScaffoldWithNav(child: child); }, routes: [ GoRoute( path: '/home', builder: (context, state) => const HomePage(), ), GoRoute( path: '/search', builder: (context, state) => const SearchPage(), ), ], ), ], ); ``` -------------------------------- ### Create Coordinator for Route Parsing Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Illustrates the creation of a custom Coordinator in Dart for ZenRouter. This `AppCoordinator` class extends `Coordinator` and implements the `parseRouteFromUri` method to map incoming URIs to specific `AppRoute` instances, including a fallback for not found routes. ```dart class AppCoordinator extends Coordinator { @override AppRoute parseRouteFromUri(Uri uri) { return switch (uri.pathSegments) { [] => HomeRoute(), ['profile'] => ProfileRoute(), _ => NotFoundRoute(), }; } } final coordinator = AppCoordinator(); ``` -------------------------------- ### Inject Global Observers via Constructor (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/navigator-observers.md This example illustrates how to inject NavigatorObservers from outside the Coordinator, useful for testing or dependency injection. It utilizes the NavigatorObserverListGetter typedef to allow passing a function that returns the observer list when creating the coordinator. ```dart class AppCoordinator extends Coordinator with CoordinatorNavigatorObserver { AppCoordinator({ NavigatorObserverListGetter observers = kEmptyNavigatorObserverList, }) : _observersGetter = observers; final NavigatorObserverListGetter _observersGetter; @override List get observers => _observersGetter(); // ... } // Example usage: final coordinator = AppCoordinator( observers: () => [ FirebaseAnalyticsObserver(...), SentryNavigatorObserver(), ], ); ``` -------------------------------- ### Initialize Navigation Paths in AppCoordinator (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Initializes various navigation paths within the `AppCoordinator`, including `homeIndexed`, `feedNavigation`, and `profileNavigation`. It also defines the list of `paths` for the coordinator. ```dart class AppCoordinator extends Coordinator { final homeIndexed = IndexedStackPath( routes: [ FeedLayout(), ProfileLayout(), ], ); late final feedNavigation = NavigationPath.createWith( coordinator: this, label: 'feed', ); late final profileNavigation = NavigationPath.createWith( coordinator: this, label: 'profile', ); @override List> get paths => [ root, homeIndexed, feedNavigation, profileNavigation, ]; // ... rest of the class ... } ``` -------------------------------- ### Define Custom Deep Link Handling with RouteDeepLink (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md The RouteDeepLink mixin allows for custom deep link handling. It provides the `deeplinkStrategy` enum (replace, push, custom) and the `deeplinkHandler` method for custom logic. This example shows a ProductRoute with a custom strategy. ```dart mixin RouteDeepLink on RouteUnique { // Strategy for handling deep links DeeplinkStrategy get deeplinkStrategy; // Custom deep link handler Future deeplinkHandler(Coordinator coordinator, Uri uri); } enum DeeplinkStrategy { replace, // Replace current stack (default) push, // Push onto current stack custom, // Use custom handler } ``` -------------------------------- ### Handle Deep Linking with Custom Strategy (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md This recipe shows how to implement deep linking for specific routes using a custom strategy. It includes handling analytics logging and managing the navigation stack to display the relevant content upon receiving a deep link. ```dart class ProductRoute extends AppRoute with RouteDeepLink { // Use custom deeplink strategy @override DeeplinkStrategy get deeplinkStrategy => DeeplinkStrategy.custom; @override Future deeplinkHandler(Coordinator coordinator, Uri uri) async { // Track analytics analytics.logDeepLink(uri); // Set up navigation stack coordinator.replace(ShopTab()); coordinator.push(this); } } ``` -------------------------------- ### Define Routes with RouteUnique for Coordinator Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/guides/getting-started.md Shows how to define unique routes for the Coordinator pattern in ZenRouter using Dart. Each route extends `AppRoute` (which implements `RouteTarget` and `RouteUnique`) and provides a `toUri` method to define its URI and a `build` method to construct the corresponding UI widget. ```dart import 'package:zenrouter/zenrouter.dart'; abstract class AppRoute extends RouteTarget with RouteUnique {} class HomeRoute extends AppRoute { @override Uri toUri() => Uri.parse('/'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () => coordinator.push(ProfileRoute()), child: const Text('Go to Profile'), ), ), ); } } class ProfileRoute extends AppRoute { @override Uri toUri() => Uri.parse('/profile'); @override Widget build(Coordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile')), body: const Center(child: Text('Profile Page')), ); } } ``` -------------------------------- ### Define Profile and Settings Routes (Dart) Source: https://github.com/definev/zenrouter/blob/main/packages/zenrouter/doc/paradigms/coordinator/coordinator.md Defines the `Profile` and `Settings` routes, specifying their layout as `ProfileLayout`. The `Profile` route displays user information and a link to settings, while `Settings` shows a simple text view. ```dart class Profile extends AppRoute { Uri toUri() => Uri.parse('/profile'); /// `ProfileView` will be rendered inside `ProfileLayout` Type? get layout => ProfileLayout; Widget build(AppCoordinator coordinator, BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile')), body: ListView( children: [ const ListTile(title: Text('Hello, User')), ListTile( title: const Text('Open Settings'), onTap: () => coordinator.push(Settings()), trailing: const Icon(Icons.chevron_right), ), ], ), ); } } class Settings extends AppRoute { Uri toUri() => Uri.parse('/settings'); /// `SettingsView` will be rendered inside `ProfileLayout` Type? get layout => ProfileLayout; Widget build(AppCoordinator coordinator, BuildContext context) { return const Center( child: Text('Settings View'), ); } } ```