You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
17 KiB
413 lines
17 KiB
import 'dart:async';
|
|
|
|
import 'package:dating_touchme_app/http/api.dart';
|
|
import 'package:dating_touchme_app/model/phone_code.dart';
|
|
import 'package:dating_touchme_app/router/route_paths.dart';
|
|
import 'package:dating_touchme_app/utils/storage.dart';
|
|
import 'package:dating_touchme_app/utils/utils.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:roundcheckbox/roundcheckbox.dart';
|
|
|
|
class LoginPage extends StatefulWidget {
|
|
const LoginPage({super.key});
|
|
|
|
@override
|
|
State<LoginPage> createState() => _LoginPageState();
|
|
}
|
|
|
|
class _LoginPageState extends State<LoginPage> {
|
|
|
|
String phone = '';
|
|
final TextEditingController _phoneController = TextEditingController();
|
|
String code = '';
|
|
final TextEditingController _codeController = TextEditingController();
|
|
|
|
String selectPhoneCode = "86";
|
|
int s = 0;
|
|
Timer? timer;
|
|
|
|
|
|
bool checked = false;
|
|
|
|
void toggleChecked(bool? value) {
|
|
checked = value ?? false;
|
|
setState(() {
|
|
});
|
|
}
|
|
|
|
sendMsg() async {
|
|
var res = await Api().$getAuthCaptcha({
|
|
"purpose":1,
|
|
"verifiableAccount":phone,
|
|
"verifiableAccountType":1
|
|
});
|
|
if(res["message"] == "successful"){
|
|
toast("发送成功", context);
|
|
setState(() {
|
|
s = 60;
|
|
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
setState(() {
|
|
s--;
|
|
if(s == 0){
|
|
timer.cancel();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
toast(res["msg"], context);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Stack(
|
|
children: [
|
|
Image.asset(
|
|
"assets/login_bg.png",
|
|
width: 750.w,
|
|
fit: BoxFit.cover,
|
|
),
|
|
Positioned(
|
|
top: 419.w,
|
|
left: 246.w,
|
|
child: Text(
|
|
"心动就动我 幸福马上行动",
|
|
style: TextStyle(
|
|
fontSize: 22.w,
|
|
color: const Color.fromRGBO(144, 144, 144, 1),
|
|
fontWeight: FontWeight.w500
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
top: 538.w,
|
|
child: Container(
|
|
width: 750.w,
|
|
padding: EdgeInsets.only(
|
|
left: 50.w,
|
|
right: 50.w,
|
|
top: 256.w
|
|
),
|
|
child: Column(
|
|
children: [
|
|
InputItem(child: TextField(
|
|
controller: _phoneController,
|
|
keyboardType: TextInputType.number,
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(28),
|
|
height: 1
|
|
),
|
|
decoration: InputDecoration(
|
|
prefixIcon: Container(
|
|
margin: EdgeInsets.only(right: 30.w),
|
|
decoration: const BoxDecoration(
|
|
border: Border(
|
|
right: BorderSide(color: const Color.fromRGBO(230, 230, 230, 1), width: 2),
|
|
),
|
|
),
|
|
child: TextButton(
|
|
onPressed: (){
|
|
final RenderBox renderBox = context.findRenderObject() as RenderBox;
|
|
final Rect size = renderBox.localToGlobal(Offset.zero) & renderBox.size;
|
|
final RelativeRect position = RelativeRect.fromRect(
|
|
Rect.fromPoints(size.topLeft, size.bottomRight),
|
|
Offset.zero & MediaQuery.of(context).size,
|
|
);
|
|
showMenu(
|
|
context: context,
|
|
position: position,
|
|
items: phoneCode.map((item){
|
|
return PopupMenuItem<String>(
|
|
value: item["tel"],
|
|
child: Container(
|
|
height: ScreenUtil().setWidth(100),
|
|
padding: EdgeInsets.symmetric(horizontal: ScreenUtil().setWidth(32)),
|
|
decoration: BoxDecoration(
|
|
border: Border( // 设置边框
|
|
bottom: BorderSide(
|
|
color: const Color.fromRGBO(228, 231, 237, 1), // 边框颜色
|
|
width: ScreenUtil().setWidth(1),
|
|
) // 边框宽度
|
|
),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
item["name"],
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(28),
|
|
color: selectPhoneCode != item["tel"] ?
|
|
const Color.fromRGBO(96, 98, 102, 1) :
|
|
const Color.fromRGBO(212, 15, 31, 1)
|
|
),
|
|
),
|
|
Text(
|
|
"+${item["tel"]}",
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(28),
|
|
color: selectPhoneCode != item["tel"] ?
|
|
const Color.fromRGBO(96, 98, 102, 1) :
|
|
const Color.fromRGBO(212, 15, 31, 1)
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
onTap: (){
|
|
setState(() {
|
|
selectPhoneCode = item["tel"];
|
|
});
|
|
},
|
|
);
|
|
}).toList(),
|
|
);
|
|
},
|
|
child: Text(
|
|
"+$selectPhoneCode",
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(35),
|
|
color: const Color.fromRGBO(51, 51, 51, 1)
|
|
),
|
|
),
|
|
),
|
|
),
|
|
contentPadding: EdgeInsets.symmetric(
|
|
vertical: 0,
|
|
horizontal: 34.w
|
|
),
|
|
hintText: "请输入你的手机号",
|
|
border: const OutlineInputBorder(
|
|
borderSide: BorderSide.none, // 这将移除边框 // 可选:设置圆角
|
|
),
|
|
// 如果你希望聚焦时和未聚焦时都没有边框,也可以设置 focusedBorder 和 enabledBorder
|
|
focusedBorder: const OutlineInputBorder(
|
|
borderSide: BorderSide.none,
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
),
|
|
enabledBorder: const OutlineInputBorder(
|
|
borderSide: BorderSide.none,
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
),
|
|
),
|
|
onChanged: (value){
|
|
phone = value;
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
)),
|
|
InputItem(child: TextField(
|
|
controller: _codeController,
|
|
keyboardType: TextInputType.number,
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(28),
|
|
height: 1
|
|
),
|
|
decoration: InputDecoration(
|
|
contentPadding: EdgeInsets.symmetric(
|
|
vertical: 0,
|
|
horizontal: 34.w
|
|
),
|
|
hintText: "请输入验证码",
|
|
|
|
suffixIcon: TextButton(
|
|
onPressed: (){
|
|
if(s > 0) return;
|
|
if(phone == ""){
|
|
toast("请输入你的手机号", context);
|
|
return;
|
|
}
|
|
// RegExp reg = RegExp(r'^1[3,4,5,6,7,8,9][0-9]{9}$');
|
|
// if(!reg.hasMatch(phone)){
|
|
// toast("请输入正确的手机号", context);
|
|
// return;
|
|
// }
|
|
sendMsg();
|
|
},
|
|
child: Text(
|
|
s > 0 ? "${s}s后再获取" : "获取验证码",
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(28),
|
|
color: const Color.fromRGBO(117, 98, 249, 1)
|
|
),
|
|
),
|
|
),
|
|
border: const OutlineInputBorder(
|
|
borderSide: BorderSide.none, // 这将移除边框 // 可选:设置圆角
|
|
),
|
|
// 如果你希望聚焦时和未聚焦时都没有边框,也可以设置 focusedBorder 和 enabledBorder
|
|
focusedBorder: const OutlineInputBorder(
|
|
borderSide: BorderSide.none,
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
),
|
|
enabledBorder: const OutlineInputBorder(
|
|
borderSide: BorderSide.none,
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
),
|
|
),
|
|
onChanged: (value){
|
|
code = value;
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
)),
|
|
SizedBox(height: 12.w,),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
RoundCheckBox(
|
|
onTap: toggleChecked,
|
|
isChecked: checked,
|
|
size: ScreenUtil().setWidth(20),
|
|
checkedColor: const Color.fromRGBO(0, 115, 254, 1),
|
|
checkedWidget: Icon(
|
|
Icons.check,
|
|
color: const Color.fromRGBO(255, 255, 255, 1),
|
|
size: ScreenUtil().setWidth(10),
|
|
),
|
|
),
|
|
Container(
|
|
margin: EdgeInsets.only(left: ScreenUtil().setWidth(5)),
|
|
child: RichText(
|
|
text: TextSpan(
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(22),
|
|
),
|
|
children: [
|
|
TextSpan(
|
|
text: "我已阅读并同意动我",
|
|
style: const TextStyle(
|
|
color: Color.fromRGBO(189, 189, 189, 1)
|
|
)
|
|
),
|
|
TextSpan(
|
|
text: "《用户协议》",
|
|
style: const TextStyle(
|
|
color: Color.fromRGBO(189, 189, 189, 1)
|
|
),
|
|
|
|
recognizer: TapGestureRecognizer()..onTap = () {
|
|
context.pushNamed(RouteNames.webview, queryParameters: {"url": Uri.encodeComponent("http://www.baidu.com")});
|
|
},
|
|
),
|
|
TextSpan(
|
|
text: "和",
|
|
style: const TextStyle(
|
|
color: Color.fromRGBO(189, 189, 189, 1)
|
|
)
|
|
),
|
|
TextSpan(
|
|
text: "《隐私政策》",
|
|
style: const TextStyle(
|
|
color: Color.fromRGBO(189, 189, 189, 1)
|
|
),
|
|
|
|
recognizer: TapGestureRecognizer()..onTap = () {
|
|
context.pushNamed(RouteNames.webview, queryParameters: {"url": Uri.encodeComponent("http://www.baidu.com")});
|
|
},
|
|
),
|
|
]
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
SizedBox(height: 175.w,),
|
|
InkWell(
|
|
onTap: () async {
|
|
context.goNamed(RouteNames.completeInfo);
|
|
return;
|
|
if(phone == ""){
|
|
toast("请输入手机号", context);
|
|
return;
|
|
}
|
|
if(code == ""){
|
|
toast("请输入6位数字验证码", context);
|
|
return;
|
|
}
|
|
if(!checked) {
|
|
toast("请阅读并同意用户协议", context);
|
|
return;
|
|
}
|
|
var res = await Api().$login({
|
|
"account":phone,
|
|
"accountType":2,
|
|
"captcha":code
|
|
});
|
|
if(res["code"] == 200){
|
|
// toast("登录成功", context);
|
|
// await Storage().removeStorage("token");
|
|
// await Storage().setStorage("token", res["data"]["token"]);
|
|
} else {
|
|
toast(res["msg"], context);
|
|
}
|
|
|
|
context.goNamed(RouteNames.completeInfo);
|
|
},
|
|
child: Container(
|
|
width: 654.w,
|
|
height: 105.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(105.w)),
|
|
color: const Color.fromRGBO(217, 217, 217, 1),
|
|
gradient: phone != "" && code != "" ? LinearGradient(
|
|
begin: Alignment.centerLeft,
|
|
end: Alignment.centerRight,
|
|
colors: [
|
|
Color.fromRGBO(131, 89, 255, 1), // 起始颜色
|
|
Color.fromRGBO(61, 138, 224, 1), // 结束颜色
|
|
],
|
|
) : null,
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"注册并登录",
|
|
style: TextStyle(
|
|
fontSize: 35.w,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w500
|
|
),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
class InputItem extends StatelessWidget {
|
|
final Widget child;
|
|
const InputItem({super.key, required this.child});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
margin: EdgeInsets.only(bottom: ScreenUtil().setWidth(27)),
|
|
padding: EdgeInsets.symmetric(horizontal: ScreenUtil().setWidth(24)),
|
|
child: Container(
|
|
height: ScreenUtil().setWidth(88),
|
|
decoration: BoxDecoration(
|
|
border: Border.all(width: 1, color: const Color.fromRGBO(230, 230, 230, 1)),
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w))
|
|
),
|
|
child: Center(
|
|
child: child,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|