getx icon indicating copy to clipboard operation
getx copied to clipboard

Nested GetRouterOutlet not working

Open LuisGMM opened this issue 10 months ago • 3 comments

Describe the bug Using doubly nested GetRouterOutlet causes the second router to.. disappear? I really have no idea what is happening. Repo: https://github.com/LuisGMM/get_bug_example

Reproduction code

app_routes.dart

// Remove analyzer from this file
// ignore_for_file: constant_identifier_names

import 'package:project/app_pages.dart';

/// Used to define all the routes in the application.
/// Use it along the `Get.*Named()` methods to navigate to the desired screen.
abstract class AppRoutes {
  AppRoutes._();

  static const String INIT = HOME;

  static const String HOME = AppPaths.HOME;

  static const String INVENTORY = AppRoutes.HOME + AppPaths.INVENTORY;

  static const SETTINGS = HOME + AppPaths.SETTINGS;
  static const SETTINGS_PROFILE = SETTINGS + AppPaths.SETTINGS_PROFILE;
  static const SETTINGS_SUPPORT_NOTIFICATION = SETTINGS + AppPaths.SETTINGS_SUPPORT_NOTIFICATION;
}

/// Used to define all the paths in the application.
/// They are not used directly for navigation, but are used to
/// build the routes in the [AppRoutes] class and the pages
/// in the [AppPages] class.
abstract class AppPaths {
  AppPaths._();

  static const HOME = '/home';

  static const INVENTORY = '/inventory';
  static const SETTINGS = '/settings';
  static const SETTINGS_PROFILE = '/profile';
  static const SETTINGS_SUPPORT_NOTIFICATION = '/support-notification';
}
app_pages.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:project/app_routes.dart';
import 'package:project/nav_bar_screen.dart';
import 'package:project/settings_screen.dart';

class AppPages {
  AppPages._();

  // ignore: constant_identifier_names
  static const INITIAL = AppRoutes.HOME;

  static final pages = [
    GetPage<void>(
      participatesInRootNavigator: true,
      name: AppPaths.HOME,
      page: NavBarScreen.new,
      transition: Transition.zoom,
      transitionDuration: const Duration(milliseconds: 250),
      children: [
        GetPage(name: AppPaths.INVENTORY, page: () => const Center(child: Text('inventory'))),
        GetPage(
          name: AppPaths.SETTINGS,
          page: () => const SettingsWrapper(),
          children: [
            GetPage(name: AppPaths.SETTINGS_PROFILE, page: () => const ProfileTabContent()),
            GetPage(
              name: AppPaths.SETTINGS_SUPPORT_NOTIFICATION,
              page: () => const SupportNotificationTabContent(),
            ),
          ],
        ),
      ],
    ),
  ];
}

nav_bar_screen.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:project/app_routes.dart';

class NavBarScreen extends GetResponsiveView<void> {
  NavBarScreen({super.key});

  @override
  Widget phone() {
    return Center(child: Text('phone'));
  }

  @override
  Widget tablet() {
    return phone();
  }

  @override
  Widget desktop() {
    return GetRouterOutlet.builder(
      route: AppRoutes.HOME,
      builder: (context) {
        return Scaffold(
          body: SafeArea(
            child: Row(
              children: [
                IndexedRouteBuilder<void>(
                  routes: const [AppRoutes.INVENTORY, AppRoutes.SETTINGS],
                  builder: (context, routes, index) {
                    final delegate = context.delegate;

                    return Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        ElevatedButton(
                          onPressed: () => delegate.toNamed<void>(AppRoutes.INVENTORY),
                          child: Text('Inventory'),
                        ),

                        ElevatedButton(
                          onPressed: () => delegate.toNamed<void>(AppRoutes.SETTINGS),
                          child: Text('Settings'),
                        ),
                      ],
                    );
                  },
                ),
                Expanded(
                  child: GetRouterOutlet(
                    initialRoute: AppRoutes.INVENTORY,
                    anchorRoute: AppRoutes.HOME,
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

settings_screen.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:project/app_routes.dart';

class ProfileTabContent extends StatelessWidget {
  const ProfileTabContent({super.key});
  @override
  Widget build(BuildContext c) => const Center(child: Text('🛠 Profile screen goes here'));
}

class SupportNotificationTabContent extends StatelessWidget {
  const SupportNotificationTabContent({super.key});
  @override
  Widget build(BuildContext c) => const Center(child: Text('🛠 Support & notification prefs'));
}

class SettingsWrapper extends StatefulWidget {
  const SettingsWrapper({super.key});

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

class _SettingsWrapperState extends State<SettingsWrapper> with SingleTickerProviderStateMixin {
  final _routes = [AppRoutes.SETTINGS_PROFILE, AppRoutes.SETTINGS_SUPPORT_NOTIFICATION];
  @override
  Widget build(BuildContext context) {
    return GetRouterOutlet.builder(
      route: AppRoutes.SETTINGS,
      builder: (context) {
        return SafeArea(
          child: Scaffold(
            bottomNavigationBar: IndexedRouteBuilder<void>(
              routes: _routes,
              builder: (context, routes, index) {
                return ElevatedButton(
                  onPressed:
                      () => context.delegate.toNamed<void>(AppRoutes.SETTINGS_SUPPORT_NOTIFICATION),
                  child: const Text('Wtf is going on?'),
                );
              },
            ),
            body: GetRouterOutlet(
              initialRoute: AppRoutes.SETTINGS_PROFILE,
              anchorRoute: AppRoutes.SETTINGS,
            ),
          ),
        );
      },
    );
  }
}

main.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:project/app_pages.dart';
import 'package:project/nav_bar_screen.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(title: 'Flutter Demo', home: NavBarScreen(), getPages: AppPages.pages);
  }
}

To Reproduce Steps to reproduce the behavior:

  1. Add the code into a GetMaterialApp
  2. Click on the 'Settings' button
  3. Click on 'Wtf is going on?'
  4. The 'Wtf is going on?' disappears

Expected behavior As with the column of buttons, I expected the bottomNavigationBar to remain in place, instead it disappears and opens the AppRoutes.SETTINGS_SUPPORT_NOTIFICATION in "Full screen" next to the column of buttons.

Screenshots Go to settings Image

Here we can see the bottom bar (I tried adding columns & rows to the body too, same result): Image

However, after clicking on it we see the new page, but the bottom bar wen on holidays :( Image

Flutter Version: Latest

Getx Version: get: ^5.0.0-release-candidate-9.3.2

Describe on which device you found the bug: ex: settings_screen.dart.

Minimal reproduce code I made a repo with it: https://github.com/LuisGMM/get_bug_example

LuisGMM avatar May 01 '25 16:05 LuisGMM

Note this example also suffers this bug: https://github.com/jonataslaw/getx/issues/3336

LuisGMM avatar May 01 '25 16:05 LuisGMM

Oh and I based this example on the @jonataslaw example:

LuisGMM avatar May 01 '25 16:05 LuisGMM

Another thing, sorry, I tested it on the web, like this: flutter run -d chrome

LuisGMM avatar May 01 '25 16:05 LuisGMM