New file |
| | |
| | | import 'dart:async'; |
| | | import 'dart:convert'; |
| | | import 'dart:ui'; |
| | | |
| | | import 'package:flutter/cupertino.dart'; |
| | | import 'package:flutter/material.dart'; |
| | | import 'package:flutter/services.dart'; |
| | | import 'package:fluttertoast/fluttertoast.dart'; |
| | | import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; |
| | | import 'package:hanju/ui/mine/email_pwd_find.dart'; |
| | | import 'package:hanju/ui/mine/email_register.dart'; |
| | | import 'package:html/dom.dart' as dom; |
| | | import '../../api/http.dart'; |
| | | import '../../model/user/user_info.dart'; |
| | | import '../../ui/common/browser.dart'; |
| | | import '../../ui/widget/button.dart'; |
| | | import '../../utils/event_bus_util.dart'; |
| | | import '../../utils/pageutils.dart'; |
| | | import '../../utils/push_util.dart'; |
| | | import '../../utils/string_util.dart'; |
| | | import '../../utils/ui_constant.dart'; |
| | | import '../../utils/ui_utils.dart'; |
| | | import '../../utils/user_util.dart'; |
| | | import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; |
| | | |
| | | void main() { |
| | | runApp(MyApp()); |
| | | } |
| | | |
| | | class MyApp extends StatelessWidget { |
| | | // This widget is the root of your application. |
| | | @override |
| | | Widget build(BuildContext context) { |
| | | return MaterialApp( |
| | | title: '登录', |
| | | theme: ThemeData(primaryColor: Color(0xFFF5F5F5)), |
| | | home: EmailLoginPage(title: ''), |
| | | ); |
| | | } |
| | | } |
| | | |
| | | class EmailLoginPage extends StatefulWidget { |
| | | //阿里云一键登录 |
| | | static const messageChannel = |
| | | BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec()); |
| | | |
| | | EmailLoginPage({Key? key, required this.title}) : super(key: key); |
| | | |
| | | // This widget is the home page of your application. It is stateful, meaning |
| | | // that it has a State object (defined below) that contains fields that affect |
| | | // how it looks. |
| | | |
| | | // This class is the configuration for the state. It holds the values (in this |
| | | // case the title) provided by the parent (in this case the App widget) and |
| | | // used by the build method of the State. Fields in a Widget subclass are |
| | | // always marked "final". |
| | | |
| | | final String title; |
| | | |
| | | @override |
| | | _EmailLoginPageState createState() => _EmailLoginPageState(); |
| | | } |
| | | |
| | | class _EmailLoginPageState extends State<EmailLoginPage> |
| | | with SingleTickerProviderStateMixin { |
| | | bool oneKeyLogin = false; |
| | | bool checked = false; |
| | | TextEditingController? emailController = TextEditingController(); |
| | | TextEditingController? codeController = TextEditingController(); |
| | | String phone = ""; |
| | | String code = ""; |
| | | Timer? timer; |
| | | |
| | | //重新发送验证码倒计时 |
| | | int? reSendSMSTimeLeft; |
| | | |
| | | @override |
| | | void initState() { |
| | | super.initState(); |
| | | reSendSMSTimeLeft = -1; |
| | | //初始化微信登录监听 |
| | | fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { |
| | | if (res is fluwx.WeChatAuthResponse) { |
| | | int errCode = res.errCode; |
| | | if (errCode == 0) { |
| | | String? code = res.code; |
| | | //TODO 把微信登录返回的code传给后台,剩下的事就交给后台处理 |
| | | } else if (errCode == -4) { |
| | | //showToast("用户拒绝授权"); |
| | | } else if (errCode == -2) { |
| | | // showToast("用户取消授权"); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | bool _aliyunLogin = false; |
| | | |
| | | void aliyunOneKeyLogin() async { |
| | | if (_aliyunLogin) { |
| | | return; |
| | | } |
| | | _aliyunLogin = true; |
| | | Future.delayed(const Duration(milliseconds: 1000), () { |
| | | _aliyunLogin = false; |
| | | }); |
| | | |
| | | showLoading(context); |
| | | |
| | | Map value = |
| | | await EmailLoginPage.messageChannel.send({"method": "checkEnv"}) as Map; |
| | | dismissDialog(context); |
| | | if (value["code"] == 0) { |
| | | value = await EmailLoginPage.messageChannel.send({"method": "startLogin"}) |
| | | as Map; |
| | | print("返回内容:${jsonEncode(value)}"); |
| | | if (value["code"] == 0) { |
| | | Map<String, dynamic>? resultValue = |
| | | await UserApiUtil.login(context, "", "", value["token"]); |
| | | |
| | | EmailLoginPage.messageChannel.send({"method": "closeLogin"}); |
| | | |
| | | if (resultValue == null) return; |
| | | |
| | | if (resultValue["code"] == 0) { |
| | | UserInfo user = UserInfo.fromJson(resultValue["data"]); |
| | | _loginSuccess(user); |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | } else if (value["code"] == 700000) { |
| | | //Fluttertoast.showToast(msg: "取消登录了"); |
| | | } |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | setState(() { |
| | | oneKeyLogin = false; |
| | | }); |
| | | } |
| | | } |
| | | |
| | | void qqLogin() async { |
| | | Map value = await UserUtil.loginQQ(); |
| | | } |
| | | |
| | | void _loginSuccess(UserInfo user) { |
| | | UserUtil.setUserInfo(user).then((value) { |
| | | print("登录成功"); |
| | | eventBus.fire(LoginEventBus(true)); |
| | | PushUtil.setAlias(user.id!.toString()).then((value) { |
| | | Navigator.pop(context); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | @override |
| | | void dispose() { |
| | | if (timer != null) { |
| | | timer!.cancel(); |
| | | } |
| | | super.dispose(); |
| | | } |
| | | |
| | | BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) { |
| | | return BoxDecoration( |
| | | borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), |
| | | color: bgColor, |
| | | boxShadow: [ |
| | | BoxShadow( |
| | | color: shadowColor, |
| | | blurRadius: 2.0, |
| | | offset: Offset(0.0, 5.0), //阴影y轴偏移量 |
| | | spreadRadius: 1 //阴影扩散程度 |
| | | ) |
| | | ]); |
| | | } |
| | | |
| | | @override |
| | | Widget build(BuildContext context) { |
| | | return Scaffold( |
| | | resizeToAvoidBottomInset: false, |
| | | backgroundColor: Colors.white, |
| | | body: Stack( |
| | | children: [ |
| | | Column(children: [ |
| | | //登录内容区域 |
| | | Expanded( |
| | | child: SingleChildScrollView( |
| | | child: Padding( |
| | | padding: EdgeInsets.fromLTRB(40, 120, 40, 14), |
| | | child: Column( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/ic_login_logo.png", |
| | | width: 131, |
| | | ), |
| | | Container( |
| | | height: 70, |
| | | ), |
| | | Container( |
| | | constraints: BoxConstraints(minHeight: 180), |
| | | child: getLoginContent()), |
| | | Row( |
| | | children: [ |
| | | InkWell( |
| | | child: const Text( |
| | | "注册", |
| | | style: TextStyle( |
| | | color: ColorConstant.theme), |
| | | ), |
| | | onTap: () { |
| | | NavigatorUtil.navigateToNextPage( |
| | | context, |
| | | EmailRegisterPage(title: ""), |
| | | (data) { |
| | | FocusScope.of(context).requestFocus(FocusNode()); |
| | | }); |
| | | }, |
| | | ), |
| | | Expanded(child: Container()), |
| | | InkWell( |
| | | child: const Text("找回密码?", |
| | | style: TextStyle( |
| | | color: ColorConstant.theme)), |
| | | onTap: () { |
| | | NavigatorUtil.navigateToNextPage( |
| | | context, |
| | | EmailFindPwdPage(title: ""), |
| | | (data) { |
| | | FocusScope.of(context).requestFocus(FocusNode()); |
| | | }); |
| | | |
| | | }, |
| | | ), |
| | | ], |
| | | ) |
| | | ])))), |
| | | //用户协议与隐私政策 |
| | | Row(children: [ |
| | | Container( |
| | | width: 25, |
| | | ), |
| | | RoundCheckBox( |
| | | value: checked, |
| | | onChanged: (value) { |
| | | setState(() { |
| | | checked = value; |
| | | }); |
| | | }, |
| | | ), |
| | | Expanded( |
| | | child: Container( |
| | | child: HtmlWidget( |
| | | "<p>登录即表明同意 <a href='${Constant.PROTOCOL_URL}'>用户协议</a> 和 <a href='${Constant.PRIVACY_URL}'>隐私政策</a> </p>", |
| | | textStyle: |
| | | const TextStyle(color: Color(0xFF999999)), |
| | | customStylesBuilder: (element) { |
| | | // print(element.localName); |
| | | // if (element.localName == 'a') { |
| | | // return {'color': 'red'}; |
| | | // } |
| | | |
| | | return null; |
| | | }, onTapUrl: (url) { |
| | | String? title = ""; |
| | | if (url == Constant.PROTOCOL_URL) { |
| | | title = "用户协议"; |
| | | } else { |
| | | title = "隐私政策"; |
| | | } |
| | | |
| | | NavigatorUtil.navigateToNextPage( |
| | | context, |
| | | BrowserPage( |
| | | title: title, |
| | | url: url, |
| | | ), |
| | | (data) {}); |
| | | |
| | | return true; |
| | | }))), |
| | | ]) |
| | | ]), |
| | | //关闭按钮 |
| | | Positioned( |
| | | top: 30, |
| | | left: 20, |
| | | child: InkWell( |
| | | onTap: () { |
| | | Navigator.of(context).pop(); |
| | | }, |
| | | child: Icon( |
| | | Icons.close, |
| | | size: 30, |
| | | ))) |
| | | ], |
| | | )); |
| | | } |
| | | |
| | | Widget getLoginContent() { |
| | | return Column( |
| | | crossAxisAlignment: CrossAxisAlignment.start, |
| | | children: [ |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: EdgeInsets.fromLTRB(20, 0, 5, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_email.png", |
| | | width: 17, |
| | | height: 15, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | phone = value; |
| | | }); |
| | | }, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.emailAddress, |
| | | controller: emailController, |
| | | maxLength: 60, |
| | | decoration: InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入邮箱", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 10), |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: const EdgeInsets.fromLTRB(20, 0, 7, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_pwd.png", |
| | | width: 16.5, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style:const TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | phone = value; |
| | | }); |
| | | }, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.visiblePassword, |
| | | controller: codeController, |
| | | maxLength: 32, |
| | | decoration: const InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入密码", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 20), |
| | | MyFillButton( |
| | | "登 录", |
| | | 10, |
| | | height: 45, |
| | | color: const Color(0xFFFF2B4B), |
| | | fontSize: 17, |
| | | enable: StringUtil.isEmail(emailController!.value.text) && |
| | | codeController!.value.text.length >= 6, |
| | | |
| | | onClick: () { |
| | | if (!(StringUtil.isEmail(emailController!.value.text) && |
| | | codeController!.value.text.length >= 6)) { |
| | | return; |
| | | } |
| | | |
| | | if (!checked) { |
| | | Fluttertoast.showToast(msg: "请同意用户协议与隐私政策"); |
| | | return; |
| | | } |
| | | |
| | | UserApiUtil.login(context, emailController!.value.text, |
| | | codeController!.value.text, "") |
| | | .then((value) { |
| | | print("结果: $value"); |
| | | if (value!["code"] == 0) { |
| | | UserInfo user = UserInfo.fromJson(value["data"]); |
| | | _loginSuccess(user); |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | }); |
| | | }, |
| | | ), |
| | | ], |
| | | ); |
| | | } |
| | | } |
New file |
| | |
| | | import 'dart:async'; |
| | | import 'dart:convert'; |
| | | import 'dart:ui'; |
| | | |
| | | import 'package:flutter/cupertino.dart'; |
| | | import 'package:flutter/material.dart'; |
| | | import 'package:flutter/services.dart'; |
| | | import 'package:fluttertoast/fluttertoast.dart'; |
| | | import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; |
| | | import 'package:html/dom.dart' as dom; |
| | | import '../../api/http.dart'; |
| | | import '../../model/user/user_info.dart'; |
| | | import '../../ui/common/browser.dart'; |
| | | import '../../ui/widget/button.dart'; |
| | | import '../../utils/event_bus_util.dart'; |
| | | import '../../utils/pageutils.dart'; |
| | | import '../../utils/push_util.dart'; |
| | | import '../../utils/string_util.dart'; |
| | | import '../../utils/ui_constant.dart'; |
| | | import '../../utils/ui_utils.dart'; |
| | | import '../../utils/user_util.dart'; |
| | | import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; |
| | | |
| | | void main() { |
| | | runApp(MyApp()); |
| | | } |
| | | |
| | | class MyApp extends StatelessWidget { |
| | | // This widget is the root of your application. |
| | | @override |
| | | Widget build(BuildContext context) { |
| | | return MaterialApp( |
| | | title: '注册', |
| | | theme: ThemeData(primaryColor: Color(0xFFF5F5F5)), |
| | | home: EmailFindPwdPage(title: ''), |
| | | ); |
| | | } |
| | | } |
| | | |
| | | class EmailFindPwdPage extends StatefulWidget { |
| | | //阿里云一键登录 |
| | | static const messageChannel = |
| | | BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec()); |
| | | |
| | | EmailFindPwdPage({Key? key, required this.title}) : super(key: key); |
| | | |
| | | // This widget is the home page of your application. It is stateful, meaning |
| | | // that it has a State object (defined below) that contains fields that affect |
| | | // how it looks. |
| | | |
| | | // This class is the configuration for the state. It holds the values (in this |
| | | // case the title) provided by the parent (in this case the App widget) and |
| | | // used by the build method of the State. Fields in a Widget subclass are |
| | | // always marked "final". |
| | | |
| | | final String title; |
| | | |
| | | @override |
| | | _EmailFindPwdPageState createState() => _EmailFindPwdPageState(); |
| | | } |
| | | |
| | | class _EmailFindPwdPageState extends State<EmailFindPwdPage> |
| | | with SingleTickerProviderStateMixin { |
| | | TextEditingController? emailController = TextEditingController(); |
| | | TextEditingController? codeController = TextEditingController(); |
| | | TextEditingController? pwdController = TextEditingController(); |
| | | String email = ""; |
| | | String code = ""; |
| | | Timer? timer; |
| | | |
| | | //重新发送验证码倒计时 |
| | | int? reSendSMSTimeLeft; |
| | | |
| | | @override |
| | | void initState() { |
| | | super.initState(); |
| | | reSendSMSTimeLeft = -1; |
| | | //初始化微信登录监听 |
| | | fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { |
| | | if (res is fluwx.WeChatAuthResponse) { |
| | | int errCode = res.errCode; |
| | | if (errCode == 0) { |
| | | String? code = res.code; |
| | | //TODO 把微信登录返回的code传给后台,剩下的事就交给后台处理 |
| | | } else if (errCode == -4) { |
| | | //showToast("用户拒绝授权"); |
| | | } else if (errCode == -2) { |
| | | // showToast("用户取消授权"); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | bool _aliyunLogin = false; |
| | | |
| | | void aliyunOneKeyLogin() async { |
| | | if (_aliyunLogin) { |
| | | return; |
| | | } |
| | | _aliyunLogin = true; |
| | | Future.delayed(const Duration(milliseconds: 1000), () { |
| | | _aliyunLogin = false; |
| | | }); |
| | | |
| | | showLoading(context); |
| | | |
| | | Map value = |
| | | await EmailFindPwdPage.messageChannel.send({"method": "checkEnv"}) as Map; |
| | | dismissDialog(context); |
| | | if (value["code"] == 0) { |
| | | value = |
| | | await EmailFindPwdPage.messageChannel.send({"method": "startLogin"}) as Map; |
| | | print("返回内容:${jsonEncode(value)}"); |
| | | if (value["code"] == 0) { |
| | | Map<String, dynamic>? resultValue = |
| | | await UserApiUtil.login(context, "", "", value["token"]); |
| | | |
| | | EmailFindPwdPage.messageChannel.send({"method": "closeLogin"}); |
| | | |
| | | if (resultValue == null) return; |
| | | |
| | | if (resultValue["code"] == 0) { |
| | | UserInfo user = UserInfo.fromJson(resultValue["data"]); |
| | | _loginSuccess(user); |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | } else if (value["code"] == 700000) { |
| | | //Fluttertoast.showToast(msg: "取消登录了"); |
| | | } |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | } |
| | | |
| | | void qqLogin() async { |
| | | Map value = await UserUtil.loginQQ(); |
| | | } |
| | | |
| | | void _loginSuccess(UserInfo user) { |
| | | UserUtil.setUserInfo(user).then((value) { |
| | | print("登录成功"); |
| | | eventBus.fire(LoginEventBus(true)); |
| | | PushUtil.setAlias(user.id!.toString()).then((value) { |
| | | Navigator.pop(context); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | @override |
| | | void dispose() { |
| | | if (timer != null) { |
| | | timer!.cancel(); |
| | | } |
| | | super.dispose(); |
| | | } |
| | | |
| | | BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) { |
| | | return BoxDecoration( |
| | | borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), |
| | | color: bgColor, |
| | | boxShadow: [ |
| | | BoxShadow( |
| | | color: shadowColor, |
| | | blurRadius: 2.0, |
| | | offset: Offset(0.0, 5.0), //阴影y轴偏移量 |
| | | spreadRadius: 1 //阴影扩散程度 |
| | | ) |
| | | ]); |
| | | } |
| | | |
| | | @override |
| | | Widget build(BuildContext context) { |
| | | return Scaffold( |
| | | resizeToAvoidBottomInset: false, |
| | | backgroundColor: Colors.white, |
| | | body: Stack( |
| | | children: [ |
| | | Column(children: [ |
| | | //登录内容区域 |
| | | Expanded( |
| | | child: SingleChildScrollView( |
| | | child: Padding( |
| | | padding: EdgeInsets.fromLTRB(40, 120, 40, 14), |
| | | child: Column( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/ic_login_logo.png", |
| | | width: 131, |
| | | ), |
| | | Container( |
| | | height: 70, |
| | | ), |
| | | Container( |
| | | constraints: BoxConstraints(minHeight: 200), |
| | | child: getLoginContent()), |
| | | Container( |
| | | height: 30, |
| | | ) |
| | | ])))), |
| | | |
| | | ]), |
| | | //关闭按钮 |
| | | Positioned( |
| | | top: 30, |
| | | left: 20, |
| | | child: InkWell( |
| | | onTap: () { |
| | | Navigator.of(context).pop(); |
| | | }, |
| | | child: const Icon( |
| | | Icons.arrow_back_ios_new, |
| | | size: 25, |
| | | ))) |
| | | ], |
| | | )); |
| | | } |
| | | |
| | | Widget getLoginContent() { |
| | | return Column( |
| | | crossAxisAlignment: CrossAxisAlignment.start, |
| | | children: [ |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: EdgeInsets.fromLTRB(20, 0, 5, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_email.png", |
| | | width: 17, |
| | | height: 15, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | email = value; |
| | | }); |
| | | }, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.emailAddress, |
| | | controller: emailController, |
| | | maxLength: 60, |
| | | decoration: InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入邮箱", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 10), |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: EdgeInsets.fromLTRB(20, 0, 7, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_code.png", |
| | | width: 16.5, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | email = value; |
| | | }); |
| | | }, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.phone, |
| | | controller: codeController, |
| | | maxLength: 8, |
| | | decoration: const InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入验证码", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | MyFillButton( |
| | | (reSendSMSTimeLeft! > 0 |
| | | ? (reSendSMSTimeLeft.toString() + "S重新获取") |
| | | : reSendSMSTimeLeft == -1 |
| | | ? "获取验证码" |
| | | : "重新获取") |
| | | .toString(), |
| | | 10, |
| | | height: 34, |
| | | padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), |
| | | enable: (reSendSMSTimeLeft! < 1 && |
| | | StringUtil.isEmail(emailController!.value.text)), |
| | | onClick: () { |
| | | if (!(reSendSMSTimeLeft! < 1 && |
| | | StringUtil.isEmail(emailController!.value.text))) { |
| | | return; |
| | | } |
| | | //发送验证码 |
| | | UserApiUtil.sendSMS( |
| | | context, emailController!.value.text) |
| | | .then((value) { |
| | | if (value != null && value["code"] == 0) { |
| | | setState(() { |
| | | reSendSMSTimeLeft = 60; |
| | | //倒计时 |
| | | timer = Timer.periodic(const Duration(seconds: 1), |
| | | (timer) { |
| | | if (reSendSMSTimeLeft! > 0) { |
| | | setState(() { |
| | | reSendSMSTimeLeft = reSendSMSTimeLeft! - 1; |
| | | }); |
| | | } else { |
| | | timer.cancel(); |
| | | } |
| | | }); |
| | | }); |
| | | } else { |
| | | ToastUtil.toast(value!["msg"]); |
| | | } |
| | | }); |
| | | }, |
| | | ), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 10), |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: const EdgeInsets.fromLTRB(20, 0, 7, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_pwd.png", |
| | | width: 16.5, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | email = value; |
| | | }); |
| | | }, |
| | | obscureText: true, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.visiblePassword, |
| | | controller: pwdController, |
| | | maxLength: 32, |
| | | decoration: const InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入密码", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 52), |
| | | MyFillButton( |
| | | "设置密码", |
| | | 10, |
| | | height: 45, |
| | | color: ColorConstant.theme, |
| | | fontSize: 17, |
| | | enable: StringUtil.isEmail(emailController!.value.text) && |
| | | codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6, |
| | | onClick: () { |
| | | if (!(StringUtil.isEmail(emailController!.value.text) && |
| | | codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6)) { |
| | | return; |
| | | } |
| | | |
| | | UserApiUtil.login(context, emailController!.value.text, |
| | | codeController!.value.text, "") |
| | | .then((value) { |
| | | print("结果: $value"); |
| | | if (value!["code"] == 0) { |
| | | UserInfo user = UserInfo.fromJson(value["data"]); |
| | | _loginSuccess(user); |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | }); |
| | | }, |
| | | ), |
| | | ], |
| | | ); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | import 'dart:async'; |
| | | import 'dart:convert'; |
| | | import 'dart:ui'; |
| | | |
| | | import 'package:flutter/cupertino.dart'; |
| | | import 'package:flutter/material.dart'; |
| | | import 'package:flutter/services.dart'; |
| | | import 'package:fluttertoast/fluttertoast.dart'; |
| | | import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; |
| | | import 'package:html/dom.dart' as dom; |
| | | import '../../api/http.dart'; |
| | | import '../../model/user/user_info.dart'; |
| | | import '../../ui/common/browser.dart'; |
| | | import '../../ui/widget/button.dart'; |
| | | import '../../utils/event_bus_util.dart'; |
| | | import '../../utils/pageutils.dart'; |
| | | import '../../utils/push_util.dart'; |
| | | import '../../utils/string_util.dart'; |
| | | import '../../utils/ui_constant.dart'; |
| | | import '../../utils/ui_utils.dart'; |
| | | import '../../utils/user_util.dart'; |
| | | import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; |
| | | |
| | | void main() { |
| | | runApp(MyApp()); |
| | | } |
| | | |
| | | class MyApp extends StatelessWidget { |
| | | // This widget is the root of your application. |
| | | @override |
| | | Widget build(BuildContext context) { |
| | | return MaterialApp( |
| | | title: '注册', |
| | | theme: ThemeData(primaryColor: Color(0xFFF5F5F5)), |
| | | home: EmailRegisterPage(title: ''), |
| | | ); |
| | | } |
| | | } |
| | | |
| | | class EmailRegisterPage extends StatefulWidget { |
| | | //阿里云一键登录 |
| | | static const messageChannel = |
| | | BasicMessageChannel('AliyunPhoneNumberAuth', StandardMessageCodec()); |
| | | |
| | | EmailRegisterPage({Key? key, required this.title}) : super(key: key); |
| | | |
| | | // This widget is the home page of your application. It is stateful, meaning |
| | | // that it has a State object (defined below) that contains fields that affect |
| | | // how it looks. |
| | | |
| | | // This class is the configuration for the state. It holds the values (in this |
| | | // case the title) provided by the parent (in this case the App widget) and |
| | | // used by the build method of the State. Fields in a Widget subclass are |
| | | // always marked "final". |
| | | |
| | | final String title; |
| | | |
| | | @override |
| | | _EmailRegisterPageState createState() => _EmailRegisterPageState(); |
| | | } |
| | | |
| | | class _EmailRegisterPageState extends State<EmailRegisterPage> |
| | | with SingleTickerProviderStateMixin { |
| | | bool checked = false; |
| | | TextEditingController? emailController = TextEditingController(); |
| | | TextEditingController? codeController = TextEditingController(); |
| | | TextEditingController? pwdController = TextEditingController(); |
| | | String email = ""; |
| | | String code = ""; |
| | | Timer? timer; |
| | | |
| | | //重新发送验证码倒计时 |
| | | int? reSendSMSTimeLeft; |
| | | |
| | | @override |
| | | void initState() { |
| | | super.initState(); |
| | | reSendSMSTimeLeft = -1; |
| | | //初始化微信登录监听 |
| | | fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { |
| | | if (res is fluwx.WeChatAuthResponse) { |
| | | int errCode = res.errCode; |
| | | if (errCode == 0) { |
| | | String? code = res.code; |
| | | //TODO 把微信登录返回的code传给后台,剩下的事就交给后台处理 |
| | | } else if (errCode == -4) { |
| | | //showToast("用户拒绝授权"); |
| | | } else if (errCode == -2) { |
| | | // showToast("用户取消授权"); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | bool _aliyunLogin = false; |
| | | |
| | | void aliyunOneKeyLogin() async { |
| | | if (_aliyunLogin) { |
| | | return; |
| | | } |
| | | _aliyunLogin = true; |
| | | Future.delayed(const Duration(milliseconds: 1000), () { |
| | | _aliyunLogin = false; |
| | | }); |
| | | |
| | | showLoading(context); |
| | | |
| | | Map value = |
| | | await EmailRegisterPage.messageChannel.send({"method": "checkEnv"}) as Map; |
| | | dismissDialog(context); |
| | | if (value["code"] == 0) { |
| | | value = |
| | | await EmailRegisterPage.messageChannel.send({"method": "startLogin"}) as Map; |
| | | print("返回内容:${jsonEncode(value)}"); |
| | | if (value["code"] == 0) { |
| | | Map<String, dynamic>? resultValue = |
| | | await UserApiUtil.login(context, "", "", value["token"]); |
| | | |
| | | EmailRegisterPage.messageChannel.send({"method": "closeLogin"}); |
| | | |
| | | if (resultValue == null) return; |
| | | |
| | | if (resultValue["code"] == 0) { |
| | | UserInfo user = UserInfo.fromJson(resultValue["data"]); |
| | | _loginSuccess(user); |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | } else if (value["code"] == 700000) { |
| | | //Fluttertoast.showToast(msg: "取消登录了"); |
| | | } |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | } |
| | | |
| | | void qqLogin() async { |
| | | Map value = await UserUtil.loginQQ(); |
| | | } |
| | | |
| | | void _loginSuccess(UserInfo user) { |
| | | UserUtil.setUserInfo(user).then((value) { |
| | | print("登录成功"); |
| | | eventBus.fire(LoginEventBus(true)); |
| | | PushUtil.setAlias(user.id!.toString()).then((value) { |
| | | Navigator.pop(context); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | @override |
| | | void dispose() { |
| | | if (timer != null) { |
| | | timer!.cancel(); |
| | | } |
| | | super.dispose(); |
| | | } |
| | | |
| | | BoxDecoration getItemDecoration(Color bgColor, Color shadowColor) { |
| | | return BoxDecoration( |
| | | borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), |
| | | color: bgColor, |
| | | boxShadow: [ |
| | | BoxShadow( |
| | | color: shadowColor, |
| | | blurRadius: 2.0, |
| | | offset: Offset(0.0, 5.0), //阴影y轴偏移量 |
| | | spreadRadius: 1 //阴影扩散程度 |
| | | ) |
| | | ]); |
| | | } |
| | | |
| | | @override |
| | | Widget build(BuildContext context) { |
| | | return Scaffold( |
| | | resizeToAvoidBottomInset: false, |
| | | backgroundColor: Colors.white, |
| | | body: Stack( |
| | | children: [ |
| | | Column(children: [ |
| | | //登录内容区域 |
| | | Expanded( |
| | | child: SingleChildScrollView( |
| | | child: Padding( |
| | | padding: EdgeInsets.fromLTRB(40, 120, 40, 14), |
| | | child: Column( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/ic_login_logo.png", |
| | | width: 131, |
| | | ), |
| | | Container( |
| | | height: 70, |
| | | ), |
| | | Container( |
| | | constraints: BoxConstraints(minHeight: 200), |
| | | child: getLoginContent()), |
| | | Container( |
| | | height: 30, |
| | | ) |
| | | ])))), |
| | | //用户协议与隐私政策 |
| | | Row(children: [ |
| | | Container( |
| | | width: 25, |
| | | ), |
| | | RoundCheckBox( |
| | | value: checked, |
| | | onChanged: (value) { |
| | | setState(() { |
| | | checked = value; |
| | | }); |
| | | }, |
| | | ), |
| | | Expanded( |
| | | child: Container( |
| | | child: HtmlWidget( |
| | | "<p>登录即表明同意 <a href='${Constant.PROTOCOL_URL}'>用户协议</a> 和 <a href='${Constant.PRIVACY_URL}'>隐私政策</a> </p>", |
| | | textStyle: |
| | | const TextStyle(color: Color(0xFF999999)), |
| | | onTapUrl: (url) { |
| | | String? title = ""; |
| | | if (url == Constant.PROTOCOL_URL) { |
| | | title = "用户协议"; |
| | | } else { |
| | | title = "隐私政策"; |
| | | } |
| | | |
| | | NavigatorUtil.navigateToNextPage( |
| | | context, |
| | | BrowserPage( |
| | | title: title, |
| | | url: url, |
| | | ), |
| | | (data) {}); |
| | | |
| | | return true; |
| | | }))), |
| | | ]) |
| | | ]), |
| | | //关闭按钮 |
| | | Positioned( |
| | | top: 30, |
| | | left: 20, |
| | | child: InkWell( |
| | | onTap: () { |
| | | Navigator.of(context).pop(); |
| | | }, |
| | | child: const Icon( |
| | | Icons.arrow_back_ios_new, |
| | | size: 25, |
| | | ))) |
| | | ], |
| | | )); |
| | | } |
| | | |
| | | Widget getLoginContent() { |
| | | return Column( |
| | | crossAxisAlignment: CrossAxisAlignment.start, |
| | | children: [ |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: EdgeInsets.fromLTRB(20, 0, 5, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_email.png", |
| | | width: 17, |
| | | height: 15, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | email = value; |
| | | }); |
| | | }, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.emailAddress, |
| | | controller: emailController, |
| | | maxLength: 60, |
| | | decoration: InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入邮箱", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 10), |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: EdgeInsets.fromLTRB(20, 0, 7, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_code.png", |
| | | width: 16.5, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | email = value; |
| | | }); |
| | | }, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.phone, |
| | | controller: codeController, |
| | | maxLength: 8, |
| | | decoration: const InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入验证码", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | MyFillButton( |
| | | (reSendSMSTimeLeft! > 0 |
| | | ? (reSendSMSTimeLeft.toString() + "S重新获取") |
| | | : reSendSMSTimeLeft == -1 |
| | | ? "获取验证码" |
| | | : "重新获取") |
| | | .toString(), |
| | | 10, |
| | | height: 34, |
| | | padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), |
| | | enable: (reSendSMSTimeLeft! < 1 && |
| | | StringUtil.isEmail(emailController!.value.text)), |
| | | onClick: () { |
| | | if (!(reSendSMSTimeLeft! < 1 && |
| | | StringUtil.isEmail(emailController!.value.text))) { |
| | | return; |
| | | } |
| | | //发送验证码 |
| | | UserApiUtil.sendSMS( |
| | | context, emailController!.value.text) |
| | | .then((value) { |
| | | if (value != null && value["code"] == 0) { |
| | | setState(() { |
| | | reSendSMSTimeLeft = 60; |
| | | //倒计时 |
| | | timer = Timer.periodic(const Duration(seconds: 1), |
| | | (timer) { |
| | | if (reSendSMSTimeLeft! > 0) { |
| | | setState(() { |
| | | reSendSMSTimeLeft = reSendSMSTimeLeft! - 1; |
| | | }); |
| | | } else { |
| | | timer.cancel(); |
| | | } |
| | | }); |
| | | }); |
| | | } else { |
| | | ToastUtil.toast(value!["msg"]); |
| | | } |
| | | }); |
| | | }, |
| | | ), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 10), |
| | | Container( |
| | | alignment: Alignment.centerLeft, |
| | | padding: const EdgeInsets.fromLTRB(20, 0, 7, 0), |
| | | decoration: BoxDecoration( |
| | | color: const Color(0xFFF5F5F5), |
| | | borderRadius: BorderRadius.circular(10)), |
| | | child: Row( |
| | | crossAxisAlignment: CrossAxisAlignment.center, |
| | | children: [ |
| | | Image.asset( |
| | | "assets/imgs/login/icon_pwd.png", |
| | | width: 16.5, |
| | | ), |
| | | Container(width: 14), |
| | | Expanded( |
| | | child: TextField( |
| | | style: TextStyle(color: Color(0xFF333333), fontSize: 17), |
| | | onChanged: (value) { |
| | | setState(() { |
| | | email = value; |
| | | }); |
| | | }, |
| | | obscureText: true, |
| | | textAlign: TextAlign.start, |
| | | keyboardType: TextInputType.visiblePassword, |
| | | controller: pwdController, |
| | | maxLength: 32, |
| | | decoration: const InputDecoration( |
| | | counterText: "", |
| | | hintText: "请输入密码", |
| | | hintStyle: |
| | | TextStyle(color: Color(0xFFCCCCCC), fontSize: 17), |
| | | contentPadding: EdgeInsets.only(bottom: 3), |
| | | border: InputBorder.none, |
| | | focusedBorder: InputBorder.none, |
| | | ), |
| | | )), |
| | | ], |
| | | ), |
| | | ), |
| | | Container(height: 52), |
| | | MyFillButton( |
| | | "注 册", |
| | | 10, |
| | | height: 45, |
| | | color: ColorConstant.theme, |
| | | fontSize: 17, |
| | | enable: StringUtil.isEmail(emailController!.value.text) && |
| | | codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6, |
| | | onClick: () { |
| | | if (!(StringUtil.isEmail(emailController!.value.text) && |
| | | codeController!.value.text.length >= 4&&pwdController!.value.text.length >= 6)) { |
| | | return; |
| | | } |
| | | |
| | | if (!checked) { |
| | | Fluttertoast.showToast(msg: "请同意用户协议与隐私政策"); |
| | | return; |
| | | } |
| | | |
| | | UserApiUtil.login(context, emailController!.value.text, |
| | | codeController!.value.text, "") |
| | | .then((value) { |
| | | print("结果: $value"); |
| | | if (value!["code"] == 0) { |
| | | UserInfo user = UserInfo.fromJson(value["data"]); |
| | | _loginSuccess(user); |
| | | } else { |
| | | Fluttertoast.showToast(msg: value["msg"]); |
| | | } |
| | | }); |
| | | }, |
| | | ), |
| | | ], |
| | | ); |
| | | } |
| | | |
| | | } |