注册后,我希望用户进入WelcomeScreen((,登录后进入Sessions((。然而,以我的根页面目前的结构方式,这有点难以实现。
我该怎么做?请参阅下面的代码片段和解释。
在我的main.dart文件中,我的RootPage被设置为initialRoute。RootPage检查是否有有效的会话,从而重定向到PaymentScreen,而不是重定向到处理登录和注销视图的Sessions.art。
//root_page.dart
// ignore: must_be_immutable
class RootPage extends StatelessWidget {
static const String id = 'root_page';
Widget buildWaitingScreen() {
return Scaffold(
body: Container(
alignment: Alignment.center,
),
);
}
@override
// ignore: missing_return
Widget build(BuildContext context) {
final BaseAuth auth = AuthProvider.of(context).auth;
return StreamBuilder<String>(
stream: auth.onAuthStateChanged,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool isLoggedIn = snapshot.hasData;
return isLoggedIn ? WelcomeEmail() : Sessions();
// return isLoggedIn ? PaymentScreen() : Sessions();
}
return buildWaitingScreen();
},
);
}
}
我的AuthProvider。。。
class AuthProvider extends InheritedWidget {
AuthProvider({
Key key,
@required this.auth,
@required Widget child,
}) : assert(auth != null),
assert(child != null),
super(key: key, child: child);
final BaseAuth auth;
@override
bool updateShouldNotify(AuthProvider old) => auth != old.auth;
//this static class allows us to access AuthProvider anywhere in our code using AuthProvider.of(context).auth
static AuthProvider of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AuthProvider>();
}
}
我的授权艺术
abstract class BaseAuth {
Stream<User> get user;
Stream<String> get onAuthStateChanged;
Future<String> handleSignIn(String email, String password);
Future<String> handleSignUp(String email, String password);
Future<String> currentUser();
}
class Auth implements BaseAuth {
final _auth = FirebaseAuth.instance;
//create a new user object based on FirebaseUser
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
//auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
@override
Stream<String> get onAuthStateChanged {
return _auth.onAuthStateChanged.map((user) => user?.uid);
}
//sign in with email and password
Future<String> handleSignIn(String email, String password) async {
AuthResult result = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password)
.catchError((error) => print(error));
if (result != null) {
FirebaseUser user = result.user;
if (user != null) {
print('From handleSignIn, Log in: ${user.email}');
}
return user.uid;
}
}
//sign up with email and password
Future<String> handleSignUp(String email, String password) async {
AuthResult result = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password)
.catchError((error) => print(error));
FirebaseUser user = result.user;
if (user != null) {
print('From handleSignUp, New user email: ${user.email}');
}
return user.uid;
}
}
我的sessions.art文件
class Sessions extends StatefulWidget {
static const String id = 'sessions';
@override
_SessionsState createState() => _SessionsState();
}
enum SessionType { signIn, signUp, reset }
class _SessionsState extends State<Sessions> {
String email, password, _warning;
bool showSpinner = false;
final _formKey = GlobalKey<FormState>();
var args;
SessionType _sessionType = SessionType.signIn;
setArguments(args) async {
_sessionType = args[0];
}
//validate form fields input and save
bool validateAndSave() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
print('form is valid, Email: $email, Password: $password');
return true;
} else {
print('form is invalid');
return false;
}
}
//remove extra spacing before and after input text
String trimTextInput(String value) {
return value.toString().trim();
}
//validate form and sign in / sign up
void validateAndSubmit() async {
if (validateAndSave()) {
setState(() {
showSpinner = true;
});
try {
final BaseAuth auth = AuthProvider.of(context).auth;
if (_sessionType == SessionType.signIn) {
String user = await auth.handleSignIn(
trimTextInput(email), trimTextInput(password));
print('Signed in: $user');
if (user == null) {
setState(() {
showSpinner = false;
_warning = 'could not sign in with those credentials';
});
}
} else if (_sessionType == SessionType.reset) {
print('password reset email sent to $email');
await auth
.sendPasswordResetEmail(trimTextInput(email))
.catchError((onError) => print(onError));
_warning = 'A password reset link has been sent to $email';
setState(() {
showSpinner = false;
_sessionType = SessionType.signIn;
});
} else {
String user = await auth.handleSignUp(
trimTextInput(email), trimTextInput(password));
print('Signed up: $user');
if (user == null) {
setState(() {
showSpinner = false;
_warning = 'could not sign up with those credentials';
});
}
}
} catch (e) {
print('Warning message: ${e.toString()}');
}
}
}
//toggle to switch between sign up and sign in views
void toggleFormView(String state) {
_formKey.currentState.reset();
if (state == 'signUp') {
setState(() {
_sessionType = SessionType.signUp;
});
} else {
setState(() {
_sessionType = SessionType.signIn;
});
}
}
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
setState(() {
args = ModalRoute.of(context).settings.arguments;
});
// _sessionType = args.sessionType;
print('Session type: $_sessionType');
// setArguments(args);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: ModalProgressHUD(
inAsyncCall: showSpinner,
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showAlert(),
buildHeaderText(_warning, 3, kHeading1TextStyle),
SizedBox(height: 8.0),
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 80.0,
child: Image.asset('images/logo.png'),
),
),
),
SizedBox(height: 7.0),
Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: Form(
key: _formKey,
child: Column(
children: buildInputFields() + submitButtons(),
),
),
),
],
),
),
),
),
);
}
Widget showAlert() {
if (_warning != null) {
return Container(
alignment: Alignment.topCenter,
color: Colors.amberAccent,
width: double.infinity,
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(Icons.error_outline),
),
Expanded(
child: warningText(),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: IconButton(
icon: Icon(Icons.close),
onPressed: () {
setState(() {
_warning = null;
});
},
),
)
],
),
);
}
return SizedBox(
height: 0,
);
}
Widget warningText() {
return Text(
_warning,
textAlign: TextAlign.center,
style: kRegularTextStyle,
maxLines: 3,
);
}
Widget buildHeaderText(String headerText, int maxLines, TextStyle style) {
if (_sessionType == SessionType.signUp) {
headerText = "Create New Account";
} else if (_sessionType == SessionType.reset) {
headerText = "Reset Password";
} else {
headerText = "Sign In";
}
return Text(
headerText,
textAlign: TextAlign.center,
style: style,
maxLines: maxLines,
);
}
List<Widget> buildInputFields() {
if (_sessionType == SessionType.reset) {
return [
TextFormField(
key: Key('email'),
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.left,
onSaved: (value) => email = value,
validator: EmailFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'enter your email'),
),
];
} else {
return [
TextFormField(
key: Key('email'),
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.left,
onSaved: (value) => email = value,
validator: EmailFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'enter your email'),
),
SizedBox(height: 8.0),
TextFormField(
key: Key('password'),
obscureText: true,
textAlign: TextAlign.left,
validator: PasswordFieldValidator.validate,
onSaved: (value) => password = value,
decoration:
kTextFieldDecoration.copyWith(hintText: 'enter your password'),
),
SizedBox(height: 8.0),
];
}
}
List<Widget> submitButtons() {
bool _showForgotPassword = false;
if (_sessionType == SessionType.signIn) {
_showForgotPassword = true;
return [
Buttons(
key: Key('signIn'),
buttonLabel: 'Sign In',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton,
onPressedButton: validateAndSubmit,
),
showForgotPassword(_showForgotPassword),
PaddedClickableText(
myText: 'Don't have an account? Sign up now',
onTap: () => toggleFormView('signUp'),
),
];
} else if (_sessionType == SessionType.reset) {
return [
Buttons(
key: Key('submit'),
buttonLabel: 'Submit',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton,
onPressedButton: validateAndSubmit,
),
PaddedClickableText(
myText: 'Return back to sign in',
onTap: () => toggleFormView('signIn'),
),
];
} else {
return [
Buttons(
key: Key('signUp'),
buttonLabel: 'Sign Up',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton,
onPressedButton: validateAndSubmit,
),
PaddedClickableText(
myText: 'Already have an account? Sign in here',
onTap: () => toggleFormView('signIn'),
),
];
}
}
Widget showForgotPassword(bool visible) {
return Visibility(
visible: visible,
child: FlatButton(
onPressed: () {
setState(() {
_sessionType = SessionType.reset;
});
},
child: Text(
'Forgot password?',
textAlign: TextAlign.center,
style: TextStyle(
color: kThemeTextColour,
fontWeight: FontWeight.bold,
),
),
),
);
}
}
class EmailFieldValidator {
static String validate(String value) {
return value.isEmpty ? 'Email can't be empty' : null;
}
}
class PasswordFieldValidator {
static String validate(String value) {
return value.length < 6 || value.isEmpty
? 'Password can't be empty'
: null;
}
}
class SessionsArguments {
final SessionType sessionType;
SessionsArguments(this.sessionType);
}
通常,人们使用共享前缀来存储基本登录信息,这样,下次有人打开应用程序时,您就可以使用这些信息来路由到您想要的任何方式。
另一种方法是使用变量。如果他们注册了,那么将该变量设置为true,然后路由到另一个页面。
如果您需要每个代码段,请告诉我。
为此,首先需要安装shared_preferences
软件包。安装很简单:打开pubspec.yaml文件,在dependencies
部分下添加此行shared_preferences: ^0.5.12+4
(这是我写这个答案时的最新版本(,然后运行flutter pub get
。
一个基本的例子:
// Import shared_preferences library
import 'package:shared_preferences/shared_preferences.dart';
// Save the isLoggedIn data when user is logged in to system
saveLoggedIn() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('isLoggedIn', isLoggedIn);
}
// Get the isLoggedIn data to check if user is returned
getLoggedIn() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isUserLoggedIn = prefs.getBool('isLoggedIn');
return isUserLoggedIn;
}