Navigation does not reload instantly on Dart/ Flutter

Viewed 29

I am working on this navigation that is a list but it is very inconstant in refreshing. Sometimes it refreshes and appears the new button, and other times it does not show the new button. Have you had this problem before.

This is my page showing the routers list and the pages list:

class RouterTabletPage extends StatefulWidget { // ignore: must_be_immutable
  BuildContext? context;

  RouterTabletPage({Key? key}) : super(key: key);

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

class _RouterTabletPageState extends State<RouterTabletPage> with SingleTickerProviderStateMixin {
  final NavigationController _navigationController = IoC.get<NavigationController>()!;
  final TopBarWidgetController _topBarController = IoC.get<TopBarWidgetController>()!;
  final TerminalLockController _terminalLockController = IoC.get<TerminalLockController>()!;
  final PreAlarmController _preAlarmController = IoC.get<PreAlarmController>()!;
  final UpdateUiService _updateUiService = IoC.get<UpdateUiService>()!;

  PageController? _pageViewController;

  @override
  initState() {
    super.initState();
    WidgetsBinding.instance!.addPostFrameCallback((_) async {
      await _navigationController.initRoutes();
      _navigationController.pageViewController = PageController(initialPage: _navigationController.menuSelectedIndex);
      _pageViewController = _navigationController.pageController;

      await _navigationController.getTabs(_navigationController.menuSelectedIndex);
      await _navigationController.setListenerPage();
      _topBarController.initTopBar();
      await _navigationController.refreshCycleBtn();
    });
  }
  registerContext() {
    widget.context = context;
    _terminalLockController.registerContext(context);
    _preAlarmController.registerContext(context);
    _updateUiService.registerContext(context);
  }
 @override 
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    registerContext();

