problem automatic log off when I navigate between tabs (Firebase Auth rest API) - flutter

Hi I'm building an app and I'm using authentication using Firebase Auth rest API but the problem is that when I navigate between my tabs my app logOut automatically I don't know if it's expiration of token problem or something else so can some one help with that?
this is my auth part it's in my provider package
class Auth with ChangeNotifier {
String _token;
String _userId;
bool get isAuth {
return token != null;
}
String get token{
return _token;
}
String get userId {
return _userId;
}
Future<void> signup(String email, String password) async {
final url = Uri.parse(
'https://...myurl...'
);
try {
final response = await http.post(url,body: json.encode(
{
'email': email,
'password':password,
'returnSecureToken': true,
},), );
final responseData = json.decode(response.body);
if(responseData['error'] != null){
throw Exception();
}
_token = responseData['idToken'];
_userId = responseData['localId'];
notifyListeners();
} catch (error) {
throw error;
} }
Future<void> login(String email, String password) async {
final url = Uri.parse( 'https://...myurl...' );
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password':password,
'returnSecureToken': true,
},),);
} catch (error) {
throw error;
} }}
this is the Ath screen:
enum AuthMode { Signup, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
bool _isLoading= false;
return Scaffold(
backgroundColor: Colors.pinkAccent[100],
body: SizedBox(
height: double.infinity,
child: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.all(8),
margin: EdgeInsets.all(8),
child: Expanded(
child:
SizedBox(
height: 280,
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 60,
child: LogoBekery(
color1:Colors.white,
color2:Colors.white,
color3:Colors.white,
),
),
SizedBox(
child: ImageSlideshow(
isLoop: true,
width: double.infinity,
height: 250,
initialPage: 0,
indicatorColor: Colors.pink,
indicatorBackgroundColor: Colors.grey,
children: [
Image.asset(
'assets/images/logoA.png',
fit: BoxFit.fill,
),
Image.asset(
'assets/images/logoB.png',
fit: BoxFit.fill,
),
Image.asset(
'assets/images/logoC.png',
fit: BoxFit.fill,
),
Image.asset(
'assets/images/logoD.png',
fit: BoxFit.fill,
),
],
onPageChanged: (value) {
// print('Page changed: $value');
},
autoPlayInterval: 3000,
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: AuthCard(),
),
],
),
),
),
],
),
),
);
}
void _submitAuthForm(
String email,
String password,
String username,
bool isLogin,
BuildContext ctx,
)
async {
UserCredential authResult; }
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
Future<void> _submit() async{
if (!_formKey.currentState.validate()) {
// Invalid!
return;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] ,
_authData['password'] );
} else {
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] ,
_authData['password'] );
}
Navigator.of(context).pushReplacementNamed(ProductOverviewScreen.routeName);
} on Exception catch (error) {
var errorMsg = 'Authentification Failed!';
}catch (error){
var errorMsg = 'Could not authentificate! please try later...';
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.Signup ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 150 : 260),
width: deviceSize.width * 0.8,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (!RegExp(r'\S+#\S+\.\S+').hasMatch(value)) {
return 'Invalid email!';
}
return null;
return null;
},
onSaved: (value) {
_authData['email'] = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value.isEmpty || value.length < 5) {
return 'Password is too short!';
}
},
onSaved: (value) {
_authData['password'] = value;
},
),
if (_authMode == AuthMode.Signup)
TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
}
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
RaisedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 8.0),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).primaryTextTheme.button.color,
),
FlatButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'}'),
onPressed: _switchAuthMode,
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}

Your _token and _userId is only set after registering. You don't set it after loging in. Therefore token could be null and isAuth will return false.
I think you should set the value of _token and _userId after the login function.
Future<void> login(String email, String password) async {
final url = Uri.parse('https://...myurl...');
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
'returnSecureToken': true,
},
),
);
// added from here
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw Exception();
}
_token = responseData['idToken'];
_userId = responseData['localId'];
// to here.
} catch (error) {
throw error;
}
}

Related

how to store Strings from TextFormField to another page

