Files
fcs/lib/pages/login_page.dart
Thinzar Win f4823d82f8 insert pages
2020-05-29 16:14:17 +06:30

759 lines
29 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import 'package:fcs/model/language_model.dart';
import 'package:fcs/model/main_model.dart';
import 'package:fcs/model/user_model.dart';
import 'package:fcs/pages/reset_password.dart';
import 'package:fcs/widget/bubble_indication_painter.dart';
import 'package:fcs/widget/localization/app_translations.dart';
import 'package:fcs/widget/progress.dart';
import '../theme/theme.dart' as Theme;
import 'forget_password.dart';
import 'sms_page.dart';
import 'util.dart';
class LoginPage extends StatefulWidget {
LoginPage({Key key}) : super(key: key);
@override
_LoginPageState createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage>
with SingleTickerProviderStateMixin {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final FocusNode myFocusNodeEmailLogin = FocusNode();
final FocusNode myFocusNodePasswordLogin = FocusNode();
final FocusNode myFocusNodePassword = FocusNode();
final FocusNode myFocusNodeEmail = FocusNode();
final FocusNode myFocusNodeName = FocusNode();
TextEditingController loginPhoneController = new TextEditingController();
TextEditingController loginPasswordController = new TextEditingController();
bool _obscureTextLogin = true;
bool _obscureTextSignup = true;
bool _obscureTextSignupConfirm = true;
TextEditingController signupPhoneNumberController =
new TextEditingController();
TextEditingController signupNameController = new TextEditingController();
TextEditingController signupPasswordController = new TextEditingController();
TextEditingController signupConfirmPasswordController =
new TextEditingController();
PageController _pageController;
Color left = Colors.black;
Color right = Colors.white;
final loginFormKey = GlobalKey<FormState>();
final signupFormKey = GlobalKey<FormState>();
bool _isLoading = false;
@override
Widget build(BuildContext context) {
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(
color: Colors.grey,
),
elevation: 0,
centerTitle: true,
title: new Image(
height: 30,
fit: BoxFit.scaleDown,
image: new AssetImage('assets/img/logo.png')),
),
body: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height >= 775.0
? MediaQuery.of(context).size.height
: 580.0,
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 50.0),
child: _buildMenuBar(context),
),
Expanded(
flex: 2,
child: PageView(
controller: _pageController,
onPageChanged: (i) {
if (i == 0) {
setState(() {
right = Colors.white;
left = Colors.black;
});
} else if (i == 1) {
setState(() {
right = Colors.black;
left = Colors.white;
});
}
},
children: <Widget>[
new ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: _buildLogin(context),
),
new ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: _buildSignUp(context),
),
],
),
),
],
),
),
),
),
);
}
@override
void dispose() {
myFocusNodePassword.dispose();
myFocusNodeEmail.dispose();
myFocusNodeName.dispose();
_pageController?.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
// SystemChrome.setPreferredOrientations([
// DeviceOrientation.portraitUp,
// DeviceOrientation.portraitDown,
// ]);
_pageController = PageController();
loginPhoneController.text = "09";
signupPhoneNumberController.text = "09";
}
Widget _buildMenuBar(BuildContext context) {
return Container(
width: 300.0,
height: 40.0,
decoration: BoxDecoration(
color: Color(0x552B2B2B),
borderRadius: BorderRadius.all(Radius.circular(25.0)),
),
child: CustomPaint(
painter: TabIndicationPainter(pageController: _pageController),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: _onSignInButtonPress,
child: Text(
AppTranslations.of(context).text("login.title"),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(
color: left,
fontSize: 14.0,
fontFamily: "WorkSansSemiBold")
: TextStyle(
color: left,
fontSize: 15.0,
fontFamily: "MyanmarUnicode"),
),
),
),
//Container(height: 33.0, width: 1.0, color: Colors.white),
Expanded(
child: FlatButton(
onPressed: _onSignUpButtonPress,
child: Text(
AppTranslations.of(context).text("sing.title"),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(
color: right,
fontSize: 14.0,
fontFamily: "WorkSansSemiBold")
: TextStyle(
color: right,
fontSize: 15.0,
fontFamily: "MyanmarUnicode"),
),
),
),
],
),
),
);
}
Widget _buildLogin(BuildContext context) {
return Container(
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
Form(
key: loginFormKey,
child: Card(
elevation: 2.0,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Container(
width: 300.0,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
focusNode: myFocusNodeEmailLogin,
controller: loginPhoneController,
keyboardType: TextInputType.phone,
style: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0,
color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(
FontAwesomeIcons.phone,
color: Colors.black,
size: 22.0,
),
labelText: AppTranslations.of(context)
.text("login.phone"),
labelStyle:
Provider.of<LanguageModel>(context).isEng
? TextStyle(
fontFamily: "WorkSansSemiBold",
color: Colors.grey)
: TextStyle(
fontFamily: "MyanmarUnicode",
color: Colors.grey),
),
validator: _validatePhone,
),
),
Container(
width: 250.0,
height: 1.0,
color: Colors.grey[400],
),
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
focusNode: myFocusNodePasswordLogin,
controller: loginPasswordController,
obscureText: _obscureTextLogin,
style: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0,
color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(
FontAwesomeIcons.lock,
size: 22.0,
color: Colors.black,
),
labelText: AppTranslations.of(context)
.text("login.password"),
labelStyle:
Provider.of<LanguageModel>(context).isEng
? TextStyle(
fontFamily: "WorkSansSemiBold",
color: Colors.grey)
: TextStyle(
fontFamily: "MyanmarUnicode",
color: Colors.grey),
suffixIcon: GestureDetector(
onTap: _toggleLogin,
child: Icon(
_obscureTextLogin
? FontAwesomeIcons.eye
: FontAwesomeIcons.eyeSlash,
size: 15.0,
color: Colors.black,
),
),
),
validator: _validatePassword,
),
),
],
),
),
),
),
Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Theme.primaryColor,
),
child: MaterialButton(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 42.0),
child: Text(
AppTranslations.of(context).text("login.btn"),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: "WorkSansBold")
: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold,
fontFamily: "MyanmarUnicode"),
),
),
onPressed: () => _login(context)),
),
],
),
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: new LinearGradient(
colors: [
Colors.white10,
Colors.white,
],
begin: const FractionalOffset(0.0, 0.0),
end: const FractionalOffset(1.0, 1.0),
stops: [0.0, 1.0],
tileMode: TileMode.clamp),
),
width: 100.0,
height: 1.0,
),
Container(
decoration: BoxDecoration(
gradient: new LinearGradient(
colors: [
Colors.white,
Colors.white10,
],
begin: const FractionalOffset(0.0, 0.0),
end: const FractionalOffset(1.0, 1.0),
stops: [0.0, 1.0],
tileMode: TileMode.clamp),
),
width: 100.0,
height: 1.0,
),
],
),
),
Padding(
padding: EdgeInsets.only(top: 10.0),
child: FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ForgetPassword(
phoneNumber: loginPhoneController.text,
)));
},
child: Text(
AppTranslations.of(context).text("login.forgot_password"),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 16.0,
fontFamily: "WorkSansMedium")
: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 16.0,
fontFamily: "MyanmarUnicode"),
)),
),
],
),
);
}
Widget _buildSignUp(BuildContext context) {
return Container(
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
Form(
key: signupFormKey,
child: Card(
elevation: 2.0,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Container(
width: 300.0,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
focusNode: myFocusNodeName,
controller: signupNameController,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
style: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0,
color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(
FontAwesomeIcons.user,
color: Colors.black,
),
labelText: AppTranslations.of(context)
.text("login.name"),
labelStyle:
Provider.of<LanguageModel>(context).isEng
? TextStyle(
fontFamily: "WorkSansSemiBold",
color: Colors.grey)
: TextStyle(
fontFamily: "MyanmarUnicode",
color: Colors.grey),
hintStyle: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0),
),
validator: (value) {
if (value.isEmpty) {
return AppTranslations.of(context)
.text("login.name_empty");
}
return null;
}),
),
Container(
width: 250.0,
height: 1.0,
color: Colors.grey[400],
),
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
focusNode: myFocusNodeEmail,
controller: signupPhoneNumberController,
keyboardType: TextInputType.phone,
style: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0,
color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(
FontAwesomeIcons.phone,
color: Colors.black,
),
labelText: AppTranslations.of(context)
.text("login.phone"),
labelStyle:
Provider.of<LanguageModel>(context).isEng
? TextStyle(
fontFamily: "WorkSansSemiBold",
color: Colors.grey)
: TextStyle(
fontFamily: "MyanmarUnicode",
color: Colors.grey),
),
validator: _validatePhone),
),
Container(
width: 250.0,
height: 1.0,
color: Colors.grey[400],
),
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
focusNode: myFocusNodePassword,
controller: signupPasswordController,
obscureText: _obscureTextSignup,
style: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0,
color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(
FontAwesomeIcons.lock,
color: Colors.black,
),
labelText: AppTranslations.of(context)
.text("login.password"),
labelStyle:
Provider.of<LanguageModel>(context).isEng
? TextStyle(
fontFamily: "WorkSansSemiBold",
color: Colors.grey)
: TextStyle(
fontFamily: "MyanmarUnicode",
color: Colors.grey),
suffixIcon: GestureDetector(
onTap: _toggleSignup,
child: Icon(
_obscureTextSignup
? FontAwesomeIcons.eye
: FontAwesomeIcons.eyeSlash,
size: 15.0,
color: Colors.black,
),
),
),
validator: _validatePassword,
),
),
Container(
width: 250.0,
height: 1.0,
color: Colors.grey[400],
),
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
controller: signupConfirmPasswordController,
obscureText: _obscureTextSignupConfirm,
style: TextStyle(
fontFamily: "WorkSansSemiBold",
fontSize: 16.0,
color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
icon: Icon(
FontAwesomeIcons.lock,
color: Colors.black,
),
labelText: AppTranslations.of(context)
.text("login.confirm_password"),
labelStyle:
Provider.of<LanguageModel>(context).isEng
? TextStyle(
fontFamily: "WorkSansSemiBold",
color: Colors.grey)
: TextStyle(
fontFamily: "MyanmarUnicode",
color: Colors.grey),
suffixIcon: GestureDetector(
onTap: _toggleSignupConfirm,
child: Icon(
_obscureTextSignupConfirm
? FontAwesomeIcons.eye
: FontAwesomeIcons.eyeSlash,
size: 15.0,
color: Colors.black,
),
),
),
validator: _validatePassword,
),
),
],
),
),
),
),
Container(
// margin: EdgeInsets.only(top: 320.0),
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Theme.primaryColor,
),
child: MaterialButton(
highlightColor: Colors.transparent,
splashColor: Theme.LoginColors.loginGradientEnd,
//shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 42.0),
child: Text(
AppTranslations.of(context).text("sing.up"),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(
color: Colors.white,
fontSize: 18.0,
fontFamily: "WorkSansBold")
: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontFamily: "MyanmarUnicode"),
),
),
onPressed: () => _signup(context)),
),
],
),
],
),
);
}
void _onSignInButtonPress() {
_pageController.animateToPage(0,
duration: Duration(milliseconds: 500), curve: Curves.decelerate);
}
void _onSignUpButtonPress() {
_pageController?.animateToPage(1,
duration: Duration(milliseconds: 500), curve: Curves.decelerate);
}
void _toggleLogin() {
setState(() {
_obscureTextLogin = !_obscureTextLogin;
});
}
void _toggleSignup() {
setState(() {
_obscureTextSignup = !_obscureTextSignup;
});
}
void _toggleSignupConfirm() {
setState(() {
_obscureTextSignupConfirm = !_obscureTextSignupConfirm;
});
}
void _signup(BuildContext context) async {
if (!signupFormKey.currentState.validate()) {
return;
}
setState(() {
_isLoading = true;
});
MainModel authModel = Provider.of<MainModel>(context);
var name = signupNameController.text;
var password = signupPasswordController.text;
var confirmPassword = signupConfirmPasswordController.text;
var phoneNumber = signupPhoneNumberController.text;
try {
await authModel.signup(name, password, confirmPassword, phoneNumber);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
SmsCodePage(id: phoneNumber, password: password),
),
);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
Future.delayed(Duration(seconds: 1), () {
if (mounted) {
setState(() {
_isLoading = false;
});
}
});
}
}
void _login(BuildContext context) async {
if (!loginFormKey.currentState.validate()) {
return;
}
setState(() {
_isLoading = true;
});
MainModel mainModel = Provider.of<MainModel>(context);
var phoneNumber = loginPhoneController.text;
var password = loginPasswordController.text;
try {
await mainModel.login(phoneNumber, password);
Navigator.pushNamedAndRemoveUntil(context, "/", (r) => false);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
}
Future.delayed(Duration(seconds: 1), () {
if (mounted) {
setState(() {
_isLoading = false;
});
}
});
}
String _validatePassword(value) {
if (value.isEmpty) {
return AppTranslations.of(context).text("login.password_empty");
}
if (value.length < 6) {
return AppTranslations.of(context).text("login.password_size");
}
return null;
}
String _validatePhone(value) {
if (value.isEmpty) {
return AppTranslations.of(context).text("login.phone_empty");
}
if (!value.startsWith("09") && !value.startsWith("959")) {
return 'Only "09 or 959".';
}
return null;
}
Future<void> _forgetPassword() async {
var phoneNumber = loginPhoneController.text;
if (phoneNumber.isEmpty) {
showMsgDialog(context, "Error", "Please input phone number");
return;
}
setState(() {
_isLoading = true;
});
try {
UserModel userModel = Provider.of<UserModel>(context);
await userModel.forgetPassword(phoneNumber);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResetPasswordPage(phoneNumber)));
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}