auth 8.0.0-pre+2 auth: ^8.0.0-pre+2 copied to clipboard
Authorization Library Package to log into Google, Facebook, or by Username and Password.
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show SystemChannels, TextInputType;
import 'package:google_sign_in/google_sign_in.dart' show GoogleUserCircleAvatar;
import 'package:auth/auth.dart'
if (dart.library.html) 'package:auth/auth_web.dart';
void main() => runApp(
const MaterialApp(
home: SignInDemo(),
debugShowCheckedModeBanner: false,
),
);
class SignInDemo extends StatefulWidget {
const SignInDemo({Key? key}) : super(key: key);
@override
State createState() => _SignInDemoState();
}
class _SignInDemoState extends State<SignInDemo>
with SingleTickerProviderStateMixin {
late Auth auth;
bool loggedIn = false;
late TabController tabController;
String errorMessage = '';
@override
void initState() {
super.initState();
tabController = TabController(length: 2, vsync: this);
auth = Auth(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
listener: (user) {
loggedIn = user != null;
errorMessage = auth.message;
setState(() {});
});
auth.signInSilently(
listen: (account) {
loggedIn = account != null;
errorMessage = auth.message;
setState(() {});
},
listener: (user) {
// final test = user != null;
},
);
loggedIn = auth.isLoggedIn();
}
@override
void dispose() {
/// Important to dispose of the Auth's resources.
auth.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sign In Demo'),
bottom: TabBar(
tabs: const [
Tab(text: 'Sign In'),
Tab(text: 'Results'),
],
controller: tabController,
),
),
body: Center(
child: TabBarView(
controller: tabController,
children: <Widget>[
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: _buildBody(),
),
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: _authResults,
),
],
),
));
}
Widget _buildBody() {
if (loggedIn) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
ListTile(
leading: auth.signedInGoogle()
? GoogleUserCircleAvatar(
identity: auth.googleUser!,
)
: const Text(''),
title: Text(auth.displayName),
subtitle: Text(auth.email),
),
const Text('Signed in successfully.'),
signInErrorMsg,
ElevatedButton(
onPressed: () {
auth.signOut();
},
child: const Text('Sign Out of Firebase'),
),
ElevatedButton(
onPressed: () {
auth.disconnect();
},
child: const Text('Sign Out & Disconnect'),
),
ElevatedButton(
onPressed: () {
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
},
child: const Text('Just Quit'),
),
],
);
} else {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
const Text('You are not currently signed in.'),
signInErrorMsg,
ElevatedButton(
onPressed: () {
auth.signInWithFacebook().then((signIn) {
return signInFunc(signIn: signIn);
}).catchError((Object err) {
if (err is! Exception) {
err = err.toString();
}
errorMessage = auth.message;
});
},
child: const Text('Sign In With Facebook'),
),
ElevatedButton(
onPressed: () {
auth
.signInWithTwitter(
key: 'ab1cefgh23KlmnOpQ4STUVWx5',
secret:
'ab1cefgh23KlmnOpQ4STUVWx5y6ZabCDe7ghi8jKLMnOP9qRst')
.then((signIn) => signInFunc(signIn: signIn))
.catchError((Object err) {
if (err is! Exception) {
err = err.toString();
}
errorMessage = auth.message;
});
},
child: const Text('Sign In With Twitter'),
),
ElevatedButton(
onPressed: () {
auth
.signInWithGoogle()
.then((signIn) => signInFunc(signIn: signIn))
.catchError((Object err) {
if (err is! Exception) {
err = err.toString();
}
errorMessage = auth.message;
});
},
child: const Text('Sign In With Google'),
),
ElevatedButton(
onPressed: () {
auth
.signInAnonymously()
.then((signIn) => signInFunc(signIn: signIn))
.catchError((Object err) {
if (err is! Exception) {
err = err.toString();
}
errorMessage = auth.message;
});
},
child: const Text('Log in anonymously'),
),
ElevatedButton(
onPressed: () async {
final ep = await dialogBox(context: context);
if (ep == null || ep.isEmpty) {
return;
}
await auth
.signInWithEmailAndPassword(email: ep[0], password: ep[1])
.then((signIn) => signInFunc(signIn: signIn))
.catchError((Object err) {
if (err is! Exception) {
err = err.toString();
}
errorMessage = auth.message;
});
},
child: const Text('Sign in with Email & Password'),
),
],
);
}
}
// This function is called by every RaisedButton widget.
void signInFunc({required bool signIn}) {
if (signIn) {
errorMessage = '';
} else {
errorMessage = auth.message;
}
setState(() {});
}
Widget get _authResults => ListView(
padding: const EdgeInsets.all(30),
itemExtent: 80,
children: <Widget>[
Text('uid: ${auth.uid}'),
Text('name: ${auth.displayName}'),
Text('photo: ${auth.photoUrl}'),
Text('new login: ${auth.isNewUser}'),
Text('user name: ${auth.username}'),
Text('email: ${auth.email}'),
Text('email verified: ${auth.isEmailVerified}'),
Text('anonymous login: ${auth.isAnonymous}'),
Text('permissions: ${auth.permissions}'),
Text('id token: ${auth.idToken}'),
Text('access token: ${auth.accessToken}'),
Text('information provider: ${auth.providerId}'),
Text('expire time: ${auth.expirationTime}'),
Text('auth time: ${auth.authTime}'),
Text('issued at: ${auth.issuedAtTime}'),
Text('signin provider: ${auth.signInProvider}'),
],
);
Widget get signInErrorMsg => Container(
padding: const EdgeInsets.all(10),
child: Center(
child: RichText(
text: TextSpan(
text: errorMessage,
style: const TextStyle(color: Colors.red),
))));
}
// Creates an alertDialog for the user to enter their email
Future<List<String>?> dialogBox({
Key? key,
required BuildContext context,
bool barrierDismissible = false,
}) {
return showDialog<List<String>>(
context: context,
barrierDismissible: barrierDismissible, // user must tap button!
builder: (BuildContext context) {
return CustomAlertDialog(
key: key!,
title: 'Email & Password',
);
},
);
}
class CustomAlertDialog extends StatefulWidget {
const CustomAlertDialog({Key? key, required this.title}) : super(key: key);
final String title;
@override
_CustomAlertDialogState createState() => _CustomAlertDialogState();
}
class _CustomAlertDialogState extends State<CustomAlertDialog> {
final _resetKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _resetValidate = false;
bool _hidePassword = true;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
elevation: 20,
content: SingleChildScrollView(
child: Form(
key: _resetKey,
autovalidateMode: _resetValidate
? AutovalidateMode.always
: AutovalidateMode.disabled,
child: ListBody(
children: <Widget>[
const Text(
'Email Address & Password.',
style: TextStyle(fontSize: 14),
),
const Padding(
padding: EdgeInsets.all(10),
),
Column(
children: <Widget>[
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 8),
child: Icon(
Icons.email,
size: 20,
),
),
SizedBox(
width: 250,
child: TextFormField(
validator: validateEmail,
controller: _emailController,
keyboardType: TextInputType.emailAddress,
autofocus: true,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Email',
contentPadding: EdgeInsets.only(left: 70, top: 15),
hintStyle:
TextStyle(color: Colors.black, fontSize: 14)),
style: const TextStyle(color: Colors.black),
),
)
]),
SizedBox(
width: 200,
child: TextFormField(
validator: (String? value) {
if (value == null || value.isEmpty) {
return 'Password required.';
}
return null;
},
keyboardType: TextInputType.text,
controller: _passwordController,
obscureText:
_hidePassword, //This will obscure text dynamically
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
// Here is key idea
suffixIcon: IconButton(
icon: Icon(
// Based on passwordVisible state choose the icon
_hidePassword
? Icons.visibility_off
: Icons.visibility,
color: Theme.of(context).primaryColorDark,
),
onPressed: () {
// Update the state i.e. google the state of passwordVisible variable
setState(() {
_hidePassword = !_hidePassword;
});
},
),
),
),
),
],
),
],
),
),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'CANCEL',
style: TextStyle(color: Colors.black),
),
),
TextButton(
onPressed: () {
_onPressed();
},
child: const Text(
'SEND EMAIL',
style: TextStyle(color: Colors.black),
),
),
],
);
}
void _onPressed() {
var valid = true;
if (_resetKey.currentState == null || !_resetKey.currentState!.validate()) {
valid = false;
}
if (valid) {
Navigator.of(context)
.pop([_emailController.text, _passwordController.text]);
} else {
_resetValidate = true;
setState(() {});
}
}
}
String? validateEmail(String? value) {
if (value == null) {
return null;
}
const pattern =
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
final regExp = RegExp(pattern);
if (value.isEmpty) {
return 'Email is required';
} else if (!regExp.hasMatch(value)) {
return 'Invalid Email';
}
}