Search code examples
flutterflutter-navigation

Flutter: Dynamic Initial Route


Dears,

I am using provider dart package which allows listeners to get notified on changes to models per se.

I am able to detect the change inside my main app root tree, and also able to change the string value of initial route however my screen is not updating. Kindly see below the code snippet and the comments lines:

  void main() => runApp(_MyAppMain());

    class _MyAppMain extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider<UserProvider>.value(
              value: UserProvider(),
            ),
            ChangeNotifierProvider<PhoneProvider>.value(
              value: PhoneProvider(),
            )
          ],
          child: Consumer<UserProvider>(
            builder: (BuildContext context, userProvider, _) {
              return FutureBuilder(
                future: userProvider.getUser(),
                builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
                  if (!snapshot.hasData) {
                    return Center(
                      child: CircularProgressIndicator(),
                    );
                  }

                  final User user = snapshot.data;

                  String initialScreen = LoginScreen.path;

    // (1) I am able to get into the condition

                  if (user.hasActiveLogin()) {
                    initialScreen = HomeOneScreen.path;
                  }

                  return MaterialApp(
                    title: 'MyApp',
                    theme: ThemeData(
                      primarySwatch: Colors.green,
                      accentColor: Colors.blueGrey,
                    ),
                    initialRoute: initialScreen, 
 // (2) here the screen is not changing...?
                    routes: {
                      '/': (context) => null,
                      LoginScreen.path: (context) => LoginScreen(),
                      RegisterScreen.path: (context) => RegisterScreen(),
                      HomeOneScreen.path: (context) => HomeOneScreen(),
                      HomeTwoScreen.path: (context) => HomeTwoScreen(),
                      RegisterPhoneScreen.path: (context) => RegisterPhoneScreen(),
                      VerifyPhoneScreen.path: (context) => VerifyPhoneScreen(),
                    },
                  );
                },
              );
            },
          ),
        );
      }
    }

Kindly Note the Below:

These are are paths static const strings
LoginScreen.path = "login"
RegisterScreen.path = "/register-screen"
HomeOneScreen.path = "home-one-screen"
HomeTwoScreen.path = "home-two-screen"
RegisterPhoneScreen.path = "/register-phone-screen"
VerifyPhoneScreen.path = "/verify-phone-screen"

What I am missing for dynamic initialRoute to work?

Many Thanks


Solution

  • According to this issue described on github issues it is not permissible to have initial route changes. At least this is what I understood. However what I did is that I replaced the initialRoute attribute with home attr. Thus this change mandates that initialScreen becomes a widget var.

    The changes is shown below:

     void main() => runApp(_MyAppMain());
    
        class _MyAppMain extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return MultiProvider(
              providers: [
                ChangeNotifierProvider<UserProvider>.value(
                  value: UserProvider(),
                ),
                ChangeNotifierProvider<PhoneProvider>.value(
                  value: PhoneProvider(),
                )
              ],
              child: Consumer<UserProvider>(
                builder: (BuildContext context, userProvider, _) {
                  return FutureBuilder(
                    future: userProvider.getUser(),
                    builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
                      if (!snapshot.hasData) {
                        return Center(
                          child: CircularProgressIndicator(),
                        );
                      }
    
                      final User user = snapshot.data;
    
    // (1) This becomes a widget
    
                      Widget initialScreen = LoginScreen();
    
    
    
                      if (user.hasActiveLogin()) {
                        initialScreen = HomeOneScreen();
                      }
    
                      return MaterialApp(
                        title: 'MyApp',
                        theme: ThemeData(
                          primarySwatch: Colors.green,
                          accentColor: Colors.blueGrey,
                        ),
                        home: initialScreen, 
     // (2) here the initial route becomes home attr.
                        routes: {
                          '/': (context) => null,
                          LoginScreen.path: (context) => LoginScreen(),
                          RegisterScreen.path: (context) => RegisterScreen(),
                          HomeOneScreen.path: (context) => HomeOneScreen(),
                          HomeTwoScreen.path: (context) => HomeTwoScreen(),
                          RegisterPhoneScreen.path: (context) => RegisterPhoneScreen(),
                          VerifyPhoneScreen.path: (context) => VerifyPhoneScreen(),
                        },
                      );
                    },
                  );
                },
              ),
            );
          }
        }
    

    Also note on my RegistrationScreen on success api response I did Navigator.of(context).pop()

    Thanks