I have three text form fields on the sign-in page
There are two of them for username and password that work well, I have no problem with them
But the first one is for entering the domain (it is programmed so that each client has its own domain), which is my problem.
I want that when the user enters his domain, the URL of the program, which is in the IP page, is changed and the sign-in page is called only once, without the need to call other pages.
thsis is signIn page code:
I suggest that you pay attention to _signIn and ElevatedButton.
import 'package:flutter/material.dart';
import 'package:mis_project/api/my_api.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:mis_project/conts/myString.dart';
import '../auth/auth_page.dart';
import '../conts/colors.dart';
import '../conts/mSize.dart';
class SignIn extends StatefulWidget {
const SignIn({Key key}) : super(key: key);
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
String postDomain;
bool isLoading = false;
PageController _pageController;
List<TextEditingController> tecList;
#override
void initState() {
super.initState();
_pageController = PageController();
tecList = List.generate(3, (index) {
return TextEditingController();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
_showModalBottomSheet(context);
});
}
_signIn() async {
print('Sign is is called');
var data = {
'email': tecList[1].text,
'password': tecList[2].text,
};
var jsonResponse = null;
SharedPreferences localStorage = await SharedPreferences.getInstance();
var response = await CallApi().postData(data, 'login');
jsonResponse = json.decode(response.body);
if (jsonResponse != null) {
setState(() {});
localStorage.setString('token', jsonResponse['token']);
Navigator.push(
context, MaterialPageRoute(builder: (context) => AuthPage()));
} else {
setState(() {});
}
}
final _formKey = GlobalKey<FormState>();
#override
void dispose() {
for (var tec in tecList) {
tec.dispose();
}
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: background_page,
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/image/background.jpg'),
fit: BoxFit.cover),
),
),
);
}
void _showModalBottomSheet(BuildContext context) {
showModalBottomSheet<void>(
elevation: 30,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(30),
),
),
context: context,
builder: (BuildContext context) {
return SizedBox(
height: mDeviceSize(context).height * 0.71,
width: mDeviceSize(context).width,
child: PageView.builder(
controller: _pageController,
itemCount: 3,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
top: 40, left: 25, right: 25, bottom: 15),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
textAlign: TextAlign.left,
textInputAction: TextInputAction.go,
style: TextStyle(color: Color(0xFF000000)),
cursorColor: view_all_color_HP,
controller: tecList[index],
keyboardType: TextInputType.text,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: view_all_color_HP,
),
),
contentPadding: EdgeInsets.symmetric(
vertical: 5.0, horizontal: 10),
labelText: signing_input_label[index],
labelStyle: TextStyle(color: view_all_color_HP),
floatingLabelBehavior: FloatingLabelBehavior.auto,
border: OutlineInputBorder(),
alignLabelWithHint: true,
hintStyle: TextStyle(
color: view_all_color_HP,
fontSize: 15,
fontWeight: FontWeight.normal),
),
autofocus: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {
int nextPage = index + 1;
if (nextPage < 3) {
_pageController.animateToPage(nextPage,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
}
if (index == 0) {
postDomain = tecList[0].text;
print('domain post is : $postDomain');
print('domain value is: ${tecList[0].text}');
}
if (index == 1) {
print('email value is: ${tecList[1].text}');
}
if (index == 2) {
print('pass: ${tecList[2].text}');
_signIn();
}
},
child: Text(signing_button_label[index]),
style: ElevatedButton.styleFrom(
elevation: 0,
primary: view_all_color_HP,
fixedSize:
Size(mDeviceSize(context).width * 0.3, 5),
minimumSize: Size(0, 45),
),
),
SizedBox(
height: MediaQuery.of(context).viewInsets.bottom,
),
],
),
),
),
],
);
},
),
);
},
);
}
}
and this is my APi page
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
class CallApi{
final String _urlF = 'https://';
final String _urlE = '.lajwardsoftwares.com/api/v1/';
postData(data, apiUrl) async {
var fullUrl = _urlF + _urlE + apiUrl + await _getToken();
print('full url is: $fullUrl');
return await http.post(
Uri.parse(fullUrl),
body: jsonEncode(data),
headers: _setHeaders()
);
}
getData(apiUrl) async {
var fullUrl = _urlF + apiUrl + await _getToken();
return await http.get(
Uri.parse(fullUrl),
headers: _setHeaders()
);
}
_setHeaders() => {
'Content-type' : 'application/json',
'Accept' : 'application/json',
};
_getToken() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var token = localStorage.getString('token');
return '?token=$token';
// print("saied: getToken ${localStorage.getString('token')}"),};
}
}
i want this .lajwardsoftwares.com to stored from TextFromField
thanks

Why I can't see the result of "print()" statement in my Flutter code?

I am trying to write a simple signup/login page. The following codes are the main.dart, screen page for the view and the auth_controller for the control page of the project.
main.dart:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
],
child: Consumer<Auth>(
builder: (ctx, auth, _) => MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: auth.isAuth
? MapScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: AuthScreen(),
),
routes: {
MapScreen.routeName: (ctx) => MapScreen(),
},
),
),
);
}
}
auth_screen.dart:
enum AuthMode { Signup, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
// final transformConfig = Matrix4.rotationZ(-8 * pi / 180);
// transformConfig.translate(-10.0);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color.fromRGBO(215, 117, 255, 1).withOpacity(0.5),
const Color.fromRGBO(255, 188, 117, 1).withOpacity(0.9),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: const [0, 1],
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: const EdgeInsets.only(bottom: 20.0),
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 94.0),
transform: Matrix4.rotationZ(-8 * pi / 180)
..translate(-10.0),
// ..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.deepOrange.shade900,
boxShadow: const [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'USmobile',
style: TextStyle(
color: Theme.of(context)
.textSelectionTheme
.selectionColor,
fontSize: 50,
fontFamily: 'Anton',
fontWeight: FontWeight.normal,
),
),
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: const AuthCard(),
),
],
),
),
),
],
),
);
}
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key? key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard>
with SingleTickerProviderStateMixin {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
AnimationController? _controller;
Animation<Offset>? _slideAnimation;
Animation<double>? _opacityAnimation;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 300,
),
);
_slideAnimation = Tween<Offset>(
begin: const Offset(0, -1.5),
end: const Offset(0, 0),
).animate(
CurvedAnimation(
parent: _controller as Animation<double>,
curve: Curves.fastOutSlowIn,
),
);
_opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller as Animation<double>,
curve: Curves.easeIn,
),
);
// _heightAnimation.addListener(() => setState(() {}));
}
#override
void dispose() {
super.dispose();
_controller!.dispose();
}
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('An Error Occurred!'),
content: Text(message),
actions: <Widget>[
TextButton(
child: const Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
);
}
Future<void> _submit() async {
if (!_formKey.currentState!.validate()) {
// Invalid!
return;
}
_formKey.currentState!.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] as String,
_authData['password'] as String,
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] as String,
_authData['password'] as String,
);
}
// } on HttpException catch (error) {
// var errorMessage = 'Authentication failed';
// print("this is the auth data");
// print(_authData);
// if (error.toString().contains('EMAIL_EXISTS')) {
// errorMessage = 'This email address is already in use.';
// } else if (error.toString().contains('INVALID_EMAIL')) {
// errorMessage = 'This is not a valid email address';
// } else if (error.toString().contains('WEAK_PASSWORD')) {
// errorMessage = 'This password is too weak.';
// } else if (error.toString().contains('EMAIL_NOT_FOUND')) {
// errorMessage = 'Could not find a user with that email.';
// } else if (error.toString().contains('INVALID_PASSWORD')) {
// errorMessage = 'Invalid password.';
// }
// _showErrorDialog(errorMessage);
} catch (error) {
var errorMessage = 'Could not authenticate you. Please try again later.' +
error.toString();
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
_controller!.forward();
} else {
setState(() {
_authMode = AuthMode.Login;
});
_controller!.reverse();
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
height: _authMode == AuthMode.Signup ? 320 : 260,
// height: _heightAnimation.value.height,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty || !value.contains('#')) {
return 'Invalid email!';
}
},
onSaved: (value) {
_authData['email'] = value as String;
},
),
TextFormField(
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return 'Password is too short!';
}
},
onSaved: (value) {
_authData['password'] = value as String;
},
),
AnimatedContainer(
constraints: BoxConstraints(
minHeight: _authMode == AuthMode.Signup ? 60 : 0,
maxHeight: _authMode == AuthMode.Signup ? 120 : 0,
),
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
child: FadeTransition(
opacity: _opacityAnimation as Animation<double>,
child: SlideTransition(
position: _slideAnimation as Animation<Offset>,
child: TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: const InputDecoration(
labelText: 'Confirm Password'),
obscureText: true,
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
}
}
: null,
),
),
),
),
const SizedBox(
height: 20,
),
if (_isLoading)
const CircularProgressIndicator()
else
ElevatedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
primary: Theme.of(context).primaryColor,
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 8.0),
onPrimary:
Theme.of(context).primaryTextTheme.button!.color,
),
),
TextButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} '),
onPressed: _switchAuthMode,
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 4),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
textStyle: TextStyle(color: Theme.of(context).primaryColor),
),
),
],
),
),
),
),
);
}
}
auth_controller.dart:
class Auth with ChangeNotifier {
String? _token;
DateTime? _expiryDate;
String? _userId;
Timer? _authTimer;
bool get isAuth {
return token != null;
}
String? get token {
if (_expiryDate != null &&
_expiryDate!.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
String? get userId {
return _userId;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
try {
final http.Response response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: json.encode(
{
'email': email,
'password': password,
//'returnSecureToken': true,
},
),
);
print("This is response.body");
print(response.body);
print("This is response.body.runtimeType");
print(response.body.runtimeType);
final responseData = json.decode(response.body);
print("this is responseData");
print(responseData);
print("this is responseData['error']");
print(responseData['error']);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
} else {
print("There wasn't error here!");
}
_token = responseData['idToken'];
print("This is the token");
print(_token);
_userId = responseData['id'];
print("This is userId");
print(_userId);
print("This is expiryDate");
print(responseData['expiresIn']);
_expiryDate = DateTime.now().add(
Duration(
seconds: int.parse(
responseData['expiresIn'],
),
),
);
print("I can no see thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis");
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate!.toIso8601String(),
},
);
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'verifyPassword');
}
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final extractedUserData = json.decode(prefs.getString('userData') as String)
as Map<String, Object>;
final expiryDate =
DateTime.parse(extractedUserData['expiryDate'] as String);
if (expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'] as String;
_userId = extractedUserData['userId'] as String;
_expiryDate = expiryDate;
notifyListeners();
_autoLogout();
return true;
}
Future<void> logout() async {
_token = null;
_userId = null;
_expiryDate = null;
if (_authTimer != null) {
_authTimer!.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
// prefs.remove('userData');
prefs.clear();
}
void _autoLogout() {
if (_authTimer != null) {
_authTimer!.cancel();
}
final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timeToExpiry), logout);
}
}
I know the backend part works fine and the following is the result I do get while running my app and try to register a new user through the Android Emulator:
I/flutter ( 6814): This is response.body
I/flutter ( 6814): {"id":"619c5141e08b15bf9173ab06","name":"","email":"test#testing.com","password":"$2a$10$yYUtDS1PrSAgpQBxoVm7Ae7O8ujR33ONz4gM5t7iHWt6e907pjFrq","idToken":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0QHRlc3RpbmcuY29tIiwiZXhwIjoxNjM5Mjc1NjAzNzQzfQ.LgrlwFNrLhGr5UfHikL83e2tBjbqMyN4OKG6Fz816AeOs6ezfnhvQoXBDAsV2pIt4CWuBVf8qGbBYSXCQxgarw","expiresIn":1639275603743}
I/flutter ( 6814): This is response.body.runtimeType
I/flutter ( 6814): String
I/flutter ( 6814): this is responseData
I/flutter ( 6814): {id: 619c5141e08b15bf9173ab06, name: , email: test#testing.com, password: $2a$10$yYUtDS1PrSAgpQBxoVm7Ae7O8ujR33ONz4gM5t7iHWt6e907pjFrq, idToken: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0QHRlc3RpbmcuY29tIiwiZXhwIjoxNjM5Mjc1NjAzNzQzfQ.LgrlwFNrLhGr5UfHikL83e2tBjbqMyN4OKG6Fz816AeOs6ezfnhvQoXBDAsV2pIt4CWuBVf8qGbBYSXCQxgarw, expiresIn: 1639275603743}
I/flutter ( 6814): this is responseData['error']
I/flutter ( 6814): null
I/flutter ( 6814): There wasn't error here!
I/flutter ( 6814): This is the token
I/flutter ( 6814): eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0QHRlc3RpbmcuY29tIiwiZXhwIjoxNjM5Mjc1NjAzNzQzfQ.LgrlwFNrLhGr5UfHikL83e2tBjbqMyN4OKG6Fz816AeOs6ezfnhvQoXBDAsV2pIt4CWuBVf8qGbBYSXCQxgarw
I/flutter ( 6814): This is userId
I/flutter ( 6814): 619c5141e08b15bf9173ab06
I/flutter ( 6814): This is expiryDate
I/flutter ( 6814): 1639275603743
I see all the print() statements work except this:
print("I can no see thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis");
I don't know why? I also see the following error message in my Android Emulator that I can't understand the reason?
type 'int' is not a subtype of type 'String'
I also know the error occures in this part of the code in auth_controller.dart file:
} catch (error) {
print(error);
throw error;
}
int.parse(
responseData['expiresIn'],
)
For the above code to work responseData['expiresIn'] should be a String. But in the response, this comes as an int value. Make sure this is a String.
Or you can just use it like this,
Duration(
seconds: responseData['expiresIn'],
),

How keep user logged in flutter

I posted yesterday this question but i didn't get any valid answer. My current situation is i can successfully log the user in but when i restart the app i have to login again so i need to save the details of the user in a shared preference so that the user can stay logged for the entire session until logout.But i am unable to do that so please help me with it. Thanks in advance
login.dart :
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(3, 9, 23, 1),
body: Container(
padding: EdgeInsets.only(
top: 100,
right: 30,
left: 30,
),
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FadeAnimation(
1.2,
Container(
padding: EdgeInsets.all(70.0),
margin: EdgeInsets.only(bottom: 50.0),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/trakinglogo.png'))),
)),
SizedBox(
height: 30,
),
FadeAnimation(
1.5,
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey[300]))),
child: TextFormField(
controller: _emailController,
onFieldSubmitted: (_) =>
FocusScope.of(context).nextFocus(),
textInputAction: TextInputAction.done,
validator: (value) {
if (value.isEmpty) {
return 'Email is required';
}
return null;
},
decoration: InputDecoration(
border: InputBorder.none,
hintStyle: TextStyle(
color: Colors.grey.withOpacity(.8)),
hintText: "Votre adresse mail"),
),
),
Container(
decoration: BoxDecoration(),
child: TextFormField(
controller: _passwordController,
validator: (value) {
if (value.isEmpty) {
return 'Password is required';
}
return null;
},
obscureText: _isHidden,
decoration: InputDecoration(
border: InputBorder.none,
hintStyle: TextStyle(
color: Colors.grey.withOpacity(.8)),
hintText: "Mot de passe",
suffix: InkWell(
onTap: _togglePasswordView,
child: Icon(
_isHidden
? (CommunityMaterialIcons
.eye_outline)
: (CommunityMaterialIcons.eye_off),
color: Color(0xFF939394),
SizedBox(
height: 40,
),
FadeAnimation(
1.8,
Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: RaisedButton(
textColor: Colors.white,
color: kPrimaryColor,
child: Text("Se connecter"),
onPressed: () async {
if (_formKey.currentState.validate()) {
showDialog(
context: context,
builder: (BuildContext context) {
return Center(
child:
CircularProgressIndicator(),
);
});
await loginUser();
}
/* Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyWidget()),
);*/
// Navigator.pushNamed(context, 'Mywidget');
},
shape: new RoundedRectangleBorder(
borderRadius:
new BorderRadius.circular(30.0),
),
),
width: 250,
padding: EdgeInsets.all(15),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AlreadyHaveAnAccountCheck(
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return SignUp();
void loginUser() async {
// if (_formKey.currentState.validate()) {
setState(() {
_isLoading = true;
});
String email = _emailController.text;
String password = _passwordController.text;
authentication.login(email, password).then((user) {
if (user != null)
Navigator.push(
context, MaterialPageRoute(builder: (context) => MyWidget()));
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(error.toString())));
});
setState(() {
_isLoading = false;
});
}
and this is login function :
Future<User> login(String email, String password) async {
await checkInternet();
Map<String, String> headers = {
'Content-type': 'application/json',
'Accept': 'application/json',
};
Map<String, String> body = {'email': email, 'password': password};
var response = await http.post(Uri.parse(ApiUtil.AUTH_LOGIN),
headers: headers, body: jsonEncode(body));
switch (response.statusCode) {
case 200:
var body = jsonDecode(response.body);
var data = body['user'];
User user = User.fromJson(data);
Track track = Track.fromJson(body);
if (body['code'] == 0) {
SharedPreferences localStorage =
await SharedPreferences.getInstance();
localStorage.setInt('id', body['user']['id']);
localStorage.setString('adress', body['user']['adress']);
localStorage.setString('phone', body['user']['phone']);
localStorage.setString('access_token', body['access_token']);
localStorage.setString('user', json.encode(body['user']));
String user = localStorage.getString('user');
}
return user;
case 500:
throw ('Erreur serveur');
break;
case 400:
throw LoginFailed();
default:
throw ('connection timeout');
break;
}
}
When i do the first login i'm saving the data on the shared preferences
ApiRepository.get().login(LoginRequest(username: _emailController.text, password: _passwordController.text)).then((response) async {
if (response != null) {
//save on the shared preferences that the user is logged in
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool(SHARED_LOGGED, true);
await prefs.setString(SHARED_USER, _emailController.text);
await prefs.setString(SHARED_PASSWORD, _passwordController.text);
}
}).catchError((error) {
});
Everytime i'm opening the app i have a splashscreen, here i do an implicit login and than i make skip the login page and bring the user on the home page
void checkUserIsLogged() async {
final prefs = await SharedPreferences.getInstance();
if ((prefs.getBool(SHARED_LOGGED) != null) && prefs.getBool(SHARED_LOGGED)) {
ApiRepository.get().login(LoginRequest(username: prefs.getString(SHARED_USER), password: prefs.getString(SHARED_PASSWORD))).then((response) {
if (response != null) {
//"do something"
}
}).catchError((error) {
});
} else {
}
}
FULL code
SplashPageLoading.dart
class SplashPageLoading extends StatefulWidget {
#override
_SplashPageLoadingState createState() => _SplashPageLoadingState();
}
class _SplashPageLoadingState extends State<SplashPageLoading> {
bool _doLogin = false;
#override
void initState() {
super.initState();
new Future.delayed(const Duration(seconds: 3), () => checkUserIsLogged());
}
void checkUserIsLogged() async {
final prefs = await SharedPreferences.getInstance();
if ((prefs.getBool(SHARED_LOGGED) != null) && prefs.getBool(SHARED_LOGGED)) {
setState(() {
_doLogin = true;
});
ApiRepository.get().login(LoginRequest(username: prefs.getString(SHARED_USER), password: prefs.getString(SHARED_PASSWORD))).then((response) {
if (response != null) {
Navigator.of(context).pushReplacementNamed(HomePage.routeName);
}
}).catchError((error) {
Navigator.of(context).pushReplacementNamed(LoginPage.routeName);
});
} else {
new Future.delayed(const Duration(seconds: 1), () => Navigator.of(context).pushReplacementNamed(LoginPage.routeName));
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
_doLogin ? "Login.." : "No data for login",
style: TextStyle(color: Colors.black),
),
),
);
}
}
Strings.dart
const String SHARED_LOGGED = "USER_IS_LOGGED";
const String SHARED_USER = "USER";
const String SHARED_PASSWORD = "PASSWORD";
shared preferences library
SplashPageLoading.dart :
class SplashPageLoading extends StatefulWidget {
#override
_SplashPageLoadingState createState() => _SplashPageLoadingState();
}
class _SplashPageLoadingState extends State<SplashPageLoading> {
bool _doLogin = false;
Authentication authentication = Authentication();
static const String SHARED_LOGGED = "USER_IS_LOGGED";
static const String SHARED_USER = "USER";
static const String SHARED_PASSWORD = "PASSWORD";
#override
void initState() {
super.initState();
new Future.delayed(const Duration(seconds: 3), () => checkUserIsLogged());
}
void checkUserIsLogged() async {
final prefs = await SharedPreferences.getInstance();
if ((prefs.getBool(SHARED_LOGGED) != null) &&
prefs.getBool(SHARED_LOGGED)) {
setState(() {
_doLogin = true;
});
authentication
.login(prefs.getString(SHARED_USER), prefs.getString(SHARED_PASSWORD))
.then((user) {
if (user != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyWidget()),
);
// Navigator.of(context).pushReplacementNamed('/splash');
}
}).catchError((error) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyWidget()),
);
// Navigator.of(context).pushReplacementNamed('/splash');
});
} else {
new Future.delayed(const Duration(seconds: 1),
() => Navigator.of(context).pushReplacementNamed('/'));
}
}
#override
Widget build(BuildContext context) {
return Text(
_doLogin ? "Login.." : "",
style: TextStyle(color: Colors.white),
);
}
}

