zenrouter_devtools 0.4.0 copy "zenrouter_devtools: ^0.4.0" to clipboard
zenrouter_devtools: ^0.4.0 copied to clipboard

Deeplink, Inspection, and Debugging Devtools for ZenRouter

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:zenrouter/zenrouter.dart';
import 'package:zenrouter_devtools/zenrouter_devtools.dart';

void main() {
  runApp(MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: appCoordinator.routerDelegate,
      routeInformationParser: appCoordinator.routeInformationParser,
    );
  }
}

final appCoordinator = AppCoordinator();

abstract class AppRoute extends RouteTarget with RouteUnique {}

class CustomLayout extends AppRoute with RouteLayout<AppRoute> {
  @override
  StackPath<RouteUnique> resolvePath(AppCoordinator coordinator) =>
      coordinator.customIndexed;

  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    final path = resolvePath(coordinator);
    final size = MediaQuery.sizeOf(context);
    return Scaffold(
      body: switch (size.width) {
        < 600 => Column(
          children: [
            Expanded(child: buildPath(coordinator)),
            Container(
              height: 60,
              color: Colors.yellow,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  ElevatedButton(
                    child: Text('One'),
                    onPressed: () => coordinator.push(FirstLayout()),
                  ),
                  ElevatedButton(
                    child: Text('Two'),
                    onPressed: () => coordinator.push(SecondTab()),
                  ),
                  ElevatedButton(
                    child: Text('Three'),
                    onPressed: () => coordinator.push(ThirdTab()),
                  ),
                ],
              ),
            ),
          ],
        ),
        _ => Column(
          children: [
            Expanded(
              child: switch (path.activeRoute) {
                ThirdTab() => path.activeRoute!.build(coordinator, context),
                _ => Row(
                  children: [
                    Expanded(child: path.stack[0].build(coordinator, context)),
                    VerticalDivider(width: 1, color: Colors.amber),
                    Expanded(child: path.stack[1].build(coordinator, context)),
                  ],
                ),
              },
            ),
            Container(
              height: 60,
              color: Colors.yellow,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  ElevatedButton(
                    child: Text('One/Two'),
                    onPressed: () {
                      if (path.activeRoute is FirstLayout) {
                        coordinator.push(SecondTab());
                      } else {
                        coordinator.push(FirstLayout());
                      }
                    },
                  ),
                  ElevatedButton(
                    child: Text('Three'),
                    onPressed: () => coordinator.push(ThirdTab()),
                  ),
                ],
              ),
            ),
          ],
        ),
      },
    );
  }
}

class FirstLayout extends AppRoute with RouteLayout {
  @override
  Uri toUri() => Uri.parse('/first');

  @override
  Type get layout => CustomLayout;

  @override
  NavigationPath<AppRoute> resolvePath(AppCoordinator coordinator) =>
      coordinator.firstStack;
}

class FirstTab extends AppRoute {
  @override
  Uri toUri() => Uri.parse('/first');

  @override
  Type get layout => FirstLayout;

  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    final activeIndex = coordinator.customIndexed.activeIndex;
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          spacing: 8,
          children: [
            Text(
              'First page ${activeIndex == 0 ? '(Focused)' : '(No focused)'}',
            ),
            FilledButton(
              onPressed: () =>
                  coordinator.push(FirstTabChild(message: "Hello")),
              child: Text('Go "Hello"'),
            ),
            FilledButton(
              onPressed: () => coordinator.push(FirstTabChild(message: "Ciao")),
              child: Text('Go "Ciao"'),
            ),
          ],
        ),
      ),
    );
  }
}

class FirstTabChild extends AppRoute {
  FirstTabChild({required this.message});

  final String message;

  @override
  Uri toUri() => Uri.parse('/first/$message');

  @override
  Type get layout => FirstLayout;

  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('First Message: $message'),
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text('Go back'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  List<Object?> get props => [message];
}

class SecondTab extends AppRoute {
  @override
  Uri toUri() => Uri.parse('/second');

  @override
  Type get layout => CustomLayout;

  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    final activeIndex = coordinator.customIndexed.activeIndex;
    return Scaffold(
      backgroundColor: Colors.red.shade100,
      body: Center(
        child: Text(
          'Second tab (${activeIndex == 1 ? 'Focused' : 'No focused'})',
        ),
      ),
    );
  }
}

class ThirdTab extends AppRoute {
  @override
  Uri toUri() => Uri.parse('/third');

  @override
  Type get layout => CustomLayout;

  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    final activeIndex = coordinator.customIndexed.activeIndex;
    return Scaffold(
      backgroundColor: Colors.blue.shade100,
      body: Center(
        child: Text(
          'Third tab (${activeIndex == 2 ? 'Focused' : 'No focused'})',
        ),
      ),
    );
  }
}

class NotFound extends AppRoute {
  @override
  Uri toUri() => Uri.parse('/not-found');

  @override
  Widget build(AppCoordinator coordinator, BuildContext context) {
    return Scaffold(body: Center(child: Text('Not found')));
  }
}

class AppCoordinator extends Coordinator<AppRoute> with CoordinatorDebug {
  late final customIndexed = IndexedStackPath<AppRoute>.createWith(
    coordinator: this,
    label: 'CustomIndexed',
    [FirstLayout(), SecondTab(), ThirdTab()],
  );
  late final firstStack = NavigationPath<AppRoute>.createWith(
    label: 'FirstStack',
    coordinator: this,
  );

  @override
  List<AppRoute> get debugRoutes => [
    FirstTab(),
    FirstTabChild(message: 'Hello'),
    FirstTabChild(message: 'Ciao'),
    SecondTab(),
    ThirdTab(),
    NotFound(),
  ];

  @override
  List<StackPath<RouteTarget>> get paths => [root, customIndexed, firstStack];

  @override
  void defineLayout() {
    RouteLayout.defineLayout(CustomLayout, CustomLayout.new);
    RouteLayout.defineLayout(FirstLayout, FirstLayout.new);
  }

  @override
  AppRoute parseRouteFromUri(Uri uri) {
    return switch (uri.pathSegments) {
      [] => FirstTab(),
      ['first'] => FirstTab(),
      ['first', final message] => FirstTabChild(message: message),
      ['second'] => SecondTab(),
      ['third'] => ThirdTab(),
      _ => NotFound(),
    };
  }
}
2
likes
160
points
271
downloads

Publisher

verified publisherzennn.dev

Weekly Downloads

Deeplink, Inspection, and Debugging Devtools for ZenRouter

Repository (GitHub)
View/report issues

Topics

#router #navigation #routing #deep-linking #web

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

flutter, zenrouter, zentoast

More

Packages that depend on zenrouter_devtools