Hello guys I\'m using BLoC for app I\'m currently developing but there some cases which I\'m clueless like when you do login you fire API call and wait for result naturally I wo
Edit: After a few months with this solution in place, I noticed that there are a few problems with it:
So I no longer recommend using this approach!
For normal user-initiated navigation, you don't need the BLoC pattern at all. Just use the Navigator
.
Login is a special case. Following the BLoC pattern, it would make sense to provide a isAuthenticated
stream:
abstract class MyBloc {
Stream<bool> get isAuthenticated;
}
Your app will probably have 2 different named route trees: One for logged in users, and one for anonymous users:
final Map<String, WidgetBuilder> anonymousRoutes = {
'/': (context) => new LoginScreen(), // default for anon
'/register': (context) => new RegisterScreen(),
};
final Map<String, WidgetBuilder> authenticatedRoutes = {
'/': (context) => new HomeScreen(), // default for logged in
'/savings': (context) => new SavingsScreen(),
// ...
};
Usually the Navigator
and its named routes are tightly coupled to the MaterialApp
, but you can also define your own that is rebuilt when the isAuthenticated
stream is updated:
class MyApp extends StatelessWidget {
const MyApp({Key key, this.bloc}) : super(key: key);
final MyBloc bloc;
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (BuildContext context, Widget child) {
return StreamBuilder<bool>(
stream: bloc.isAuthenticated,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData) {
return Text('loading...');
}
bool isAuthenticated = snapshot.data;
return _buildNavigator(isAuthenticated);
},
);
},
);
}
}
Navigator _buildNavigator(bool isAuthenticated) {
// different route tree and different default route depending on auth state
final routes = isAuthenticated ? authenticatedRoutes : anonymousRoutes;
return Navigator(
key: new ValueKey(isAuthenticated),
onGenerateRoute: (RouteSettings settings) {
final name = settings.name;
return new MaterialPageRoute(
builder: routes[name],
settings: settings,
);
},
onUnknownRoute: (RouteSettings settings) {
throw Exception('unknown route');
},
);
}
Sadly right now (2018-07-14) there are a 2 conflicting asserts in the Flutter code which you have to remove to make the code above work (you can just edit it with your IDE):
Line 93 and 96 in packages\flutter\lib\src\widgets\app.dart
//assert(navigatorObservers != null),
//assert(onGenerateRoute != null || navigatorObservers == const <NavigatorObserver>[]),