I am busy coding a hairdresser application for a university project. I have set up User Authentication using firebase, allowing users to sign in/up using email and password. However my application needs to have two roles, hairdressers and customers. The user role needs to determine what widgets a user can see.
Below is my Auth.dart code, followed by my auth_screen.dart code.
import 'dart:convert';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import '../models/http_exception.dart';
class Auth with ChangeNotifier {
String? _token;
DateTime? _expiryDate;
String? _userId;
bool get isAuth {
return token != null;
}
String? get token {
if (_expiryDate != null &&
_expiryDate!.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url =
Uri.parse('https://www.googleapis.com/identitytoolkit/v3/relyingparty/$urlSegment?key=AIzaSyAvod1Xfk4P9zjSRKb4lZzGA9sVIiYOAf4');
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']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(
Duration(
seconds: int.parse(
responseData['expiresIn'],
),
),
);
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> signup(String? email, String? password, var options) async {
return _authenticate(email!, password!, 'signupNewUser');
}
Future<void> login(String? email, String? password) async {
return _authenticate(email!, password!, 'verifyPassword');
}
void logout(){
_token = null;
_userId = null;
_expiryDate = null;
notifyListeners();
}
}
//Auth_screen.dart
import 'dart:math';
import 'package:barber/Screens/widgets.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../Provider/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.fromARGB(255, 149, 176, 179).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: const EdgeInsets.only(bottom: 20.0),
padding:
const EdgeInsets.symmetric(vertical: 6.0, horizontal: 80.0),
// transform: Matrix4.rotationZ(-8 * pi / 180)
// ..translate(-10.0),
// ..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Color.fromARGB(255, 103, 161, 179),
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'MyFriseur',
style: TextStyle(
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();
var options = [
'Driver',
'Customer'
];
var _currentItemSelected = "Student";
var rool = "Student";
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 Occurred!'),
content: Text(message),
actions: <Widget>[
TextButton(
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) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'],
_authData['password'],
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'],
_authData['password'],
_authData['options'],
);
}
} on HttpException catch (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 you. Please try again later.';
_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!';
}
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!';
}
return null;
},
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
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(Color.fromARGB(255, 103, 161, 179)),
),
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
),
TextButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} INSTEAD'),
style: TextButton.styleFrom(
primary: Colors.black),
onPressed: _switchAuthMode,
// padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
// materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
// textColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}
Any help creating user roles would help me greatly, thank you!