I am building simple authentication using Rest Api. Function are working but when I got token I want to move on mainPage of the Application. For this I used Consumer to build the Main Page using the bool value which I am getting from _auth.token
when the token is present but it is returning Stack Overflow Error.
The following StackOverflowError was thrown building Consumer<Auth>(dirty, dependencies:
[_InheritedProviderScope<Auth>]):
Stack Overflow
The relevant error-causing widget was:
Consumer<Auth>
My Code is main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:sole_entrepreneur/screens/business_overview_screen.dart';
import 'package:sole_entrepreneur/screens/splash_screen.dart';
// import './screens/selection_screen.dart';
import './screens/login_screen.dart';
import './screens/register_screen.dart';
import './screens/selection_screen.dart';
import './providers/auth.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// await Auth().signIn('[email protected]', 'Developer');
// await Auth().register(
// '[email protected]', "csdwx9spq", "matshary", "test", "testlast");
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => Auth(),
),
],
child: Consumer<Auth>(builder: (ctx, auth, _) {
// print(auth.isAuth);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
scaffoldBackgroundColor: Colors.white,
primaryColor: Color.fromRGBO(124, 116, 146, 1),
buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
appBarTheme: AppBarTheme(
color: Colors.white,
elevation: 0.0,
iconTheme: IconThemeData(color: Colors.black)),
),
home: auth.isAuth
? BusinessOverViewScreen()
: FutureBuilder(
builder: (context, authResultSnapshot) {
print(auth.isAuth);
return authResultSnapshot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: LoginScreen();
},
future: auth.tryAutoLogin(),
),
routes: {
LoginScreen.routeName: (ctx) => LoginScreen(),
RegisterScreen.routeName: (ctx) => RegisterScreen(),
BusinessOverViewScreen.routeName: (ctx) =>
BusinessOverViewScreen()
},
);
}));
}
}
auth.dart
import 'dart:convert';
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
class Auth with ChangeNotifier {
String _token;
DateTime _expiryDate;
int _userId;
Timer _authTimer;
List<dynamic> _userRole;
String _userEmail;
String _userNiceName;
String _userDisplayName;
String _userAvatar;
String message;
bool get isAuth {
return token != null;
}
String get token {
print(_expiryDate);
// print(_expiryDate.isAfter(DateTime.now()).toString());
if (_expiryDate != null &&
_expiryDate.isAfter(DateTime.now()) &&
_token != null) {
return token;
}
return null;
}
int get userId {
return _userId;
}
Future<void> authethicate(
String email,
String password,
) async {
try {
final url = 'https://soleentrepreneur.co.uk/wp-json/jwt-auth/v1/token';
final response = await http.post(
url,
body: {
'username': email,
'password': password,
},
);
print(
json.decode(response.body),
);
final responseData = json.decode(response.body);
if (responseData['message'] != null) {
throw HttpException(responseData['message']);
}
_token = responseData['token'];
_userEmail = responseData['user_email'];
_userNiceName = responseData['user_nicename'];
_userDisplayName = responseData['user_display_name'];
_userRole = responseData['user_role'];
_userId = responseData['user_id'];
_userAvatar = responseData['avatar'];
_expiryDate = DateTime.now().add(new Duration(days: 7));
notifyListeners();
SharedPreferences pref = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
'userEmail': _userEmail,
'userNiceName': _userNiceName,
'userDisplayName': _userDisplayName,
'userRole': _userRole,
'userAvatar': _userAvatar,
});
pref.setString('userData', userData);
} catch (error) {
throw (error);
}
}
Future<void> signIn(String email, String password) async {
await authethicate(email, password);
}
Future<void> register(String email, String password, String username,
String firstName, String lastName) async {
await registerAuth(email, username, password, firstName, lastName);
}
Future<void> registerAuth(String email, String username, String password,
String firstName, String lastName) async {
try {
final registerUrl =
'https://soleentrepreneur.co.uk/wp-json/wp/v2/users/register';
final response = await http.post(registerUrl,
headers: {'Content-Type': 'application/json'},
body: json.encode(
{
'username': username,
'password': password,
'email': email,
'first_name': firstName,
'last_name': lastName
},
));
final responseData = json.decode(response.body);
if (responseData['code'] != 200) {
throw HttpException(responseData['message']);
}
print(
json.decode(response.body),
);
message = responseData['message'];
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> logOut() async {
_userId = null;
_token = null;
_expiryDate = null;
if (_authTimer != null) {
_authTimer.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
prefs.clear();
}
Future<void> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
print(_token);
return false;
}
final extractedUserData =
json.decode(prefs.getString('userData')) as Map<String, Object>;
final expiryDate = DateTime.parse(extractedUserData['expiryDate']);
if (expiryDate.isBefore(DateTime.now())) {
print(_token);
return false;
}
_token = extractedUserData['token'];
_userId = extractedUserData['userId'];
_expiryDate = expiryDate;
_userEmail = extractedUserData['user_email'];
_userDisplayName = extractedUserData['user_display_name'];
_userNiceName = extractedUserData['user_nicename'];
_userRole = extractedUserData['user_role'];
_userAvatar = extractedUserData['avatar'];
notifyListeners();
_autoLogOut();
print(_token);
return true;
}
void _autoLogOut() {
if (_authTimer != null) {
_authTimer.cancel();
}
final timeToExpiry = _expiryDate.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timeToExpiry), logOut);
}
}
login.dart
import 'dart:io';
import 'package:flutter/material.dart';
import '../providers/auth.dart';
import '../widgets/button.dart';
import '../widgets/text_form_field_style.dart';
import 'package:provider/provider.dart';
import '../models/httpException.dart';
class LoginScreen extends StatefulWidget {
static const routeName = '/login';
@override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final GlobalKey<FormState> _formKey = GlobalKey();
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(message),
title: Text('An Error Occured'),
actions: [
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Okay'))
],
);
},
);
}
Future<void> _submit() async {
if (!_formKey.currentState.validate()) {
print('not Returning');
return;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try {
await Provider.of<Auth>(context, listen: false)
.signIn(_authData['email'], _authData['password']);
} on HttpException catch (error) {
var errormessage = 'Authethication failed';
if (error.toString().contains('Unknown email address.')) {
errormessage =
'Unknown email address. Check again or try your username';
} else if (error.toString().contains('[jwt_auth] incorrect_password')) {
errormessage =
'The password you entered for the email address is incorrect.';
} else if (error.toString().contains('[jwt_auth] invalid_username')) {
errormessage = 'This email is not valid';
}
_showErrorDialog(errormessage);
} catch (error) {
var errormessage = 'Could not authenticate you. Please try again later';
print(error);
_showErrorDialog(errormessage);
}
setState(() {
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Column(
children: [
Expanded(
child: Container(
margin: EdgeInsets.all(MediaQuery.of(context).size.width / 5),
child: Image.asset('assets/Logo.png'),
color: Colors.blue,
),
),
Expanded(
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: [
buildTextFormStyle(
MediaQuery.of(context).size.height / 9,
TextFormField(
decoration: InputDecoration(
labelText: 'Email',
border: InputBorder.none,
contentPadding: EdgeInsets.all(5),
),
keyboardType: TextInputType.emailAddress,
// ignore: missing_return
validator: (value) {
if (value.isEmpty || !value.contains('@'))
return 'Invalid email!';
},
onSaved: (newValue) {
_authData['email'] = newValue;
},
),
),
SizedBox(height: 10),
buildTextFormStyle(
MediaQuery.of(context).size.height / 9,
TextFormField(
decoration: InputDecoration(
labelText: 'Password',
border: InputBorder.none,
contentPadding: EdgeInsets.all(5),
),
obscureText: true,
// ignore: missing_return
validator: (value) {
if (value.isEmpty || value.length < 5)
return 'Password is too short!';
},
onSaved: (newValue) {
_authData['password'] = newValue;
},
),
),
if (_isLoading)
CircularProgressIndicator()
else
AppButton(name: 'LOGIN', onPressed: _submit),
],
),
),
),
),
],
),
),
);
}
}
//Text Field Style
The Error is due to getter method of the Auth. Where i returning the getter token
but i have to return _token
string which i am getting after logging in.Due to Name Confusion i am returning getter over and over again.