Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Start app with different routes depending on login state

I'm searching for a way to show a different screens on app startup depending on login state. For example, I have the following routes defined:

  • /home
  • /login
  • /settings

Naturally, I would check if the user has already logged in within the main() method and then set the initialRoute of my MaterialApp to either /login or /home. After successful login, I can call Navigator.pushReplacement to navigate to /home and the login screen is removed from the stack. Unfortunately, I always have to either define a route for / or set the home property of MaterialApp. So if I set / to a blank Container(), this Container will be on the navigation stack and the user can go back to this blank screen.

Two options I came up with are:

  • Setting the home property of MaterialApp to either HomeScreen or LoginScreen
  • Return a LoginScreen within HomeScreen's build() method, if the user has not logged in yet

Both options are feasible, but then I have to come up with some reload logic and re-set the state in order to update the home property or HomeScreen.

Any ideas what is the proper way in Flutter to deal with such cases?

like image 221
zrkl Avatar asked Nov 07 '18 17:11

zrkl


1 Answers

Maybe, you could do this. Imagine you have a class Auth with an async method isLogged.

class Auth {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

  Future<bool> isLogged() async {
    try {
      final FirebaseUser user = await _firebaseAuth.currentUser();
      return user != null;
    } catch (e) {
      return false;
    }
  }
}

You could use the myApp constructor to pass the initialRoute, and decide the initial route depending on the login state. Then, you can pass the instance of myApp to runApp:

Warning: In case of error, add WidgetsFlutterBinding.ensureInitialized(); just before void main() async {. Check this issue #40253.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final Auth _auth = Auth();
  final bool isLogged = await _auth.isLogged();
  final MyApp myApp = MyApp(
    initialRoute: isLogged ? '/home' : '/',
  );
  runApp(myApp);
}

After that, you have to modify the myApp class to pass the initial route in the constructor:

class MyApp extends StatelessWidget {
  final String initialRoute;

  MyApp({this.initialRoute});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dynamic Route Demo',
      initialRoute: initialRoute,
      routes: {
        '/': (context) => LoginPage(),
        '/home': (context) => HomePage(),
        '/settings': (context) => SettingsPage(),
      },
    );
  }
}

Hope this helps.

like image 175
Timbergus Avatar answered Nov 16 '22 13:11

Timbergus