更新验证码选择区号

This commit is contained in:
wyf
2025-12-10 15:22:17 +08:00
parent 793dddfba8
commit fb5a17830b
19 changed files with 671 additions and 438 deletions

View File

@@ -21,6 +21,8 @@ import 'package:vbvs_app/controller/time/countdown_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/controller/weather/weather_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/person/select_time.dart';
import 'dart:ui' as ui;
class OtherLoginPage extends StatefulWidget {
const OtherLoginPage({super.key});
@@ -106,7 +108,7 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
// 登录成功移出网络检查监听
Checknetwork.subscription?.cancel();
if (Get.currentRoute != '/mianPageBottomChange') {
Get.offAndToNamed("/mianPageBottomChange");
Get.offAndToNamed("/mianPageBottomChange");
}
}
// TODO 操作全部跳转页面前成功以后移除监听,防止重复监听,其他方式登录成功也需要移出监听
@@ -122,7 +124,6 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
}
}
});
}
@override
@@ -255,6 +256,22 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 95.rpx, 0, 0),
child: Container(
width: double.infinity,
height: bodysize.maxHeight * 0.056,
constraints: BoxConstraints(
minHeight: 90.rpx,
),
// ✅ 在这里塞进去
child: _buildLoginMethodSelector(bodysize),
),
),
),
Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 26.rpx, 0, 0),
child: Container(
width: double.infinity,
height: bodysize.maxHeight * 0.056,
@@ -279,128 +296,161 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
26.rpx, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
InkWell(
onTap: () async {},
child: Container(
alignment: Alignment.center,
// constraints: BoxConstraints(
// minWidth: 150.rpx,
// ),
child: Text(
"+86",
style: TextStyle(
fontFamily: 'Readex Pro',
Obx(() {
if (userInfoController
.select_login_method.value ==
2) {
return Container();
}
return Padding(
padding:
EdgeInsetsDirectional.fromSTEB(
26.rpx, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
InkWell(
onTap: () async {
await showCountryCodePickerDialog(
context,
initialCode: userInfoController
.select_country_code
.value, // ✅ 来自 controller
onConfirm: (String code) {
print("选中的区号:$code");
userInfoController
.select_country_code
.value = code;
userInfoController
.updateAll();
// setState / controller.update
},
title: "选择区号".tr,
);
},
child: Obx(() {
return Container(
width: 80.rpx,
alignment: Alignment.center,
child: Text(
"${userInfoController.select_country_code.value}",
style: TextStyle(
fontFamily:
'Readex Pro',
color: themeController
.currentColor.sc2,
fontSize: AppConstants()
.middler_text_fontSize,
),
),
);
}),
),
SizedBox(
height: 30.rpx,
child: VerticalDivider(
thickness: 2.rpx,
color: themeController
.currentColor.sc4,
),
),
].divide(SizedBox(width: 10.rpx)),
),
);
}),
Obx(() {
return Expanded(
child: Container(
child: Align(
alignment:
AlignmentDirectional(-1, 0),
child: TextFormField(
onChanged: (value) {
loginController.model.phone =
value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
hintText: userInfoController
.select_login_method
.value ==
2
? '输入邮箱'.tr
: "输入手机号码".tr,
hintStyle: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
fontSize: AppConstants()
.middler_text_fontSize,
letterSpacing: 0,
),
enabledBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
errorBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedErrorBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
filled: false,
fillColor: Colors.white,
),
),
),
SizedBox(
height: 30.rpx,
child: VerticalDivider(
thickness: 2.rpx,
color: themeController
.currentColor.sc4,
),
),
].divide(SizedBox(width: 10.rpx)),
),
),
Expanded(
child: Container(
child: Align(
alignment:
AlignmentDirectional(-1, 0),
child: TextFormField(
onChanged: (value) {
loginController.model.phone =
value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
hintText: '其他手机登录页.输入内容'.tr,
hintStyle: TextStyle(
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
.currentColor.sc3,
),
enabledBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedErrorBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
filled: false,
fillColor: Colors.white,
),
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
cursorColor: themeController
.currentColor.sc3,
// validator: _model
// .textControllerValidator
// .asValidator(context),
),
cursorColor: themeController
.currentColor.sc3,
// validator: _model
// .textControllerValidator
// .asValidator(context),
),
),
),
),
);
}),
],
),
),
@@ -629,7 +679,6 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
),
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 26.rpx, 0, 0),
@@ -1071,4 +1120,179 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
)),
);
}
Widget _buildLoginMethodSelector(BoxConstraints bodysize) {
final userInfoController = Get.find<UserInfoController>();
// 文本样式
final textStyle = TextStyle(
fontSize: 28.rpx,
fontWeight: FontWeight.w600,
);
// 两个 tab 之间的间距
final double gap = 60.rpx;
// 左侧内边距
final double leftPadding = 40.rpx;
// 下划线和文字的垂直间距
final double underlineGap = 20.rpx;
// 下划线高度
final double underlineHeight = 6.rpx;
return Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
child: Container(
width: double.infinity,
height: bodysize.maxHeight * 0.056,
constraints: const BoxConstraints(minHeight: 90),
child: Obx(() {
final selectedIndex =
userInfoController.select_login_method.value; // 1 or 2
// --- 计算文字宽高 ---
final tp1 = TextPainter(
text: TextSpan(text: '手机号登录'.tr, style: textStyle),
textDirection: ui.TextDirection.ltr,
)..layout();
final tp2 = TextPainter(
text: TextSpan(text: '邮箱登录'.tr, style: textStyle),
textDirection: ui.TextDirection.ltr,
)..layout();
final double w1 = tp1.width;
final double w2 = tp2.width;
final double textHeight = tp1.height;
// --- 每个 tab 的起始 X ---
final double startX1 = leftPadding;
final double startX2 = leftPadding + w1 + gap;
// --- 下划线宽度(和文字等宽)---
final double underlineWidth1 = w1;
final double underlineWidth2 = w2;
// --- 下划线 left始终居中文字---
final double underlineLeft1 = startX1;
final double underlineLeft2 = startX2;
final double underlineLeft =
selectedIndex == 1 ? underlineLeft1 : underlineLeft2;
final double underlineWidth =
selectedIndex == 1 ? underlineWidth1 : underlineWidth2;
return Stack(
clipBehavior: Clip.none,
children: [
// ===== 文字行 =====
Positioned(
left: 0,
top: 0,
child: Row(
children: [
SizedBox(width: leftPadding),
// 手机号登录
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () =>
userInfoController.select_login_method.value = 1,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 6.rpx),
child: Obx(() {
final selected =
userInfoController.select_login_method.value ==
1;
return Text(
'手机号登录'.tr,
style: textStyle.copyWith(
color: selected
? themeController.currentColor.sc2
: themeController.currentColor.sc4,
),
);
}),
),
),
SizedBox(width: gap),
// 邮箱登录
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () =>
userInfoController.select_login_method.value = 2,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 6.rpx),
child: Obx(() {
final selected =
userInfoController.select_login_method.value ==
2;
return Text(
'邮箱登录'.tr,
style: textStyle.copyWith(
color: selected
? themeController.currentColor.sc2
: themeController.currentColor.sc4,
),
);
}),
),
),
],
),
),
// ===== 下划线(文字正下方) =====
AnimatedPositioned(
duration: const Duration(milliseconds: 280),
curve: Curves.easeOutCubic,
left: underlineLeft,
top: textHeight + underlineGap,
child: AnimatedContainer(
duration: const Duration(milliseconds: 280),
curve: Curves.easeOutCubic,
width: underlineWidth,
height: underlineHeight,
decoration: BoxDecoration(
color: themeController.currentColor.sc2,
borderRadius: BorderRadius.circular(underlineHeight / 2),
),
),
),
],
);
}),
),
),
);
}
Widget _buildLoginTab({
required String text,
required int index,
required UserInfoController controller,
}) {
return GestureDetector(
onTap: () {
controller.select_login_method.value = index;
},
child: Obx(() {
final selected = controller.select_login_method.value == index;
return Text(
text,
style: TextStyle(
fontSize: 28.rpx,
fontWeight: FontWeight.w600,
color: selected
? themeController.currentColor.sc2
: themeController.currentColor.sc4,
),
);
}),
);
}
}