Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Web] / [Need help] Navigate with URL should build the full stack #1894

Closed
stefanschaller opened this issue Mar 19, 2024 · 2 comments
Closed

Comments

@stefanschaller
Copy link

stefanschaller commented Mar 19, 2024

I have a HomePage with a AutoTabsRouter and some tabs.

Disclaimer, I found a workaround that works on mobile, but doesn't on Web. Since I need full URL support, this is imporant and need to be fixed.

On top of that is a Settings-Dialog, which should be shown as a dialog with /home/settings

The structure:

       Home 
    /       \
Books      Profile 

The settings dialog could be opened when clicking on the action button in the home and should open the dialog.
The most important thing is, whenever I open the settings directly with the url /home/settings, the navigator needs to build the HomePage + the SettingsDialog.

The current result:

Bildschirmaufnahme.2024-03-18.um.17.53.53.mov

I'm using the following versions:

auto_route: 7.9.0

Flutter 3.19.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ba39319843 (vor 11 Tagen) • 2024-03-07 15:22:21 -0600
Engine • revision 2e4ba9c6fb
Tools • Dart 3.3.1 • DevTools 2.31.1

My code:

main.dart

import 'package:example/mobile/router/router.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _rootRouter = RootRouter();

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _rootRouter.config(),
      theme: ThemeData.dark(),
    );
  }
}

home_page.dart

import 'package:auto_route/auto_route.dart';
import 'package:example/mobile/router/router.gr.dart';
import 'package:flutter/material.dart';

@RoutePage<String>()
class HomePage extends StatefulWidget {
  const HomePage({
    Key? key,
  }) : super(key: key);

  @override
  HomePageState createState() => HomePageState();
}

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
  @override
  Widget build(context) {
    return AutoTabsRouter(
      routes: [
        MyBooksRoute(),
        ProfileRoute(),
      ],
      builder: (context, child) {
        return Scaffold(
          appBar: AppBar(
            title: Text(context.topRoute.title(context)),
            actions: [
              IconButton(
                onPressed: () {
                  AutoRouter.of(context).push(SettingsRoute());
                },
                icon: Icon(Icons.settings),
              )
            ],
            leading: AutoLeadingButton(ignorePagelessRoutes: true),
          ),
          body: child,
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: context.tabsRouter.activeIndex,
            onTap: context.tabsRouter.setActiveIndex,
            items: [
              BottomNavigationBarItem(
                icon: Icon(Icons.source),
                label: 'Books',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.person),
                label: 'Profile',
              ),
            ],
          ),
        );
      },
    );
  }
}

my_books_page.dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';

@RoutePage()
class MyBooksPage extends StatelessWidget {
  MyBooksPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.green);
  }
}

profile_page.dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';

@RoutePage()
class ProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.red);
  }
}

settings_page.dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';

@RoutePage()
class SettingsPage extends StatelessWidget {
  const SettingsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.center,
      child: Container(
        height: 300,
        width: 200,
        color: Colors.redAccent,
        child: IconButton(
          icon: Icon(Icons.close),
          onPressed: () {
            AutoRouter.of(context).popForced();
          },
        ),
      ),
    );
  }
}

router.dart

import 'package:auto_route/auto_route.dart';
import 'package:example/mobile/router/router.gr.dart';
import 'package:flutter/material.dart';

@AutoRouterConfig(generateForDir: ['lib/mobile'])
class RootRouter extends $RootRouter {
  @override
  final List<AutoRoute> routes = [
    AutoRoute(
      page: HomeRoute.page,
      path: '/home',
      initial: true,
      children: [
        AutoRoute(
          path: 'books',
          page: MyBooksRoute.page,
          initial: true,
        ),
        AutoRoute(
          path: 'profile',
          page: ProfileRoute.page,
        ),
        DetailRoute(
          path: 'settings',
          page: SettingsRoute.page,
        ),
      ],
    ),
  ];
}

class DetailRoute extends CustomRoute {
  DetailRoute({
    required super.page,
    required super.path,
    super.guards,
    super.children,
    super.initial,
  }) : super(
          customRouteBuilder: <T>(context, child, page) {
            return _customRouteBuilder<T>(
              context: context,
              child: child,
              page: page,
            );
          },
        );

  static Route<T> _customRouteBuilder<T>({
    required BuildContext context,
    required Widget child,
    required AutoRoutePage<T> page,
  }) {
    return DialogRoute(
      context: context,
      settings: page,
      useSafeArea: false,
      barrierDismissible: false,
      barrierColor: Colors.black.withOpacity(0.35),
      builder: (_) => child,
    );
  }
}

router.gr.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

