Reputation: 41
I try to do this, but it doesn't seem good.
If I remove the FutureBuilder
and the CircularProgressIndicator
it's OK.
But it will be good to have this for the time to loading data.
Is it possible ?
My source code:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:serialtrip/config/theme.dart';
import 'package:serialtrip/pages/home.dart';
import 'package:serialtrip/pages/login.dart';
import 'package:serialtrip/providers/authProvider.dart';
main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => AuthProvider(),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serialtrip',
debugShowCheckedModeBanner: false,
theme: defaultTheme,
home: context.watch<AuthProvider>().loggedInStatus == Status.LoggedIn
? Home()
: FutureBuilder(
future: context.read<AuthProvider>().autoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState == ConnectionState.waiting ? CircularProgressIndicator() : Login(),
),
);
}
}
And the error:
The following assertion was thrown building MyApp(dirty, dependencies: [_InheritedProviderScope<AuthProvider>]):
Tried to use `context.read<AuthProvider>` inside either a `build` method or the `update` callback of a provider.
This is unsafe to do so. Instead, consider using `context.watch<AuthProvider>`.
If you used `context.read` voluntarily as a performance optimisation, the solution
is instead to use `context.select`.
'package:provider/src/provider.dart':
Failed assertion: line 584 pos 9: 'debugIsInInheritedProviderCreate ||
(!debugDoingBuild && !debugIsInInheritedProviderUpdate)'
Upvotes: 1
Views: 4452
Reputation: 41
ok i have found a solution. I use the constructor of AuthProvider to call autoLogin() at the first launch of the app.
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:serialtrip/config/theme.dart';
import 'package:serialtrip/pages/home.dart';
import 'package:serialtrip/pages/login.dart';
import 'package:serialtrip/pages/splash.dart';
import 'package:serialtrip/providers/authProvider.dart';
main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => AuthProvider(),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serialtrip',
debugShowCheckedModeBanner: false,
theme: defaultTheme,
home: _showScreen(context),
);
}
}
Widget _showScreen(BuildContext context) {
switch (context.watch<AuthProvider>().loggedInStatus) {
case Status.Authenticating:
return Splash();
case Status.LoggedIn:
return Home();
default:
return Login();
}
}
authProvider.dart
import 'package:flutter/widgets.dart';
enum Status { NotLoggedIn, Authenticating, LoggedIn }
class AuthProvider with ChangeNotifier {
Status _loggedInStatus = Status.NotLoggedIn;
Status get loggedInStatus => _loggedInStatus;
/// Constructor
AuthProvider() {
_autoLogin();
}
/// Auto-login
Future<void> _autoLogin() async {
_loggedInStatus = Status.Authenticating;
notifyListeners();
print('autologin - waiting');
await new Future.delayed(const Duration(seconds: 5));
_loggedInStatus = Status.LoggedIn;
notifyListeners();
print('autologin - sucess');
}
/// Login
Future<void> login(String email, String password) async {
_loggedInStatus = Status.Authenticating;
notifyListeners();
print('login - waiting');
await new Future.delayed(const Duration(seconds: 2));
_loggedInStatus = Status.LoggedIn;
notifyListeners();
print('login - sucess');
}
/// Logout
Future<void> logout() async {
_loggedInStatus = Status.NotLoggedIn;
notifyListeners();
print('logout - sucess');
}
}
Upvotes: 2
Reputation: 2900
First Possibility
In order to se an affect of the autoLogin
function, you need to use Consumer
Widget _showScreen(BuildContext context) {
return Consumer<Status>(
builder: (context, loginStatus, child) {
switch (loginStatus) {
case Status.Authenticating:
return Splash();
case Status.LoggedIn:
return Home();
default:
return Login();
}
}
);
}
Update your autoLogin
function as follows.
Future<Status> autoLogin() async {
await new Future.delayed(const Duration(seconds: 2));
_loggedInStatus = Status.LoggedIn;
return _loggedInStatus;
}
Second Possibility(Recommended)
If you want to listen to loggedInState changes continuously, you need StreamProvider
since FutureProvier
listens to changes only once.
In this case,
MyApp Class
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serialtrip',
debugShowCheckedModeBanner: false,
theme: defaultTheme,
home: StreamProvider(
create: (_) => AuthProvider().autoLogin(),
initialData: Status.Authenticating,
child: _showScreen(context),
));
}
}
AutoLogin Stream
You need to change AutoLogin
from future to stream
Stream<Status> autoLogin() async* {
_loggedInStatus = Status.Authenticating;
yield _loggedInStatus;
await new Future.delayed(const Duration(seconds: 2));
_loggedInStatus = Status.LoggedIn;
yield _loggedInStatus;
}
Consumer
remains unchanged.
Widget _showScreen(BuildContext context) {
return Consumer<Status>(
builder: (context, loginStatus, child) {
switch (loginStatus) {
case Status.Authenticating:
return Splash();
case Status.LoggedIn:
return Home();
default:
return Login();
}
}
);
}
Upvotes: 0
Reputation: 41
My last try with FutureProvider but autologin is not call :(
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:serialtrip/config/theme.dart';
import 'package:serialtrip/pages/home.dart';
import 'package:serialtrip/pages/login.dart';
import 'package:serialtrip/pages/splash.dart';
import 'package:serialtrip/providers/authProvider.dart';
main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => AuthProvider(),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serialtrip',
debugShowCheckedModeBanner: false,
theme: defaultTheme,
home: FutureProvider(
create: (_) => AuthProvider().autoLogin(),
initialData: Status.Authenticating,
child: _showScreen(context),
));
}
}
Widget _showScreen(BuildContext context) {
switch (context.watch<AuthProvider>().loggedInStatus) {
case Status.Authenticating:
return Splash();
case Status.LoggedIn:
return Home();
default:
return Login();
}
}
authProvider.dart
import 'package:flutter/widgets.dart';
enum Status { NotLoggedIn, LoggedIn, Authenticating, LoggedOut }
class AuthProvider with ChangeNotifier {
Status _loggedInStatus;
String _token;
Status get loggedInStatus => _loggedInStatus;
String get token => _token;
Future<String> autoLogin() async {
_loggedInStatus = Status.Authenticating;
notifyListeners();
print('autologin - waiting');
await new Future.delayed(const Duration(seconds: 2));
_token = 'abcd1234';
_loggedInStatus = Status.LoggedIn;
notifyListeners();
print('autologin - sucess');
return _token;
}
Future login(String email, String password) async {
_loggedInStatus = Status.Authenticating;
notifyListeners();
print('login - waiting');
await new Future.delayed(const Duration(seconds: 2));
_token = 'abcd1234';
_loggedInStatus = Status.LoggedIn;
notifyListeners();
print('login - sucess');
}
Future logout() async {
_token = null;
_loggedInStatus = Status.LoggedOut;
notifyListeners();
print('logout - sucess');
}
}
Upvotes: 1
Reputation: 5601
Tried to use
context.read<AuthProvider>
inside either abuild
method or theupdate
callback of a provider
If you read the documentation you will notice that it discourage you tu use context.read inside the build method, use Provider.of<AuthProvider>(context, listen: false).autoLogin();
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serialtrip',
debugShowCheckedModeBanner: false,
theme: defaultTheme,
home: context.watch<AuthProvider>().loggedInStatus == Status.LoggedIn
? Home()
: FutureBuilder(
future: Provider.of<AuthProvider>(context, listen: false).autoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState == ConnectionState.waiting ? CircularProgressIndicator() : Login(),
),
);
}
}
Upvotes: 0