jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.27k stars 1.61k forks source link

Get.back does not remove route from the stack of initially generated routes using multiple navigators with bottom navigation bar #3203

Open phawadshah opened 3 weeks ago

phawadshah commented 3 weeks ago

ATTENTION: DO NOT USE THIS FIELD TO ASK SUPPORT QUESTIONS. USE THE PLATFORM CHANNELS FOR THIS. THIS SPACE IS DEDICATED ONLY FOR BUGS DESCRIPTION. Fill in the template. Issues that do not respect the model will be closed.

Describe the bug Using multiple navigators with bottom navigation bar, Get.back works fine when the route is generated through onGenerateRoute but does not work when the routes are generated through onGenerateInitialRoutes.

Reproduction code NOTE: THIS IS MANDATORY, IF YOUR ISSUE DOES NOT CONTAIN IT, IT WILL BE CLOSED PRELIMINARY)

example:


void main() {
  runApp(
    GetMaterialApp(
      title: "Nested Routing",
      initialRoute: Routes.BASE,
      getPages: [
        GetPage(
          name: Routes.BASE,
          page: () => const BaseView(),
          binding: BaseBinding(),
        ),
      ],
    ),
  );
}

class BaseView extends GetView<BaseController> {
  const BaseView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Obx(() =>
          controller.widgetOptions.elementAt(controller.selectedIndex.value)),
      bottomNavigationBar: Obx(
        () => BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: 'Home',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.person),
              label: 'Profile',
            ),
          ],
          currentIndex: controller.selectedIndex.value,
          onTap: controller.onItemTapped,
        ),
      ),
    );
  }
}

class BaseController extends GetxController {
  static BaseController get to => Get.find<BaseController>();
  RxInt selectedIndex = 0.obs;
  late List<Widget> widgetOptions;

  BaseController() {
    widgetOptions = <Widget>[
      const HomeNavigator(),
      const ProfileWrapper(),
    ];
  }

  void onItemTapped(int index) {
    selectedIndex.value = index;
  }
}

class HomeNavigator extends StatelessWidget {
  const HomeNavigator({
    super.key,
  });
  @override
  Widget build(BuildContext context) {
    Get.put<HomeNavigatorController>(HomeNavigatorController(),
        permanent: true);
    return GetBuilder<HomeNavigatorController>(
      builder: (controller) {
        return Navigator(
          key: Get.nestedKey(nestedNavigationHomeId),
          initialRoute: Routes.HOME,
          onGenerateInitialRoutes: controller.onGenerateInitalRoutes,
          onGenerateRoute: controller.onGenerateRoute,
        );
      },
    );
  }
}

class HomeNavigatorController extends GetxController {
  static HomeNavigatorController get to => Get.find<HomeNavigatorController>();

  // Stack of route names to manage the navigation history
  final List<String> _routeStack = [];

  List<String> get routeStack => _routeStack;

  void pushRoute(String routeName) {
    _routeStack.add(routeName);
  }

  List<Route<dynamic>> get generateRoutes => routeStack.map(
        (route) {
          return GetPageRoute(
            routeName: route,
            page: () {
              switch (route) {
                case Routes.HOME:
                  return const HomeView();
                case Routes.DETAILS:
                  return const DetailsView();
                default:
                  return const HomeView();
              }
            },
            binding: route == Routes.HOME
                ? HomeBinding()
                : route == Routes.DETAILS
                    ? DetailsBindings()
                    : null,
          );
        },
      ).toList();

  List<Route<dynamic>> onGenerateInitalRoutes(
      NavigatorState state, String initialRoute) {
    return routeStack.isNotEmpty
        ? generateRoutes
        : Navigator.defaultGenerateInitialRoutes(state, initialRoute);
  }

  Route<dynamic>? onGenerateRoute(RouteSettings settings) {
    if (settings.name == Routes.HOME) {
      routeStack.add(Routes.HOME);
      return GetPageRoute(
        routeName: Routes.HOME,
        page: () => const HomeView(),
        binding: HomeBinding(),
      );
    }
    if (settings.name == Routes.DETAILS) {
      routeStack.add(Routes.DETAILS);
      return GetPageRoute(
        routeName: Routes.DETAILS,
        page: () => const DetailsView(),
        binding: DetailsBindings(),
      );
    }
    return null;
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: Get.nestedKey(nestedNavigationProfileId),
      initialRoute: Routes.PROFILE,
      onGenerateRoute: (routeSettings) {
        if (routeSettings.name == Routes.PROFILE) {
          return GetPageRoute(
              routeName: Routes.PROFILE,
              title: "Profile Page",
              page: () => const ProfileView(),
              binding: ProfileBinding());
        }
        return null;
      },
    );
  }
}

class HomeView extends GetView<HomeController> {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('HomeView'),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextButton(
              onPressed: controller.goToDetails,
              child: const Text("Go to details"),
            ),
          ],
        ),
      ),
    );
  }
}

class ProfileView extends GetView<ProfileController> {
  const ProfileView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ProfileView'),
        centerTitle: true,
      ),
      body: Center(
        child: TextButton(
          onPressed: (){},
          child: const Text("Profile Page"),
        ),
      ),
    );
  }
}

class ProfileController extends GetxController {
  void goToSettingPage() {
  }
}

class HomeController extends GetxController {
  void goToDetails() {
    Get.toNamed(Routes.DETAILS, id: nestedNavigationHomeId);
  }
}

class ProfileBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<ProfileController>(() => ProfileController());
  }
}

class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(() => HomeController());
  }
}

class DetailsView extends GetView<DetailsController> {
  const DetailsView({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Details view'),
        centerTitle: true,
        leading: IconButton(
          onPressed: controller.goBack,
          icon: const Icon(Icons.arrow_back),
        ),
      ),
      body: Center(
        child: TextButton(
          onPressed: (){},
          child: TextButton(
            onPressed: controller.goToSearch,
            child: const Text("Details Page"),
          ),
        ),
      ),
    );
  }
}

class DetailsController extends GetxController {
// This is supposed to go through home navigator
  void goBack() {
    Get.back(id: nestedNavigationHomeId);
  }
}

class DetailsBindings extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<DetailsController>(() => DetailsController());
  }
}

**To Reproduce**
Steps to reproduce the behavior:
1. Go to Details View
2. Change tab to Profile
3. Change tab back to Home
4. Go back
5. Change tab to profile again
6. Change tab back to Home

**Expected behavior**
It is supposed to be on Home Page rather than Details

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Flutter Version:**
3.24.0

**Getx Version:**
get: ^4.6.6

**Describe on which device you found the bug:**
Iphone 15 simulator

**Minimal reproduce code**
Provide a minimum reproduction code for the problem