    return Observer(
      builder: (_) {
        return Scaffold(
          appBar: _topBarController.topBarWidget,
          backgroundColor: Theme.of(context).primaryColor,
          body: Container(
            color: Theme.of(context).primaryColor,
            margin: const EdgeInsets.all(0.0),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                Container(
                  width: 60,
                  margin: const EdgeInsets.only(top: 0.0),
                  color: Theme.of(context).primaryColor,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    mainAxisSize: MainAxisSize.max,
                    children:  _navigationController.tabs,
                    ),
                ),
                Expanded(
                  child: Container(
                    color: Theme.of(context).backgroundColor,
                    child: PageView(
                      scrollDirection: Axis.vertical,
                      controller: _pageViewController,
                      children: _navigationController.pages,
                    ),

And this is my controller:

  @observable
  Map<num, PageWithRouter> routers = {};

  @observable
  String router2 = "";

  @observable
  int menuSelectedIndex = 0;

  @observable
  String preloader = "";

  @observable
  Object? arguments;

  @observable
  List<Widget> pages = [];

  @observable
  PageController? pageController;

  @observable
  List<Widget> tabs = [];

  String pathPage = "";

  @observable
  bool cycleEnable = true;

  @observable
  bool isCycleStarted = false;

  @observable
  BuildContext? context;

  set pageViewController(PageController _pageController) =>
      pageController = _pageController;

  @action
  Future setRouter(String path) async {
    initRoutes();
    if (router2 != path) {
      pathPage = path;
      if (path != pathSplashScreen && path != "") router2 = path;

      if (router2 != pathRegister) {
        await _treatAuth().then((value) async {
          if (!value) {
            setMenuSelectedByPath(path);
            await initPages();
          }
        });
      }
    }
  }

  @action
  Future refreshCurrentPage(List<String> path) async {
    if (path.contains(router2)) {
      await _treatAuth().then((value) async {
        if (!value) {
          await initPages();
        }
      });
    }
  }

  @action
  setRouterByHomePage(String path) async {
    await setRouter(path);
    // log('path'+path);

    pageController!.jumpToPage(menuSelectedIndex);
  }
  @action
  Future<void> setRouterByIndex(int index) async {
      menuSelectedIndex = index;

      String _router = routers[menuSelectedIndex]?.defaultRouter ?? " ";

      if (_router != router2) {
        await setRouter(_router);
      }
    }



  @action
  setArguments(Object? obj) {
    arguments = obj;
  }

  @action
  setCycleEnable(bool enable) async{
    cycleEnable = enable;
    
log('noaction'+cycleEnable.toString());

  }

  @action
  setCycleStarted(bool started) {
    isCycleStarted = started;
  }

  @action
  setMenuSelectedIndex(int index) {
    menuSelectedIndex = index;
  }

  @action
  Widget getByIndex(int index) {
    return routers[index]?.page ?? const SizedBox.shrink();
  }

  @action
  Future<Widget> getPage(String router, int pageIdentify) async {
    if (pageIdentify != menuSelectedIndex) {
      return getByIndex(pageIdentify);
    }

    for (var item in routers.values) {
      if (item.routers.any((r) => r == router) ||
          (router == "" && item.defaultRouter == pathHome)) {
        item.page = _createPageByRouter(router);
        return _createPageByRouter(router);
        // TODO: strange behaviour where returning item.page is identified as Widget?
      }
    }

    return const SizedBox.shrink();
  }

  @action
  Widget _createPageByRouter(String router) {
    bool isTablet = DeviceType.get().isTablet!;
    Widget page = const SizedBox.shrink();
    bool isShowSubMenu = true;
  log('router'+router);

    switch (router) {
      case '':
      case pathHome:
        page = isTablet
            ? const HomeTabletPage(title: "Home")
            : const HomePhonePage(title: "Home");
        if (isTablet) isShowSubMenu = false;
        break;
      case pathMessageReceived:
        page = isTablet
            ? MessageListTabletPage(type: 1)
            : MessageListPhonePage(type: 1);
        break;
      case pathMessageSend:
        page = isTablet
            ? MessageListTabletPage(type: 0)
            : MessageListPhonePage(type: 0);
        break;
      case pathInformation:
        page = isTablet ? const InformationTabletPage() : const InformationPhonePage();
        break;
      case pathExternalDevice:
        page =
            isTablet ? const ExternalDeviceTabletPage() : const ExternalDevicePhonePage();
        break;
      case pathErrorCode:
        page = isTablet ? const ErrorCodeTabletPage() : const ErrorCodePhonePage();
        break;
      case pathSetting:
        page = isTablet
            ? SettingTabletPage(title: "Configurações", defaultPage: true)
            : SettingPhonePage(title: "Configurações", defaultPage: true);
        break;
      case pathSettingUnitConfig:
        page = isTablet
            ? SettingTabletPage(title: "Configurações", defaultPage: false)
            : SettingPhonePage(title: "Configurações", defaultPage: false);
        break;
      case pathOperationCycle:
        if (isTablet) {
          return const OperationCycleMasterTablet();
        } else {
          if (isCycleStarted) {
            page = const OperationCyclePhonePage();
          } else {
            page = const OperationCycleHomePhonePage();
          }
        }

        if (isTablet) isShowSubMenu = false;
        break;
      default:
        page = const SizedBox.shrink();
        break;
    }

    if (isShowSubMenu && isTablet) {
      return Row(
        mainAxisSize: MainAxisSize.max,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          IoC.get<SubMenu>()!,
          Expanded(
            child: page,
          ),
        ],
      );
    }

    return page;
  }


  @action
  Future initPages() async {
    initRoutes();
    pages = [];

    for (final key in routers.keys) {
      if (routers[key]!.defaultRouter ==
              NavigationControllerBase.pathOperationCycle &&
          cycleEnable == false) {
        setMenuSelectedIndex(0);
        setRouterByHomePage(pathHome);
      }

      final page = await getPage(router2, key as int);

      pages.add(page);
      log('initPages'+ pages.toString());
    }
  }

  Future<bool> _treatAuth() async {
    final authStatusService = IoC.get<AuthStatusService>()!;
    final authStatus = await authStatusService.syncData();

    if (authStatus != null && authStatus.requireLogin) {
      pathPage = pathAuthentication;
      router2 = pathAuthentication;
      IoC.get<NavigationService>()!.navigateWithoutHistory(pathAuthentication);
      return true;
    }

    return false;
  }

  @action
  Future initRoutes() async {
    
    if (DeviceType.get().isPhone!) {
      routers = <num, PageWithRouter>{
        0: PageWithRouter([pathHome], null),
        1: PageWithRouter([pathInformation, pathExternalDevice], null),
        2: PageWithRouter([pathErrorCode], null),
        3: PageWithRouter([pathSetting, pathSettingUnitConfig], null),
      };

      if (cycleEnable) {
        routers.addAll({
          4: PageWithRouter([pathOperationCycle], null),
          5: PageWithRouter([pathMessageReceived, pathMessageSend], null),
        });
      } else {
        routers.addAll({
          4: PageWithRouter([pathMessageReceived, pathMessageSend], null),
        });
      }
    } else {
      routers = <num, PageWithRouter>{
        0: PageWithRouter([pathHome], null),
        1: PageWithRouter([pathMessageReceived, pathMessageSend], null),
        2: PageWithRouter([pathInformation, pathExternalDevice], null),
        3: PageWithRouter([pathErrorCode], null),
        4: PageWithRouter([pathSetting, pathSettingUnitConfig], null),
      };

      if (cycleEnable == true) {
        routers.addAll({
          5: PageWithRouter([pathOperationCycle], null)
        });
        log('initRoutes'+routers.toString());
      }
    }
  }
  @action
  Future refreshCycleBtn() async {
    tabs = [];
    

    if (DeviceType.get().isPhone!) {
      tabs = List.from(tabs..addAll(await getTabsPhone(menuSelectedIndex)));
    } else {
      tabs = List.from(tabs..addAll(await getTabs(menuSelectedIndex)));
      log('tabs'+tabs.toString());
    }
    await initRoutes();
    await _verifyOperationCycleEnabled();

    if (cycleEnable == false) {
      if (menuSelectedIndex > routers.length - 1) {
        await setRouterByIndex(0);
          pageController!.jumpToPage(0);
      } else {
        await initPages();
      }
    } else {
      await initPages();

      pages = [];
      List<Widget> newPages = [];

      for (final key in routers.keys) {
        final page = await getPage(router2, key as int);

        newPages.add(page);
        pages = List.from(pages..addAll(newPages));
      }

      if (menuSelectedIndex > routers.length - 1) {
        await setRouterByIndex(0);

      } else {
        await initRoutes();
        await initPages();
        
      }
    }
  }

  Future<List<Widget>> getTabs(int index) async {
    List<Widget> newTabs = [];
    //await _menuIconsController.refreshAllBadge();
    for (final key in routers.keys) {
      if (routers[key]!.defaultRouter ==
            NavigationControllerBase.pathOperationCycle && cycleEnable == false) {
        continue;
      }

      newTabs.add(
        SizedBox(
          height: 70,
          child: TextButton(
            style: TextButton.styleFrom(
              backgroundColor: index == key ? AppTheme.theme.colorScheme.secondary : Colors.transparent,
              shape: const ContinuousRectangleBorder(
                borderRadius: BorderRadius.all(Radius.zero),
              ),
            ),
            child: _getTabIcon(routers[key]!.defaultRouter),
            onPressed: () async {
              await setRouterByIndex(key as int);
              pageController!.jumpToPage(key);
            },
          ),
        ),
      );
    }

    tabs = [];
    tabs = List.from(tabs..addAll(newTabs));
    log('newtabs'+newTabs.toString());
    return newTabs;
  }

  Widget _getTabIcon(String router) { // os cases com icons
    switch (router) {
      case '': //setado para home
        return const Icon(
          Icons.home,
          color: Colors.white,
          size: 30,
        );
      case NavigationControllerBase.pathHome:
        return const Icon(
          Icons.home,
          key: Key('btn_home_page'),
          color: Colors.white,
          size: 30,
        );
      case NavigationControllerBase.pathMessageReceived:
        var icon = const Icon(
          Icons.mail,
          key: Key('btn_message_page'),
          color: Colors.white,
          size: 30,
        );

        return Observer(builder: (_) {
          if (_menuIconsController.countMessages == 0) return icon;

          return Badge(
            badgeContent: Text(
              _menuIconsController.countMessages.toString(),
              style: const TextStyle(
                color: Colors.white,
              ),
            ),
            child: icon,
          );
        });
      case NavigationControllerBase.pathInformation:
        return const Icon(
          Icons.info,
          key: Key('btn_information_page'),
          color: Colors.white,
          size: 30,
        );
      case NavigationControllerBase.pathErrorCode:
        var icon = const Icon(
          Icons.warning,
          key: Key('btn_erro_code_page'),
          color: Colors.white,
        );

        return Observer(builder: (_) {
          if (_menuIconsController.countUccErrors == 0) return icon;

          return Badge(
            badgeContent: Text(
              _menuIconsController.countUccErrors.toString(),
              style: const TextStyle(
                color: Colors.white,
              ),
            ),
            child: icon,
          );
        });
      case NavigationControllerBase.pathSetting:
        var icon = const Icon(
          Icons.settings,
          key: Key('btn_setting_page'),
          color: Colors.white,
          size: 30,
        );

        if (!_menuIconsController.showBadgetSetting!) return icon;

        return Observer(builder: (_) {
          return Badge(
            badgeContent: const Padding(
              padding: EdgeInsets.all(2.0),
              child: Text(
                "!",
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
            ),
            child: icon,
          );
        });
      case NavigationControllerBase.pathOperationCycle:
        return const Icon(
          MtfIcons.operationalCycleHomeMenu,
          key: Key('btn_operation_cycle'),
          color: Colors.white,
          size: 30,
        );
      default:
        return const SizedBox.shrink();
    }
  }

  Future<List<Widget>> getTabsPhone(int index) async {
    List<Widget> newTabs = [];

    //await _menuIconsController.refreshAllBadge();

    for (final key in routers.keys) {
      if (routers[key]!.defaultRouter ==
              NavigationControllerBase.pathOperationCycle &&
          cycleEnable == false) {
        continue;
      }

      newTabs.add(
        Expanded(
          child: TextButton(
            style: TextButton.styleFrom(
              primary: index == key ? AppTheme.theme.colorScheme.secondary : Colors.transparent,
            ),
            onPressed: () async {
              await setRouterByIndex(key as int);
              pageController!.jumpToPage(key);
            },
            child: _getTabIcon(routers[key]!.defaultRouter),
          ),
        ),
      );
    }
    tabs = [];
    tabs = List.from(tabs..addAll(newTabs));
    return newTabs;
  }

  Future setListenerPage() async {
    // TODO: refactor this lambda;
    var listener = () async { // ignore: prefer_function_declarations_over_variables
      if (DeviceType.get().isPhone!) {
        await getTabsPhone(menuSelectedIndex);
      } else {
        await getTabs(menuSelectedIndex);
      }

      double page = pageController!.page!;
      await setRouterByIndex(page.round());
    };

    pageController!.removeListener(listener);
    pageController!.addListener(listener);
  }

  void setMenuSelectedByPath(String? path) { //init menuSeletecteIndex =id
    routers.forEach((id, page) {
      if (page.routers.any((r) => r == path)) {
        menuSelectedIndex = id as int;
      }
    });
  }

  Future _verifyOperationCycleEnabled() async {  //setCycleEnable true || false
    final _operationCycleService = IoC.get<OperationCycleService>()!;

    final operationCycle = await _operationCycleService.syncData();
    if (operationCycle == null) {
      setCycleEnable(false);
    } else {
      setCycleEnable(true);
    }
  }
}

class PageWithRouter {
  List<String> routers;
  Widget? page;

  String get defaultRouter => routers.first;

  PageWithRouter(this.routers, this.page);
}

I have already tried changing WidgetsBinding to Future.delay and tried initiating different ways inside refreshCycleBtn().

0 Answers
Related