beamer icon indicating copy to clipboard operation
beamer copied to clipboard

Problem with BottomNavigationBar with multiple Beamers

Open abigotado opened this issue 2 years ago • 2 comments

Describe the bug

When implementing BottomNavigation and PageView with multiple Beamers appears a bug. Everything is OK when I'm clicking BottomNavigationBar Items - the pages are changing. Then I'm beaming toNamed to get to one of the pages (friends page). It goes OK too. And tapping BottomNavBarItem goes OK. But if I'm trying to beamToNamed (friends page as previously) again - it redirects to 'Not found' and all the navigation through NavBarItems breaks.

Here is my beamer code parts: main:

class _MyApp extends StatelessWidget {
  final BeamerDelegate<BeamState> routerDelegate = BeamerDelegate<BeamState>(
    initialPath: '/users',
    locationBuilder: SimpleLocationBuilder(
      routes: <Pattern, dynamic Function(BuildContext, BeamState)>{
        '*': (final BuildContext context, final BeamState state) =>
            NavigationScreen(),
      },
    ),
  );

MaterialApp:

GetMaterialApp.router(
              scaffoldMessengerKey: snackBarKey,
              debugShowCheckedModeBanner: false,
              localizationsDelegates: context.localizationDelegates,
              supportedLocales: context.supportedLocales,
              locale: context.locale,
              theme: Theme.of(themeContext),
              routerDelegate: routerDelegate,
              routeInformationParser: BeamerParser(),
              backButtonDispatcher: BeamerBackButtonDispatcher(
                delegate: routerDelegate,
              ),
            ),

Locations:

class UsersLocation extends BeamLocation<BeamState> {
  UsersLocation(final BeamState state) : super(state);

  @override
  List<String> get pathBlueprints => <String>['/users/'];

  @override
  List<BeamPage> buildPages(
    final BuildContext context,
    final BeamState state,
  ) =>
      <BeamPage>[
        BeamPage(
          key: const ValueKey<String>('users'),
          title: 'Users',
          type: BeamPageType.noTransition,
          child: const DatingScreen(),
        ),
      ];
}

class RestaurantsLocation extends BeamLocation<BeamState> {
  RestaurantsLocation(final BeamState state) : super(state);

  @override
  List<String> get pathBlueprints => <String>['/restaurants/'];

  @override
  List<BeamPage> buildPages(
    final BuildContext context,
    final BeamState state,
  ) =>
      <BeamPage>[
        BeamPage(
          key: const ValueKey<String>('restaurants'),
          title: 'Restaurants',
          type: BeamPageType.noTransition,
          child: const DefaultScreen(),
        ),
      ];
}

class FriendsLocation extends BeamLocation<BeamState> {
  FriendsLocation(final BeamState state) : super(state);

  @override
  List<String> get pathBlueprints => <String>['/friends/'];

  @override
  List<BeamPage> buildPages(
    final BuildContext context,
    final BeamState state,
  ) =>
      <BeamPage>[
        BeamPage(
          key: const ValueKey<String>('friends'),
          title: 'Friends',
          type: BeamPageType.noTransition,
          child: const FriendsScreen(),
        ),
      ];
}

class ChatsLocation extends BeamLocation<BeamState> {
  ChatsLocation(final BeamState state) : super(state);

  @override
  List<String> get pathBlueprints => <String>['/chats/'];

  @override
  List<BeamPage> buildPages(
    final BuildContext context,
    final BeamState state,
  ) =>
      <BeamPage>[
        BeamPage(
          key: const ValueKey<String>('chats'),
          title: 'Chats',
          type: BeamPageType.noTransition,
          child: const ChatsScreen(),
        ),
      ];
}

NavigationScreen:

class NavigationScreen extends StatelessWidget {
  NavigationScreen({final Key? key}) : super(key: key);

  final List<BeamerDelegate<BeamState>> routerDelegates =
      <BeamerDelegate<BeamState>>[
    BeamerDelegate<BeamState>(
      initialPath: '/users',
      locationBuilder: (final BeamState state) {
        if (state.uri.pathSegments.contains('users')) {
          return UsersLocation(state);
        }
        return NotFound();
      },
    ),
    BeamerDelegate<BeamState>(
      initialPath: '/restaurants',
      locationBuilder: (final BeamState state) {
        if (state.uri.pathSegments.contains('restaurants')) {
          return RestaurantsLocation(state);
        }
        return NotFound();
      },
    ),
    BeamerDelegate<BeamState>(
      initialPath: '/friends',
      locationBuilder: (final BeamState state) {
        if (state.uri.pathSegments.contains('friends')) {
          return FriendsLocation(state);
        }
        return NotFound();
      },
    ),
    BeamerDelegate<BeamState>(
      initialPath: '/chats',
      locationBuilder: (final BeamState state) {
        if (state.uri.pathSegments.contains('chats')) {
          return ChatsLocation(state);
        }
        return NotFound();
      },
    ),
  ];

