Milad-Akarie / auto_route_library

Flutter route generator
MIT License
1.57k stars 399 forks source link

AutoBackButton does not work when using wrapper pages and AutoTabsScaffold #571

Closed pauli2406 closed 2 years ago

pauli2406 commented 3 years ago

Hi, I am facing the issue that the auto back button is not working correctly when navigation within a tab of the AutoTabsScaffold. The AutoTabsScaffold is used within the Node Wrapper Page The button is not updated after navigating via

AutoRouter.of(context).push( MileStoneDetailRoute(messageId: milestone.messageId)),

It is only re-rendered when switching tabs. The same happens after using the back button, it stays even if no page is available to pop anymore until tabs are changed.

Any idea how to solve this?

Router ```dart @MaterialAutoRouter( replaceInRouteName: 'Page,Route', routes: [ AutoRoute(path: '/', page: AppWrapperPage, children: []), AutoRoute(path: '/add', page: AddNodePage), AutoRoute( path: '/node', page: NodeWrapperPage, children: [ AutoRoute( path: 'home', name: 'HomeRouter', page: EmptyRouterPage, children: [ AutoRoute( path: '', page: HomePage, ), RedirectRoute(path: '*', redirectTo: ''), ], ), AutoRoute( path: 'analytics', name: 'AnalyticsRouter', page: EmptyRouterPage, children: [ AutoRoute( path: '', page: AnalyticsPage, ), RedirectRoute(path: '*', redirectTo: ''), ], ), AutoRoute( path: 'peers', name: 'PeersRouter', page: EmptyRouterPage, children: [ AutoRoute( path: '', page: PeersPage, ), RedirectRoute(path: '*', redirectTo: ''), ], ), AutoRoute( path: 'explorer', name: 'ExplorerRouter', page: EmptyRouterPage, children: [ AutoRoute( path: '', page: ExplorerPage, ), AutoRoute(path: 'milestone/:messageId', page: MileStoneDetailPage), RedirectRoute(path: '*', redirectTo: ''), ], ), ], ), RedirectRoute(path: '*', redirectTo: '/'), ], ) class $AppRouter {} ```
Wrapper page ```dart class NodeWrapperPage extends StatefulWidget { const NodeWrapperPage({Key? key}) : super(key: key); @override _NodeWrapperPageState createState() => _NodeWrapperPageState(); } class _NodeWrapperPageState extends State { @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider( create: (context) => getIt(), ), BlocProvider( create: (context) => getIt()..health(), ), BlocProvider( create: (context) => getIt()..info(), ), BlocProvider( create: (context) => getIt(), ), ], child: ResponsiveBuilder(builder: (context, sizingInformation) { if (sizingInformation.deviceScreenType == DeviceScreenType.desktop) { return OrientationLayoutBuilder( portrait: (context) => Container(color: Colors.green), landscape: (context) => Container(color: Colors.pink), ); } if (sizingInformation.deviceScreenType == DeviceScreenType.tablet) { return OrientationLayoutBuilder( portrait: (context) => Container(color: Colors.red), landscape: (context) => Container(color: Colors.pink), ); } if (sizingInformation.deviceScreenType == DeviceScreenType.watch) { return OrientationLayoutBuilder( portrait: (context) => Container(color: Colors.yellow), landscape: (context) => Container(color: Colors.pink), ); } return OrientationLayoutBuilder( portrait: (context) => AutoTabsScaffold( appBarBuilder: (context, tabsRouter) { return AppBar( title: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // const Padding( // padding: EdgeInsets.all(8.0), // child: Text( // 'Node:', // style: TextStyle(fontSize: 17), // ), // ), BlocBuilder( buildWhen: (previous, current) => previous.selectedNode.uuid != current.selectedNode.uuid, builder: (context, state) { return DropdownButton( value: state.selectedNode.uuid, items: buildDropdownMenuItems(state.nodes), underline: const SizedBox( height: 0, ), onChanged: (uuid) async { var selectedNodeUuid = uuid as String; var currentlySelectedNode = BlocProvider.of(context) .state .selectedNode; if (currentlySelectedNode.uuid != selectedNodeUuid) { await BlocProvider.of(context) .selectedNodeChanged(selectedNodeUuid); await BlocProvider.of(context) .health(); var info = await BlocProvider.of(context) .info(); await BlocProvider.of(context) .milestones(info!.data.latestMilestoneIndex); } }, ); }, ), ], ), actions: [ const _HealthIndicator(), ], leading: tabsRouter.canPopSelfOrChildren ? BackButton( // color: widget.color, onPressed: tabsRouter.popTop, ) : const SizedBox(), // leading: const AutoBackButton(), ); }, drawer: Drawer( child: ListView( padding: EdgeInsets.zero, children: [ DrawerHeader( decoration: BoxDecoration( color: Theme.of(context).accentColor, ), child: SvgPicture.asset( 'assets/svg/hornet_banner.svg', semanticsLabel: 'Hornet Banner', color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black, fit: BoxFit.fitHeight, ), ), ListTile( title: const Text('Manage Nodes'), onTap: () { // Update the state of the app. // ... }, ), ListTile( title: const Text('Item 2'), onTap: () { // Update the state of the app. // ... }, ), ], ), ), routes: [ const HomeRouter(), const AnalyticsRouter(), const PeersRouter(), const ExplorerRouter(), ], bottomNavigationBuilder: (_, tabsRouter) { return BottomNavigationBar( currentIndex: tabsRouter.activeIndex, onTap: tabsRouter.setActiveIndex, items: [ const BottomNavigationBarItem( icon: Icon( Icons.home_outlined, ), label: 'Home', ), const BottomNavigationBarItem( icon: Icon(Icons.analytics_outlined), label: 'Analytics', ), const BottomNavigationBarItem( icon: Icon(Icons.account_tree_outlined), label: 'Peers', ), const BottomNavigationBarItem( icon: Icon(Icons.explore_outlined), label: 'Explorer', ), ], ); }, ), landscape: (context) => Container(color: Colors.pink), ); }), ); } List> buildDropdownMenuItems( List nodes) { var items = >[]; for (var node in nodes) { items.add( DropdownMenuItem( value: node.uuid, child: SizedBox( width: 150, child: Text( node.name, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 17, ), textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, ), ), ), ); } return items; } } class _HealthIndicator extends StatelessWidget { const _HealthIndicator({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { return AnimatedSwitcher( duration: const Duration(milliseconds: 350), child: state.map( initial: (_) { BlocProvider.of(context).health(); return const SizedBox(); }, loadInProgress: (_) => const Center( child: Padding( padding: EdgeInsets.only(right: 10.0), child: CircularProgressIndicator(), ), ), loadSuccess: (value) => _CircleIndicator(healthy: value.statusCode == 200), loadFailure: (_) => const _CircleIndicator(healthy: false), ), ); }, ); } } class _CircleIndicator extends StatelessWidget { const _CircleIndicator({Key? key, required this.healthy}) : super(key: key); final bool healthy; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(right: 10.0), child: Container( width: 20, height: 20, decoration: BoxDecoration( shape: BoxShape.circle, color: healthy ? Colors.green.withAlpha(100) : Colors.red.withAlpha(100), ), child: Padding( padding: const EdgeInsets.all(5.0), child: Container( decoration: BoxDecoration( shape: BoxShape.circle, color: healthy ? const Color(0xFF50B86C) : Colors.red, ), ), ), ), ); } } class AutoBackButton extends StatefulWidget { const AutoBackButton({Key? key, this.color}) : super(key: key); final Color? color; @override _AutoBackButtonState createState() => _AutoBackButtonState(); } class _AutoBackButtonState extends State { @override Widget build(BuildContext context) { final scope = RouterScope.of(context); if (scope.controller.canPopSelfOrChildren) { return BackButton( color: widget.color, onPressed: scope.controller.popTop, ); } else { return const SizedBox(); } // return IconButton( // icon: Icon( // Icons.list, // color: Theme.of(context).brightness == Brightness.dark // ? Colors.white // : Colors.black, // ), // onPressed: () => Scaffold.of(context).openDrawer()); } } ```

Screenshots

https://user-images.githubusercontent.com/24795790/120071216-8a1d5800-c08e-11eb-915d-ef58be8bf8b1.png https://user-images.githubusercontent.com/24795790/120071228-96091a00-c08e-11eb-8eb0-8452d8935039.png

jlnrrg commented 3 years ago

I also noticed this behavior when using the scaffold. Interessting is also that flutter recommended method: ModalRoute.of(context)?.canPop also returns false.

also @pauli2406 please consider using details and syntax highlighting with "dart". Otherwise your issue is just unreadable :pray:

pauli2406 commented 3 years ago

@jlnrrg You are right. Did not know about the language support. Adjusted it.

admedina commented 3 years ago

@pauli2406 I'm not sure if you solved this yet but I ran into a similar issue.
Where you wrote onPressed: tabsRouter.popTop,, I was able to make it work using the following.

if (tabsRouter.canPopSelfOrChildren) {
      final childRouter = context.innerRouterOf(tabsRouter.currentChild!.name);
      return BackButton(
        onPressed: () => childRouter!.pop(),
      );
    } else {
      return null;
    }

Hopefully this is helpful!

github-actions[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions