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
Related
When making a put request and I edit all the field the object is updated. But if I only update one field on the edit screen than the object is not update. I think this is because the unchanged controllers do not keep the value that is already given to them in the Set state method.
Can anyone give me some hints how to solve this ?
import 'package:fin_app/apiservice/variables.dart';
import 'package:fin_app/screens/reminder/reminder_screen.dart';
import 'package:fin_app/screens/login_screen/login_screen.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../models/user.dart';
import '../monthly_expense/expense_app_theme.dart';
const String myhomepageRoute = '/';
const String myprofileRoute = 'profile';
class ReminderEdit extends StatefulWidget {
final String id;
final String title;
final String date;
final int amount;
const ReminderEdit({Key? key, required this.id, required this.title,required this.date,required this.amount}) : super(key: key);
#override
_ReminderEditState createState() => _ReminderEditState();
}
class _ReminderEditState extends State<ReminderEdit> {
final GlobalKey<FormState> _formKey = GlobalKey();
String id="";
final TextEditingController _titleInput = TextEditingController();
final TextEditingController _dateInput = TextEditingController();
final TextEditingController _amountInput = TextEditingController();
Future<Reminder>? _futureReminder;
Future<void> edit(String id,String title,String date,int amount) async {
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final editReminder = jsonEncode({
'title': title,
'date': date,
'amount': amount
});
if (_titleInput.text.isNotEmpty &&
_dateInput.text.isNotEmpty ) {
var response = await http.put(
Uri.parse("$baseUrl/reminder/me/$id/details"),
body: editReminder,
headers: requestHeaders);
if (response.statusCode == 200) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile edited succesfully.")));
} else {
print(response.statusCode);
print(id);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Could not edit the reminder.")));
}
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Please fill out the field.")));
}
}
#override
void initState() {
_dateInput.text = ""; //set the initial value of text field
super.initState();
setState(() {
id = widget.id;
_titleInput.text = widget.title;
_dateInput.text = widget.date;
_amountInput.text=widget.amount.toString();
});
}
void navigate() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AlarmPage()),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ExpenseAppTheme.background,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: ListView(
children: <Widget>[
const Align(
alignment: Alignment.topLeft,
child: Text("Edit reminder",
style: TextStyle(
fontSize: 24,
)),
),
const SizedBox(
height: 20,
),
Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextFormField(
controller: _titleInput,
decoration: const InputDecoration(
labelText: 'Title',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
borderSide:
BorderSide(color: Colors.grey, width: 0.0),
),
border: OutlineInputBorder()),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null ||
value.isEmpty ||
value.contains(RegExp(r'^[a-zA-Z\-]'))) {
return 'Use only text!';
}
},
),
const SizedBox(
height: 20,
),
TextFormField(
controller:_dateInput, //editing controller of this TextField
decoration: InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
labelText: "Enter Date" //label text of field
),
readOnly:
true, //set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(
2000), //DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2101));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
//you can implement different kind of Date Format here according to your requirement
setState(() {
_dateInput.text =
formattedDate; //set output date to TextField value.
});
} else {
print("Date is not selected");
}
},
),
const SizedBox(
height: 35,
),
TextFormField(
controller: _amountInput,
decoration: const InputDecoration(
labelText: 'Amount',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
borderSide:
BorderSide(color: Colors.grey, width: 0.0),
),
border: OutlineInputBorder()),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Amount must not be empty';
} else if (value.contains(RegExp(r'^[0-9]*$'))) {
return 'Amount must only contain numbers';
}
},
), const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(60)),
onPressed: () {
edit(widget.id,_titleInput.text,_dateInput.text,int.parse(_amountInput.text));
navigate();
},
child: const Text("Submit"),
),
],
),
),
],
),
),
);
}
FutureBuilder<Reminder> buildFutureBuilder() {
return FutureBuilder<Reminder>(
future: _futureReminder,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('Expense added');
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}
Every thing is working fine except that the page is not navigating while I press login button. The user is logged in and The screen is changing once I reload it. But the screen has to change when I click the login button. I used the setState fuction But still not working.Please help me solve this. Thanks in advance.
This is my root page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
class Root extends StatefulWidget {
const Root({Key? key}) : super(key: key);
#override
State<Root> createState() => _RootState();
}
enum AuthState { signedIn, signedOut }
class _RootState extends State<Root> {
AuthState _authState = AuthState.signedOut;
AuthService auth = AuthService();
String authuser = "ghnfgjy";
void signOut() async {
await auth.signOut();
setState(() {
_authState = AuthState.signedOut;
});
}
void signIn() async {
setState(() {
_authState = AuthState.signedIn;
});
}
#override
void initState() {
super.initState();
auth.currentUser().then((user) {
print("check check $user ");
setState(() {
_authState = user == null ? AuthState.signedOut : AuthState.signedIn;
});
});
}
#override
Widget build(BuildContext context) {
if (_authState == AuthState.signedOut) {
return Login();
} else {
return Scaffold(
body: Center(
child: Column(
children: [
SizedBox(
height: 69,
),
Text("Helllloooooooo $authuser"),
SizedBox(
height: 45,
),
FlatButton(
onPressed: () {
signOut();
},
child: Text("Sign out"))
],
),
));
}
}
}
This is my login.dart page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
import 'package:login/share/constant.dart';
class Login extends StatefulWidget {
const Login({Key? key}) : super(key: key);
#override
_LoginState createState() => _LoginState();
}
enum FormType {
login,
register,
}
class _LoginState extends State<Login> {
dynamic _email;
dynamic _password;
final formkey = GlobalKey<FormState>();
FormType _formType = FormType.login;
dynamic result;
AuthService auth = AuthService();
bool validateandsave() {
final form = formkey.currentState;
if (form!.validate()) {
form.save();
print('form is valid');
print('$_email $_password');
return true;
} else {
print('form is not valid');
return false;
}
}
Future validateandsumit() async {
if (validateandsave()) {
if (_formType == FormType.register) {
auth.register(_email, _password);
setState(() {
_formType = FormType.login;
});
} else {
auth.signIn(_email, _password);
}
}
}
void moveToRegister() {
formkey.currentState!.reset();
setState(() {
_formType = FormType.register;
});
}
void moveToLogin() {
formkey.currentState!.reset();
setState(() {
_formType = FormType.login;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Colors.blueAccent,
Colors.purple,
],
),
),
padding: EdgeInsets.all(16),
child: Form(
key: formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: openText() + inputFields() + buttons(),
),
),
),
);
}
List<Widget> openText() {
if (_formType == FormType.register) {
return [
Text(
'Please Register to continue',
style: TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
SizedBox(
height: 40,
),
];
} else {
return [
Text('Please Login to continue',
style: TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
SizedBox(
height: 40,
),
];
}
}
List<Widget> inputFields() {
return [
TextFormField(
decoration: inputDecoration.copyWith(
labelText: 'Email Address',
),
style: TextStyle(color: Colors.black),
validator: (val) => val!.isEmpty ? 'Enter the email address' : null,
onSaved: (val) => _email = val),
SizedBox(
height: 20,
),
TextFormField(
obscureText: true,
decoration: inputDecoration.copyWith(
labelText: 'Password',
),
style: TextStyle(color: Colors.black),
validator: (val) => val!.isEmpty ? 'Enter the password' : null,
onSaved: (val) => _password = val),
SizedBox(
height: 60,
),
];
}
List<Widget> buttons() {
if (_formType == FormType.register) {
return [
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: validateandsumit,
child: Text(
'Register',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
SizedBox(
height: 20,
),
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: moveToLogin,
child: Text(
'Have an account? Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
];
} else {
return [
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: validateandsumit,
child: Text(
'Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
SizedBox(
height: 20,
),
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: moveToRegister,
child: Text(
'Register',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
];
}
}
}
This is my authservice file
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class AuthService {
FirebaseAuth _auth = FirebaseAuth.instance;
//Stream <User>? get authStateChanges => _auth.authStateChanges();
Stream<User?> get authStateChanges => _auth.authStateChanges();
CollectionReference users = FirebaseFirestore.instance.collection('users');
late User user;
//register in with email and password
Future register(email, password) async {
try {
UserCredential userCredential = await _auth
.createUserWithEmailAndPassword(email: email, password: password);
user = userCredential.user!;
print('Registered ${user.uid}');
var userdata = {
'email': email,
'password': password,
'role': 'user',
};
users.doc(user.uid).get().then((doc) {
if (doc.exists) {
doc.reference.update(userdata);
} else {
users.doc(user.uid).set(userdata);
}
});
} catch (e) {
print(e);
}
}
//sign in with email and password
Future signIn(email, password) async {
try {
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email, password: password);
user = userCredential.user!;
print('logged in ${user.uid}');
var userdata = {
'email': email,
'password': password,
'role': 'user',
};
users.doc(user.uid).get().then((doc) {
if (doc.exists) {
doc.reference.update(userdata);
} else {
users.doc(user.uid).set(userdata);
}
});
} catch (e) {
print(e);
}
}
Future currentUser() async {
try {
User user = await _auth.currentUser!;
return user.uid;
} catch (e) {
print(e);
}
}
//sign out
Future signOut() async {
try {
await _auth.signOut();
} catch (e) {
print(e);
}
}
}
I think the problem is that the build function in _RootState does not rebuild when you login.
One possible solution is to use StreamBuilder to rebuild whenever auth changes (login/logout).
Add this function to your AuthService class:
class AuthService {
final _auth = FirebaseAuth.instance;
...
Stream<User?> authStream() => _auth.authStateChanges(); // add this line
}
Then write your build function (in _RootState) as below:
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: auth.authStream(), // auth here is AuthService.
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
// StreamBuilder will automatically rebuild anytime you log in or log
// logout. No need for your initState or signout & signin functions.
if (snapshot.hasError) return const Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.data == null) return Login();
// snapshot.data is User.
// print(snapshot.data?.email); print(snapshot.data?.displayName);
return Scaffold(
body: Center(
child: Column(
children: [
const SizedBox(height: 69),
Text('Hello ${snapshot.data?.email}'),
const SizedBox(height: 45),
FlatButton(
onPressed: () async {
// no need to call sign out here.
await auth.signOut();
},
child: const Text('Sign out'),
)
],
),
),
);
},
);
// you can delete your initState, signin and signout functions in _RootState
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;
}
}
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),
);
}
}
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,
),
],
),
),
),
),
);
}
}