Is it possible to POST Data using localhost woocommerce rest api in flutter

Is it possible to POST data from flutter app to woocommerce localhost using woocommerce localhost server rest api.
i have GET & POST data with private domain but i want to POST & GET data with localhost woocommerce rest api. i have setup my wordpress and woocommerce on localhost I am trying to make flutter ecommerce app and trying to GET & POST data from woocommerce localhost. but its not working and i dont want to send from private domain rest api, i can get data on postman if i select OAuth 1.0 but if i dont use OAuth 1.0 i cant get data.
Config.dart
class Config {
static String key =
'ck_00000000000000000000000000';
static String sceret =
'cs_00000000000000000000000000';
static String url = 'http://10.0.2.2:80/wordpress_new/wp-json/wc/v3/';
static String customerURL = 'customers';
}
customer.dart
class CustomerModel {
String email;
String firstName;
String lastName;
String password;
CustomerModel({
this.email,
this.firstName,
this.lastName,
this.password,
});
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {};
map.addAll({
'email': email,
'first_name': firstName,
'last_name': lastName,
'password': password,
'username': email,
});
return map;
}
}
apiservice.dart
class APIService {
Future<bool> createCustomer(CustomerModel model) async {
var authToken = base64.encode(
utf8.encode(Config.key + ':' + Config.sceret),
);
bool ret = false;
try {
var response = await Dio().post(
Config.url +
Config.customerURL,
data: model.toJson(),
options: new Options(headers: {
HttpHeaders.authorizationHeader: 'Basic $authToken',
HttpHeaders.contentTypeHeader: 'application/json',
}));
if (response.statusCode == 201) {
ret = true;
}
} on DioError catch (e) {
if (e.response.statusCode == 404) {
print(e.response.statusCode);
ret = false;
} else {
print(e.message);
print(e.request);
ret = false;
}
}
return ret;
}
Future<LoginResponseModel> loginCustomer(
String username,
String password,
) async {
LoginResponseModel model;
try {
var response = await Dio().post(Config.tokenURL,
data: {
'username': username,
'password': password,
},
options: new Options(headers: {
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded',
}));
if (response.statusCode == 200) {
model = LoginResponseModel.fromJson(response.data);
}
} on DioError catch (e) {
print(e.message);
}
return model;
}
}
signuppage.dart
class SignupPage extends StatefulWidget {
#override
_SignupPageState createState() => _SignupPageState();
}
class _SignupPageState extends State<SignupPage> {
APIService apiService;
CustomerModel model;
GlobalKey<FormState> globalKey = GlobalKey<FormState>();
bool hidePassword = true;
bool isApiCallProcess = false;
#override
void initState() {
apiService = new APIService();
model = new CustomerModel();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
automaticallyImplyLeading: true,
title: Text('Sign Up'),
),
body: ProgressHUD(
child: Form(
key: globalKey,
child: _formUI(),
),
inAsyncCall: isApiCallProcess,
opacity: 0.3),
);
}
Widget _formUI() {
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10.00),
child: Container(
child: Align(
alignment: Alignment.topLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
FormHelper.fieldLabel('First Name'),
FormHelper.textInput(
context,
model.firstName,
(value) => {
this.model.firstName = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter First Name.';
}
return null;
},
),
FormHelper.fieldLabel('Last Name'),
FormHelper.textInput(
context,
model.lastName,
(value) => {
this.model.lastName = value,
},
onValidate: (value) {
return null;
},
),
FormHelper.fieldLabel('Email Id'),
FormHelper.textInput(
context,
model.email,
(value) => {
this.model.email = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter Email id.';
}
if (value.isNotEmpty && !value.toString().isValidEmail()) {
return 'Please enter valid email id';
}
},
),
FormHelper.fieldLabel('Password'),
FormHelper.textInput(
context,
model.password,
(value) => {
this.model.password = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter Password.';
}
return null;
},
obscureText: hidePassword,
suffixIcon: IconButton(
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
color: Theme.of(context).accentColor.withOpacity(0.4),
icon: Icon(
hidePassword ? Icons.visibility_off : Icons.visibility,
),
),
),
SizedBox(
height: 20,
),
Center(
child: FormHelper.saveButton(
'Register',
() {
if (validateAndSave()) {
print(model.toJson());
setState(() {
isApiCallProcess = true;
});
apiService.createCustomer(model).then(
(ret) {
setState(() {
isApiCallProcess = false;
});
if (ret) {
FormHelper.showMessage(
context,
'WooCommerce App',
'Registration Successfull',
'Ok',
() {
Navigator.of(context).pop();
},
);
} else {
FormHelper.showMessage(
context,
'WooCommerce App',
'Email Id already registered.',
'Ok',
() {
Navigator.of(context).pop();
},
);
}
},
);
}
},
),
)
],
),
),
),
),
);
}
bool validateAndSave() {
final form = globalKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
}
form_helper.dart
class FormHelper {
static Widget textInput(
BuildContext context,
Object initialValue,
Function onChanged, {
bool isTextArea = false,
bool isNumberInput = false,
obscureText: false,
Function onValidate,
Widget prefixIcon,
Widget suffixIcon,
}) {
return TextFormField(
initialValue: initialValue != null ? initialValue.toString() : "",
decoration: fieldDecoration(
context,
"",
"",
suffixIcon: suffixIcon,
),
obscureText: obscureText,
maxLines: !isTextArea ? 1 : 3,
keyboardType: isNumberInput ? TextInputType.number : TextInputType.text,
onChanged: (String value) {
return onChanged(value);
},
validator: (value) {
return onValidate(value);
},
);
}
static InputDecoration fieldDecoration(
BuildContext context,
String hintText,
String helperText, {
Widget prefixIcon,
Widget suffixIcon,
}) {
return InputDecoration(
contentPadding: EdgeInsets.all(6),
hintText: hintText,
helperText: helperText,
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 1,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 1,
),
),
);
}
static Widget fieldLabel(String labelName) {
return new Padding(
padding: EdgeInsets.fromLTRB(0, 5, 0, 10),
child: Text(
labelName,
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
);
}
static Widget saveButton(String buttonText, Function onTap,
{String color, String textColor, bool fullWidth}) {
return Container(
height: 50.0,
width: 150,
child: GestureDetector(
onTap: () {
onTap();
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.redAccent,
style: BorderStyle.solid,
width: 1.0,
),
color: Colors.redAccent,
borderRadius: BorderRadius.circular(30.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(
buttonText,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
letterSpacing: 1,
),
),
),
],
),
),
),
);
}
static void showMessage(
BuildContext context,
String title,
String message,
String buttonText,
Function onPressed,
) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(title),
content: new Text(message),
actions: [
new FlatButton(
onPressed: () {
return onPressed();
},
child: new Text(buttonText),
)
],
);
},
);
}
}
progressHUD.dart
class ProgressHUD extends StatelessWidget {
final Widget child;
final bool inAsyncCall;
final double opacity;
final Color color;
final Animation<Color> valueColor;
ProgressHUD({
Key key,
#required this.child,
#required this.inAsyncCall,
this.opacity = 0.3,
this.color = Colors.grey,
this.valueColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
List<Widget> widgetList = new List<Widget>();
widgetList.add(child);
if (inAsyncCall) {
final modal = new Stack(
children: [
new Opacity(
opacity: opacity,
child: ModalBarrier(dismissible: false, color: color),
),
new Center(child: new CircularProgressIndicator()),
],
);
widgetList.add(modal);
}
return Stack(
children: widgetList,
);
}
}

Unable to identify source of exception error: Flutter

Image of code that occurs with error
I am going through a udemy Flutter course and I do not understand why the try catch cannot handle the error with the if statement inside inside of the try{}. I have had this problem for this a couple of times and I have just avoided it by running error-free trials.
The code is as follows:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/http_exception.dart';
class Auth with ChangeNotifier {
String _token;
//tokens only last about an hour
DateTime _expiryDate;
String _userId;
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = 'UrlIsCorrectInMyCode'; //changed on purpose
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if(responseData['error'] != null){
throw HttpException(responseData['error']['message']);
}
} catch (error) {
throw error;
}
}
Future<void> signUp(String email, String password) async {
return _authenticate(email, password, 'signUp');
//in order for the progress indicator to be shown
//it must be returned so that it takes the future of
//_authenticate and not just any future
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'signInWithPassword');
}
}
And the class that registers UI and uses Auth:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/auth.dart';
import '../models/http_exception.dart';
enum AuthMode { Signup, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
// final transformConfig = Matrix4.rotationZ(-8 * pi / 180);
// transformConfig.translate(-10.0);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromRGBO(215, 117, 255, 1).withOpacity(0.5),
Color.fromRGBO(255, 188, 117, 1).withOpacity(0.9),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: [0, 1],
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: EdgeInsets.only(bottom: 20.0),
padding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 94.0),
transform: Matrix4.rotationZ(-8 * pi / 180)
..translate(-10.0),
//transform allows to rotate or scale a box
//the '..' operator allows you to return the matrix4
//object that rotationZ provides instead of the void
//response that .translate provides
// ..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.deepOrange.shade900,
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'MyShop',
style: TextStyle(
color:
Theme.of(context).accentTextTheme.headline6.color,
fontSize: 50,
fontFamily: 'Anton',
fontWeight: FontWeight.normal,
),
),
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: AuthCard(),
),
],
),
),
),
],
),
);
}
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text("An error occured"),
content: Text(message),
actions: [
FlatButton(
child: Text("Okay"),
onPressed: () {
Navigator.of(ctx).pop();
},
),
],
),
);
}
Future<void> _submit() async {
if (!_formKey.currentState.validate()) {
// Invalid!
return;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
await Provider.of<Auth>(context, listen: false).login(
_authData['email'],
_authData['password'],
);
} else {
await Provider.of<Auth>(context, listen: false).signUp(
_authData['email'],
_authData['password'],
);
}
} on HttpException catch (error) {
//this means a special type of error is thrown
//this acts as a filter for the type of error
var errorMessage = 'Authentication failed.';
if (error.toString().contains("EMAIL_EXISTS")) {
errorMessage = 'This email address is already in use';
} else if (error.toString().contains('INVALID_EMAIL')) {
errorMessage = 'This is not a valid email address.';
} else if (error.toString().contains('WEAK_PASSWORD')) {
errorMessage = 'This password is too weak.';
} else if (error.toString().contains('EMAIL_NOT_FOUND')) {
errorMessage = 'Could not find a user with that email.';
} else if (error.toString().contains('INVALID_PASSWORD')) {
errorMessage = 'Invalid password.';
}
_showErrorDialog(errorMessage);
} catch (error) {
const errorMessage = 'Could not authenticate. Please try again.';
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.Signup ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Invalid email!';
} else {
return null;
}
},
onSaved: (value) {
_authData['email'] = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value.isEmpty || value.length < 5) {
return 'Password is too short!';
} else {
return null;
}
},
onSaved: (value) {
_authData['password'] = value;
},
),
if (_authMode == AuthMode.Signup)
TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
//this allows stars to mask the input
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
} else {
return null;
}
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
RaisedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 8.0),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).primaryTextTheme.button.color,
),
FlatButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} INSTEAD'),
onPressed: _switchAuthMode,
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
//reduces the amount of surface area that is tappable
textColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}