|
|
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 '../user/content_authority_page.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<LoginPage> {
|
|
|
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;
|
|
|
DateTime? _lastTap;
|
|
|
|
|
|
@override
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
_phoneFocusNode = FocusNode();
|
|
|
_smsCodeFocusNode = FocusNode();
|
|
|
_phoneController = TextEditingController();
|
|
|
_smsCodeController = TextEditingController();
|
|
|
final userProvider = Provider.of<UserProvider>(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.unfocus();
|
|
|
_smsCodeFocusNode.unfocus();
|
|
|
_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 {
|
|
|
// DateTime? _lastTap;
|
|
|
if (_phoneController.text.length < 11) {
|
|
|
BotToast.showText(text: "请输入手机号");
|
|
|
} else if (_smsCodeController.text.length < 6) {
|
|
|
BotToast.showText(text: "请输入验证码");
|
|
|
} else if (!_chooseAgreement) {
|
|
|
BotToast.showText(text: "请同意并勾选隐私政策");
|
|
|
} else {
|
|
|
if (_lastTap != null && DateTime.now().difference(_lastTap!).inSeconds < 2) {
|
|
|
// BotToast.showText(text: "过快");
|
|
|
return;
|
|
|
}
|
|
|
_lastTap = DateTime.now();
|
|
|
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.offAll(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,
|
|
|
});
|
|
|
var res = RegExp(
|
|
|
r'^((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\d{8}$');
|
|
|
if ((_phoneController.text).isNotEmpty &&
|
|
|
res.hasMatch(_phoneController.text)) {
|
|
|
_beginCountDown();
|
|
|
} else {
|
|
|
BotToast.showText(text: "手机号不能为空且手机号格式错误");
|
|
|
}
|
|
|
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) {
|
|
|
Get.to(() => const ContentAuthorityPage());
|
|
|
// 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, 2)),
|
|
|
],
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
}
|