slovnicki / beamer

A routing package built on top of Router and Navigator's pages API, supporting arbitrary nested navigation, guards and more.
MIT License
585 stars 129 forks source link

How to beam to tab in BottomNavigationBar? #578

Open vixez opened 1 year ago

vixez commented 1 year ago

Hello,

I would like to beam to a specific tab, but for some reason I can't get it to work. This does not do anything: Beamer.of(context) .beamToNamed(kHomeRecognitionTabRoute); It only logs in the main delegate as routes: /home/recognition

This is my main delegate

final routerDelegate = BeamerDelegate(
  initialPath: kSplashRoute,
  routeListener: (RouteInformation routeInformation, BeamerDelegate delegate) {
    Logger().info(
      routeInformation.location ?? '',
      category: 'routes',
    );
  },
  transitionDelegate: const NoAnimationTransitionDelegate(),
  locationBuilder: (routeInformation, _) {
    if (routeInformation.location == null) {
      return NotFound();
    }

    switch (routeInformation.location) {
      case kSplashRoute:
        return SplashLocation(routeInformation);
      case kLoginDomainRoute:
        return LoginLocation(routeInformation);
    }

    if (routeInformation.location!.startsWith(kHomeRoute)) {
      return HomeLocation(routeInformation);
    }

    return NotFound();
  },
);

HomeLocation

class HomeLocation extends BeamLocation<BeamState> {
  HomeLocation(RouteInformation routeInformation) : super(routeInformation);

  @override
  List<String> get pathPatterns => [
        kHomeRoute,
      ];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) => [
        const BeamPage(
          key: ValueKey('home'),
          title: 'Home',
          type: BeamPageType.scaleTransition,
          child: HomeScreen(),
        )
      ];
}

HomeScreen

final beamerHomeKey = GlobalKey<BeamerState>();

final routerDelegate = BeamerDelegate(
  locationBuilder: RoutesLocationBuilder(
    routes: {
      kHomeRoute: (context, state, data) => const HomeTabs(),
      kHomeNotificationsRoute: (context, state, data) => const BeamPage(
            child: NotificationsScreen(),
            type: BeamPageType.slideRightTransition,
          ),
    },
  ),
);

class HomeScreen extends ConsumerStatefulWidget {
  const HomeScreen({super.key});

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

class HomeScreenState extends ConsumerState<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const CustomAppBar(),
      body: Beamer(
        key: beamerHomeKey,
        routerDelegate: routerDelegate,
      ),
    );
  }
}

HomeTabs

final _routerDelegates = [
  BeamerDelegate(
    initialPath: kHomeHomeTabRoute,
    routeListener:
        (RouteInformation routeInformation, BeamerDelegate delegate) {
      Logger().info(
        routeInformation.location ?? '',
        category: 'routes_home_tabs',
      );
    },
    locationBuilder: (routeInformation, _) {
      return TabHomeLocation(routeInformation);
    },
  ),
  BeamerDelegate(
    initialPath: kHomeRecognitionTabRoute,
    locationBuilder: (routeInformation, _) {
      return TabRecognitionLocation(routeInformation);
    },
  ),
  BeamerDelegate(
    initialPath: kHomeIncentivesTabRoute,
    locationBuilder: (routeInformation, _) {
      return TabIncentivesLocation(routeInformation);
    },
  ),
  BeamerDelegate(
    initialPath: kHomeMoreTabRoute,
    locationBuilder: (routeInformation, _) {
      return TabMoreLocation(routeInformation);
    },
  ),
];

class HomeTabs extends ConsumerStatefulWidget {
  const HomeTabs({Key? key}) : super(key: key);

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

class HomeState extends ConsumerState<HomeTabs> {
  int currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    var tr = ref.watch(localizationProvider).translations;

    return Scaffold(
      body: IndexedStack(
        index: currentIndex,
        children: [
          Beamer(
            routerDelegate: _routerDelegates[0],
          ),
          Beamer(
            routerDelegate: _routerDelegates[1],
          ),
          Beamer(
            routerDelegate: _routerDelegates[2],
          ),
          Beamer(
            routerDelegate: _routerDelegates[3],
          ),
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: currentIndex,
        items: [
          BottomNavigationBarItem(
            label: tr['global.home'],
            icon: const Icon(
              Icons.home,
            ),
          ),
          BottomNavigationBarItem(
            label: tr['global.recognitions'],
            icon: const Icon(
              Icons.handshake,
            ),
          ),
          BottomNavigationBarItem(
            label: tr['global.gifts'],
            icon: const Icon(
              Icons.card_giftcard,
            ),
          ),
          BottomNavigationBarItem(
            label: tr['global.more'],
            icon: const Icon(
              Icons.person,
            ),
          ),
        ],
        onTap: (index) {
          if (index != currentIndex) {
            setState(() => currentIndex = index);
            _routerDelegates[currentIndex].update(rebuild: false);
          }
        },
      ),
    );
  }
}

What am I doing wrong so I can navigate to the tab from anywhere?

Thanks!

alanlanglois commented 1 year ago

I had to do the same, I ended up using Bloc (Already used for other stuff in my app) I created a NavigationBloc, with a ChangeTabEvent, and listening for this event in the HomeTabs Class using BlocListener. Then you can call the same logic you got in your onTap Method

MadGeorge commented 1 year ago

@vixez Hi! Did you manage to find the answer?

Retr0sec7 commented 1 year ago

I had to do the same, I ended up using Bloc (Already used for other stuff in my app) I created a NavigationBloc, with a ChangeTabEvent, and listening for this event in the HomeTabs Class using BlocListener. Then you can call the same logic you got in your onTap Method

Hello @alanlanglois

I'm also using Bloc in my app, but I'm struggling with nested routes and beamer key placement. Could you provide a code example of your implementation?

alanlanglois commented 1 year ago

Sure, It's a lot of file, I'll make it short if you have any struggle with my explaination let me know. I have a NavigationBloc (Using Freezed to minimize the boilerplate):