import 'dart:async'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:project_telephony/ui/widget/plone_back_button.dart'; import 'package:project_telephony/utils/headers.dart'; import 'package:provider/provider.dart'; import '../../base/base_style.dart'; import '../../constants/api.dart'; import '../../constants/environment/environment.dart'; import '../../model/network/api_client.dart'; import '../../providers/user_provider.dart'; import '../../utils/toast/cloud_toast.dart'; import '../../utils/user_tool.dart'; import '../tab_navigator.dart'; import '../widget/image_scaffold.dart'; import '../widget/plone_bottom.dart'; class LoginPage extends StatefulWidget { const LoginPage({Key? key}) : super(key: key); @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State { bool _chooseAgreement = false; bool _getCodeEnable = true; late Timer _timer; ///时钟 String _countDownStr = "发送验证码"; ///初始化文本 int _countDownNum = 59; late TextEditingController _phoneController; late TextEditingController _smsCodeController; late FocusNode _phoneFocusNode; late FocusNode _smsCodeFocusNode; bool _cantSelected = false; @override void initState() { super.initState(); _phoneFocusNode = FocusNode(); _smsCodeFocusNode = FocusNode(); _phoneController = TextEditingController(); _smsCodeController = TextEditingController(); final userProvider = Provider.of(context, listen: false); var env = const String.fromEnvironment('ENV', defaultValue: 'dev'); if (kDebugMode) { print('env :$env'); } DevEV.instance.setEnvironment( context, environment: env == 'dev', ); } @override void dispose() { _phoneFocusNode.dispose(); _smsCodeFocusNode.dispose(); _phoneController.dispose(); _smsCodeController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return CloudScaffold( systemStyle: const SystemUiOverlayStyle( statusBarIconBrightness: Brightness.dark, ), path: Assets.images.bg.path, appbar: Row( children: [ Padding( padding: EdgeInsets.only(top: 88.w, left: 8.w), child: const CloudBackButton(isSpecial: true), ), Padding( padding: EdgeInsets.only(left: 186.w, top: 88.w), child: Text( "登录/注册", style: TextStyle( fontSize: BaseStyle.fontSize34, color: BaseStyle.color333333, fontWeight: FontWeight.bold), )) ], ), extendBody: true, body: Container( padding: EdgeInsets.only(left: 64.w, right: 64.w, top: 124.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "短信帮手", style: TextStyle( fontSize: 64.sp, fontWeight: FontWeight.bold, color: Colors.black), ), 32.hb, Text( "希望能成为您的短信小助手", style: TextStyle(fontSize: 32.sp, color: const Color(0xFF999999)), ), 80.hb, _getBox('+86', 36, _phoneTFWidget()), _getBox('验证码', 32, _codeWidget()), 112.hb, PloneBottom( blM: false, border: _phoneController.text.length != 11, opacity: _phoneController.text.length == 11 ? 1 : 0.4, onTap: () async{ if (_phoneController.text.length < 11) { BotToast.showText(text: "请输入手机号"); }else if(_smsCodeController.text.length < 6){ BotToast.showText(text: "请输入验证码"); }else if(!_chooseAgreement){ BotToast.showText(text: "请同意并勾选隐私政策"); }else{ var base = await apiClient.request(API.app.login, data: {'phone': _phoneController.text, 'code': _smsCodeController.text}); if (base.code == 0) { await UserTool.userProvider.setToken(base.data['token']); Get.to(() => const TabNavigator()); } else { CloudToast.show(base.msg); } } }, text: "立即登录", ), 32.hb, _getText() ], ), ), ); } _getBox(String text, int fontSize, Widget plone) { return Container( height: 144.w, width: double.infinity, padding: EdgeInsets.symmetric(vertical: 48.w), decoration: BoxDecoration( // color: Colors.black12, border: Border( bottom: BorderSide(color: const Color(0xFFE8E8E8), width: 1.w), ), ), child: Row(children: [ SizedBox( width: 112.w, child: Text( text, style: TextStyle( fontSize: fontSize.sp, color: BaseStyle.color333333, fontWeight: FontWeight.bold), ), ), Container( width: 2.w, height: 48.w, margin: EdgeInsets.symmetric(horizontal: 32.w), color: const Color(0xFFE8E8E8), ), plone, ]), ); } // 输入手机号 _phoneTFWidget() { return SizedBox( // alignment: Alignment.centerLeft, // padding: EdgeInsets.symmetric(horizontal: 72.w), width: 430.w, height: 50.w, child: TextField( maxLength: 11, inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))], textCapitalization: TextCapitalization.none, onChanged: (text) { _phoneController.text = text; setState(() {}); }, decoration: InputDecoration( contentPadding: EdgeInsets.only(bottom: 20.w), border: InputBorder.none, counterText: "", //textfield占位语,类似于iOS中的placeholder hintText: "请输入手机号", //占位语颜色 hintStyle: const TextStyle(color: Colors.black12), suffixIcon: GestureDetector( onTap: !_getCodeEnable ? () {} : () async { await apiClient.request(API.app.captcha, data: { 'phone': _phoneController.text, }); _beginCountDown(); if (_cantSelected) return; _cantSelected = true; Future.delayed(const Duration(seconds: 1), () { _cantSelected = false; }); }, child: Container( width: 180.w, alignment: Alignment.centerRight, color: Colors.transparent, child: Text( _countDownStr, style: TextStyle( color: _getCodeEnable ? kPrimaryColor : BaseStyle.colorcccccc), ), ), )), ), ); } // 输入验证码 _codeWidget() { return SizedBox( // alignment: Alignment.centerLeft, // padding: EdgeInsets.symmetric(horizontal: 72.w), width: 430.w, height: 50.w, child: TextField( maxLength: 6, inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))], textCapitalization: TextCapitalization.none, onChanged: (text) { _smsCodeController.text = text; setState(() {}); }, decoration: InputDecoration( contentPadding: EdgeInsets.only(bottom: 20.w), border: InputBorder.none, counterText: "", //textfield占位语,类似于iOS中的placeholder hintText: "请输入验证码", //占位语颜色 hintStyle: const TextStyle(color: Colors.black12), ), ), ); } _beginCountDown() { ///开始倒计时 setState(() { _getCodeEnable = false; _countDownStr = "${_countDownNum}s"; }); _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (!mounted) { return; } setState(() { if (_countDownNum == 0) { _countDownNum = 59; _countDownStr = "获取验证码"; _getCodeEnable = true; _timer.cancel(); return; } _countDownStr = "${_countDownNum--}s"; }); }); } // 协议 _recognizer(context, int type) { final TapGestureRecognizer recognizer = TapGestureRecognizer(); recognizer.onTap = () { if (kDebugMode) { print("点击协议了"); } ///跳转到用户协议页面 }; return recognizer; } _getText() { return GestureDetector( onTap: () { _chooseAgreement = !_chooseAgreement; setState(() {}); }, child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 50.w, height: 50.w, padding: EdgeInsets.only(top: 6.w, right: 5.w), child: !_chooseAgreement ? const Icon(CupertinoIcons.circle, size: 18, color: Color(0xFFdddddd)) : const Icon(CupertinoIcons.checkmark_circle, size: 18, color: Colors.blue), ), RichText( text: TextSpan( text: "我已阅读并同意", style: TextStyle( color: BaseStyle.colorcccccc, fontSize: 12 * 2.sp), children: [ TextSpan( text: '《用户服务协议》', style: TextStyle(color: kPrimaryColor, fontSize: 12 * 2.sp), recognizer: _recognizer(context, 2)), TextSpan( text: "和", style: TextStyle( color: BaseStyle.colorcccccc, fontSize: 12 * 2.sp), ), TextSpan( text: '《隐私协议》', style: TextStyle(color: kPrimaryColor, fontSize: 12 * 2.sp), recognizer: _recognizer(context, 1)), ])), ], ), ); } }