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:fluwx_no_pay/fluwx_no_pay.dart' as fluwx; import '../../api/user_api.dart'; import 'email_pwd_find.dart'; import 'email_register.dart'; import '../widget/nav.dart'; import '../../utils/push_util.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/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 with SingleTickerProviderStateMixin { bool oneKeyLogin = false; bool checked = false; TextEditingController? emailController = TextEditingController(); TextEditingController? pwdController = 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("用户取消授权"); } } }); } 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) { popPage(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: const 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: const 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: const 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( "

登录即表明同意 用户协议 和 隐私政策 

", 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: () { popPage(context); }, child: const Icon( Icons.close, size: 30, ))) ], )); } Widget getLoginContent() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( alignment: Alignment.centerLeft, padding: const 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: const TextStyle(color: Color(0xFF333333), fontSize: 17), onChanged: (value) { setState(() { phone = value; }); }, textAlign: TextAlign.start, keyboardType: TextInputType.emailAddress, controller: emailController, maxLength: 60, 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: 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; }); }, 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: 20), MyFillButton( "登 录", 10, height: 45, color: const Color(0xFFFF2B4B), fontSize: 17, enable: StringUtil.isEmail(emailController!.value.text) && pwdController!.value.text.length >= 6, onClick: () { if (!(StringUtil.isEmail(emailController!.value.text) && pwdController!.value.text.length >= 6)) { return; } if (!checked) { ToastUtil.toast("请同意用户协议与隐私政策", context); return; } UserApiUtil.loginByEmail(context, emailController!.value.text, pwdController!.value.text) .then((value) { print("结果: $value"); if (value!["IsPost"] == "true") { UserInfo user = UserInfo.fromJson(value["Data"]); _loginSuccess(user); } else { ToastUtil.toast(value["Error"], context); } }); }, ), ], ); } }