  @override
  Widget build(final BuildContext context) {

    final String uriString = Beamer.of(context).state.uri.toString();
    final RxInt _page = 0.obs;
    if (uriString.contains('users')) {
      _page.value = 0;
    } else if (uriString.contains('restaurants')) {
      _page.value = 1;
    } else if (uriString.contains('friends')) {
      _page.value = 2;
    } else if (uriString.contains('chats')) {
      _page.value = 3;
    }

    final PageController _pageController = PageController(
      initialPage: _page.value,
    );

    routerDelegates[_page.value].active = true;
    routerDelegates[_page.value].update();

    _pageController.addListener(() {
      if (_pageController.page == 0) {
        routerDelegates[0].active = true;
        routerDelegates[1].active = false;
        routerDelegates[2].active = false;
        routerDelegates[3].active = false;
        routerDelegates[0].update();
   
      } else if (_pageController.page == 1) {
        routerDelegates[1].active = true;
        routerDelegates[0].active = false;
        routerDelegates[2].active = false;
        routerDelegates[3].active = false;
        routerDelegates[1].update();

      } else if (_pageController.page == 2) {
        routerDelegates[2].active = true;
        routerDelegates[1].active = false;
        routerDelegates[0].active = false;
        routerDelegates[3].active = false;
        routerDelegates[2].update();

      } else if (_pageController.page == 3) {
        routerDelegates[3].active = true;
        routerDelegates[1].active = false;
        routerDelegates[2].active = false;
        routerDelegates[0].active = false;
        routerDelegates[3].update();
      }
    });

    return Scaffold(
      resizeToAvoidBottomInset: false,
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Beamer.of(context).beamToNamed('/friends', replaceCurrent: true);
        },
      ),
      body: PageView(
        controller: _pageController,
        pageSnapping: false,
        physics: const NeverScrollableScrollPhysics(),
        onPageChanged: (final int newPage) {
          _page.value = newPage;
        },
        children: <Widget>[
          Beamer(
            key: const Key('users-page'),
            routerDelegate: routerDelegates[0],
          ),
          Beamer(
            key: const Key('restaurants-page'),
            routerDelegate: routerDelegates[1],
          ),
          Beamer(
            key: const Key('friends-page'),
            routerDelegate: routerDelegates[2],
          ),
          Beamer(
            key: const Key('chats-page'),
            routerDelegate: routerDelegates[3],
          ),
        ],
      ),
      bottomNavigationBar: Obx(
        () => BottomNavigationBar(
          currentIndex: _page.value,
          onTap: (final int index) {
            if (index != _page.value) {
              _page.value = index;
              _pageController.jumpToPage(_page.value);
            }
          },
          items: <BottomNavigationBarItem>[...],
        ),
      ),
    );
  }
}

Beamer version: v0.14.1

To Reproduce Steps to reproduce the behavior:

  1. Navigate through NavBarItems
  2. Click FloatingActionButton to get to friends page
  3. Navigate to any other NavBarItem
  4. Click again FloatingActionButton to get to friends page
  5. See "Not Found" page

Smartphone (please complete the following information):

  • Device: iPhone13 pro simulator
  • OS: iOS15.0 (the same on Android)

Is it a bug or am I doing anything wrong?

abigotado avatar Nov 26 '21 09:11 abigotado

Hi @abigotado :wave: Thanks for creating an issue and sorry for a late response.

Have you tried on v1.0.0? If you can make a runnable app with the code snippets you provided, that would be much appreciated. I can then migrate it and try against v1.0.0 to check if the problem is still there.

slovnicki avatar Nov 29 '21 18:11 slovnicki

Hello @slovnicki !

Thank you for your response! I'm sorry for answering so long.

No, I haven't tried newer versions, but I think the problem is somewhere in my code and doesn't depend on the version. Well, I've made a special repository to check the problem, so you can see fully reproducible code here: https://github.com/abigotado/problem_beamer_example

Hope you will find some time to see it. Thank you very much!

abigotado avatar Jan 17 '22 09:01 abigotado