// **************************************************************************
// AutoRouterGenerator
// **************************************************************************

// ignore_for_file: type=lint
// coverage:ignore-file

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:auto_route/auto_route.dart' as _i5;
import 'package:example/mobile/screens/home_page.dart' as _i1;
import 'package:example/mobile/screens/profile/my_books_page.dart' as _i2;
import 'package:example/mobile/screens/profile/profile_page.dart' as _i3;
import 'package:example/mobile/screens/profile/settings_page.dart' as _i4;
import 'package:flutter/material.dart' as _i6;

abstract class $RootRouter extends _i5.RootStackRouter {
  $RootRouter({super.navigatorKey});

  @override
  final Map<String, _i5.PageFactory> pagesMap = {
    HomeRoute.name: (routeData) {
      return _i5.AutoRoutePage<String>(
        routeData: routeData,
        child: const _i1.HomePage(),
      );
    },
    MyBooksRoute.name: (routeData) {
      final args = routeData.argsAs<MyBooksRouteArgs>(
          orElse: () => const MyBooksRouteArgs());
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: _i2.MyBooksPage(key: args.key),
      );
    },
    ProfileRoute.name: (routeData) {
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: _i3.ProfilePage(),
      );
    },
    SettingsRoute.name: (routeData) {
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: const _i4.SettingsPage(),
      );
    },
  };
}

/// generated route for
/// [_i1.HomePage]
class HomeRoute extends _i5.PageRouteInfo<void> {
  const HomeRoute({List<_i5.PageRouteInfo>? children})
      : super(
          HomeRoute.name,
          initialChildren: children,
        );

  static const String name = 'HomeRoute';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}

/// generated route for
/// [_i2.MyBooksPage]
class MyBooksRoute extends _i5.PageRouteInfo<MyBooksRouteArgs> {
  MyBooksRoute({
    _i6.Key? key,
    List<_i5.PageRouteInfo>? children,
  }) : super(
          MyBooksRoute.name,
          args: MyBooksRouteArgs(key: key),
          initialChildren: children,
        );

  static const String name = 'MyBooksRoute';

  static const _i5.PageInfo<MyBooksRouteArgs> page =
      _i5.PageInfo<MyBooksRouteArgs>(name);
}

class MyBooksRouteArgs {
  const MyBooksRouteArgs({this.key});

  final _i6.Key? key;

  @override
  String toString() {
    return 'MyBooksRouteArgs{key: $key}';
  }
}

/// generated route for
/// [_i3.ProfilePage]
class ProfileRoute extends _i5.PageRouteInfo<void> {
  const ProfileRoute({List<_i5.PageRouteInfo>? children})
      : super(
          ProfileRoute.name,
          initialChildren: children,
        );

  static const String name = 'ProfileRoute';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}

/// generated route for
/// [_i4.SettingsPage]
class SettingsRoute extends _i5.PageRouteInfo<void> {
  const SettingsRoute({List<_i5.PageRouteInfo>? children})
      : super(
          SettingsRoute.name,
          initialChildren: children,
        );

  static const String name = 'SettingsRoute';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}
@Milad-Akarie
Copy link
Owner

@stefanschaller if the settings route is not a tab route it should be in the root scope

  final List<AutoRoute> routes = [
    AutoRoute(
      page: HomeRoute.page,
      path: '/home',
      initial: true,
      children: [
        AutoRoute(
          path: 'books',
          page: MyBooksRoute.page,
          initial: true,
        ),
        AutoRoute(
          path: 'profile',
          page: ProfileRoute.page,
        ),
    
      ],
    ),
/// should be in the root scope
    DetailRoute(
          path: 'settings',
          page: SettingsRoute.page,
        ),
  ];

if for some reason, you need it to be in the tab-host scope, user router.navigate() instead of push.

@stefanschaller
Copy link
Author

@SeriousMonk @Milad-Akarie I fixed it. Thanks for the fast response.

The soution was:

  final List<AutoRoute> routes = [
    AutoRoute(
      page: HomeRoute.page,
      path: '/home',
      initial: true,
      children: [
        AutoRoute(
          path: 'books',
          page: MyBooksRoute.page,
          initial: true,
        ),
        AutoRoute(
          path: 'profile',
          page: ProfileRoute.page,
        ),
    
      ],
    ),
/// should be in the root scope
    DetailRoute(
          path: '/home/settings', <- This also contains the `/home  `
          page: SettingsRoute.page,
        ),
  ];
return MaterialApp.router(
          routerDelegate: _rootRouter.delegate(),
          routeInformationParser: _rootRouter.defaultRouteParser(
            // and this 
            includePrefixMatches: true
          ),
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants