更新验证码选择区号
This commit is contained in:
@@ -614,5 +614,14 @@
|
|||||||
"详情": "Detail",
|
"详情": "Detail",
|
||||||
"更新成功": "Update Success",
|
"更新成功": "Update Success",
|
||||||
"原邮箱号": "Original Email",
|
"原邮箱号": "Original Email",
|
||||||
"请输入邮箱号":"Please enter email"
|
"请输入邮箱号": "Please enter email",
|
||||||
|
"中国": "China",
|
||||||
|
"香港": "Hong Kong",
|
||||||
|
"选择区号": "Select Country Code",
|
||||||
|
"输入邮箱号码": " Enter Email",
|
||||||
|
"通知设置": "Notification Settings",
|
||||||
|
"注意!关闭后将无法接受任何消息": "Note! After closing, you will not receive any messages",
|
||||||
|
"手机号登录": "Phone Login",
|
||||||
|
"邮箱登录": "Email Login",
|
||||||
|
"输入邮箱": "Enter Email"
|
||||||
}
|
}
|
||||||
@@ -615,5 +615,16 @@
|
|||||||
"原邮箱号": "原邮箱号",
|
"原邮箱号": "原邮箱号",
|
||||||
"用户拒绝授权": "用户拒绝授权",
|
"用户拒绝授权": "用户拒绝授权",
|
||||||
"用户取消授权": "用户取消授权",
|
"用户取消授权": "用户取消授权",
|
||||||
"请输入邮箱号":"请输入邮箱号"
|
"请输入邮箱号":"请输入邮箱号",
|
||||||
|
"中国":"中国",
|
||||||
|
"香港":"香港",
|
||||||
|
"选择区号":"选择区号",
|
||||||
|
"输入邮箱号码":"输入邮箱号码",
|
||||||
|
"通知设置":"通知设置",
|
||||||
|
"注意!关闭后将无法接受任何消息":"注意!关闭后将无法接受任何消息",
|
||||||
|
"手机号登录":"手机号登录",
|
||||||
|
"邮箱登录":"邮箱登录",
|
||||||
|
"输入邮箱":"输入邮箱"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -612,5 +612,14 @@
|
|||||||
"原邮箱号": "原郵箱號",
|
"原邮箱号": "原郵箱號",
|
||||||
"用户拒绝授权": "用戶拒絕授權",
|
"用户拒绝授权": "用戶拒絕授權",
|
||||||
"用户取消授权": "用戶取消授權",
|
"用户取消授权": "用戶取消授權",
|
||||||
"请输入邮箱号":"請輸入郵箱號"
|
"请输入邮箱号": "請輸入郵箱號",
|
||||||
|
"中国": "中國",
|
||||||
|
"香港": "香港",
|
||||||
|
"选择区号": "选择區號",
|
||||||
|
"输入邮箱号码": "輸入郵箱號碼",
|
||||||
|
"通知设置": "通知設置",
|
||||||
|
"注意!关闭后将无法接受任何消息": "注意!關閉將無法接受任何消息",
|
||||||
|
"手机号登录": "手機登入",
|
||||||
|
"邮箱登录": "電子郵件登入",
|
||||||
|
"输入邮箱": "輸入電子郵件"
|
||||||
}
|
}
|
||||||
@@ -226,6 +226,11 @@ class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
|
|||||||
if (res.code == HttpStatusCodes.ok) {
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
// bindDeviceNum.value = res.total!;
|
// bindDeviceNum.value = res.total!;
|
||||||
deviceList.value = res.data!;
|
deviceList.value = res.data!;
|
||||||
|
deviceList.value.sort((a, b) {
|
||||||
|
final int at = a['create_time'] ?? 0;
|
||||||
|
final int bt = b['create_time'] ?? 0;
|
||||||
|
return bt.compareTo(at);
|
||||||
|
});
|
||||||
updateAll();
|
updateAll();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,8 +164,10 @@ class LoginController extends GetControllerEx<LoginModel> {
|
|||||||
queryUrl += "?lang=$language";
|
queryUrl += "?lang=$language";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
var data = {
|
var data = {
|
||||||
"userName": model.phone,
|
"userName": model.phone,
|
||||||
|
"ccode":userInfoController.select_country_code.value,
|
||||||
};
|
};
|
||||||
if (AppConstants().ent_type == APPPackageType.HUANSHUI.code) {
|
if (AppConstants().ent_type == APPPackageType.HUANSHUI.code) {
|
||||||
data['code'] = "hzhskj";
|
data['code'] = "hzhskj";
|
||||||
@@ -232,9 +234,11 @@ class LoginController extends GetControllerEx<LoginModel> {
|
|||||||
queryUrl += "?lang=$language";
|
queryUrl += "?lang=$language";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
var data = {
|
var data = {
|
||||||
"userName": model.updatePhone,
|
"userName": model.updatePhone,
|
||||||
"type": 5,
|
"type": 5,
|
||||||
|
"ccode":userInfoController.select_country_code.value,
|
||||||
};
|
};
|
||||||
if (AppConstants().ent_type == APPPackageType.HUANSHUI.code) {
|
if (AppConstants().ent_type == APPPackageType.HUANSHUI.code) {
|
||||||
data['code'] = "hzhskj";
|
data['code'] = "hzhskj";
|
||||||
|
|||||||
@@ -74,6 +74,20 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
|
|||||||
FluwxCancelable? fluwxCancelable;
|
FluwxCancelable? fluwxCancelable;
|
||||||
final Fluwx fluwx = Fluwx();
|
final Fluwx fluwx = Fluwx();
|
||||||
|
|
||||||
|
List<Map<String, String>> country_code = [
|
||||||
|
{
|
||||||
|
"name": "中国",
|
||||||
|
"id": "+86",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "香港",
|
||||||
|
"id": "+852",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
RxString select_country_code = "+86".obs;
|
||||||
|
RxInt select_login_method = 1.obs;//1手机 2邮箱
|
||||||
|
|
||||||
Future<ApiResponse> uploadImg() async {
|
Future<ApiResponse> uploadImg() async {
|
||||||
EasyDartModule.logger.info("请求上传图片");
|
EasyDartModule.logger.info("请求上传图片");
|
||||||
DailyLogUtils.writeLog("请求上传图片");
|
DailyLogUtils.writeLog("请求上传图片");
|
||||||
|
|||||||
@@ -207,6 +207,15 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
_pageController.animateToPage(index,
|
_pageController.animateToPage(index,
|
||||||
duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
|
duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
|
||||||
BodyDeviceController deviceController = Get.find();
|
BodyDeviceController deviceController = Get.find();
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
deviceController.model.type = 1;
|
||||||
|
homeController.model.type = 1;
|
||||||
|
} else if (index == 1) {
|
||||||
|
deviceController.model.type = 2;
|
||||||
|
homeController.model.type = 2;
|
||||||
|
}
|
||||||
|
deviceController.updateAll();
|
||||||
await deviceController.getDeviceList();
|
await deviceController.getDeviceList();
|
||||||
await deviceController.getSleepReport();
|
await deviceController.getSleepReport();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import 'package:vbvs_app/enum/BindType.dart';
|
|||||||
import 'package:vbvs_app/model/api_response.dart';
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
||||||
|
|
||||||
|
|
||||||
class DeviceDataComponentWidget extends StatefulWidget {
|
class DeviceDataComponentWidget extends StatefulWidget {
|
||||||
final Map<String, dynamic> device;
|
final Map<String, dynamic> device;
|
||||||
|
|
||||||
|
|||||||
@@ -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/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/controller/weather/weather_controller.dart';
|
import 'package:vbvs_app/controller/weather/weather_controller.dart';
|
||||||
import 'package:vbvs_app/model/api_response.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 {
|
class OtherLoginPage extends StatefulWidget {
|
||||||
const OtherLoginPage({super.key});
|
const OtherLoginPage({super.key});
|
||||||
@@ -106,7 +108,7 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
// 登录成功移出网络检查监听
|
// 登录成功移出网络检查监听
|
||||||
Checknetwork.subscription?.cancel();
|
Checknetwork.subscription?.cancel();
|
||||||
if (Get.currentRoute != '/mianPageBottomChange') {
|
if (Get.currentRoute != '/mianPageBottomChange') {
|
||||||
Get.offAndToNamed("/mianPageBottomChange");
|
Get.offAndToNamed("/mianPageBottomChange");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO 操作全部跳转页面前成功以后移除监听,防止重复监听,其他方式登录成功也需要移出监听
|
// TODO 操作全部跳转页面前成功以后移除监听,防止重复监听,其他方式登录成功也需要移出监听
|
||||||
@@ -122,7 +124,6 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -255,6 +256,22 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
0, 95.rpx, 0, 0),
|
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(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: bodysize.maxHeight * 0.056,
|
height: bodysize.maxHeight * 0.056,
|
||||||
@@ -279,128 +296,161 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceBetween,
|
MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Obx(() {
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
if (userInfoController
|
||||||
26.rpx, 0, 0, 0),
|
.select_login_method.value ==
|
||||||
child: Row(
|
2) {
|
||||||
mainAxisSize: MainAxisSize.max,
|
return Container();
|
||||||
children: [
|
}
|
||||||
InkWell(
|
return Padding(
|
||||||
onTap: () async {},
|
padding:
|
||||||
child: Container(
|
EdgeInsetsDirectional.fromSTEB(
|
||||||
alignment: Alignment.center,
|
26.rpx, 0, 0, 0),
|
||||||
// constraints: BoxConstraints(
|
child: Row(
|
||||||
// minWidth: 150.rpx,
|
mainAxisSize: MainAxisSize.max,
|
||||||
// ),
|
children: [
|
||||||
child: Text(
|
InkWell(
|
||||||
"+86",
|
onTap: () async {
|
||||||
style: TextStyle(
|
await showCountryCodePickerDialog(
|
||||||
fontFamily: 'Readex Pro',
|
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
|
color: themeController
|
||||||
.currentColor.sc4,
|
.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,
|
||||||
),
|
),
|
||||||
),
|
style: TextStyle(
|
||||||
),
|
|
||||||
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(
|
|
||||||
fontFamily: 'Inter',
|
fontFamily: 'Inter',
|
||||||
fontSize: 26.rpx,
|
fontSize: 26.rpx,
|
||||||
letterSpacing: 0.0,
|
letterSpacing: 0.0,
|
||||||
color: themeController
|
color: themeController
|
||||||
.currentColor.sc4,
|
.currentColor.sc3,
|
||||||
),
|
),
|
||||||
enabledBorder:
|
cursorColor: themeController
|
||||||
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
|
|
||||||
.currentColor.sc3,
|
.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(
|
||||||
padding:
|
padding:
|
||||||
EdgeInsetsDirectional.fromSTEB(0, 26.rpx, 0, 0),
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,14 @@ import 'package:vbvs_app/controller/time/countdown_controller.dart';
|
|||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/model/api_response.dart';
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/user/controller/bind_tel_controller.dart';
|
import 'package:vbvs_app/pages/mh_page/user/controller/bind_tel_controller.dart';
|
||||||
import 'package:vbvs_app/pages/mh_page/user/controller/mht_login_controller.dart';
|
import 'package:vbvs_app/pages/person/select_time.dart';
|
||||||
|
|
||||||
class THBindTelWidget extends GetView<AuthBindTelController> {
|
class THBindTelWidget extends GetView<AuthBindTelController> {
|
||||||
BoxConstraints? bodysize;
|
BoxConstraints? bodysize;
|
||||||
Map img;
|
Map img;
|
||||||
|
|
||||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
|
||||||
THBindTelWidget({super.key, required this.img});
|
THBindTelWidget({super.key, required this.img});
|
||||||
|
|
||||||
@@ -184,24 +185,40 @@ class THBindTelWidget extends GetView<AuthBindTelController> {
|
|||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {},
|
onTap: () async {
|
||||||
child: Container(
|
await showCountryCodePickerDialog(
|
||||||
alignment: Alignment.center,
|
context,
|
||||||
// constraints: BoxConstraints(
|
initialCode: userInfoController
|
||||||
// minWidth: 150.rpx,
|
.select_country_code
|
||||||
// ),
|
.value, // ✅ 来自 controller
|
||||||
child: Text(
|
onConfirm: (String code) {
|
||||||
"+86",
|
print("选中的区号:$code");
|
||||||
style: TextStyle(
|
userInfoController
|
||||||
fontFamily: 'Readex Pro',
|
.select_country_code
|
||||||
color: themeController
|
.value = code;
|
||||||
.currentColor.sc4,
|
userInfoController
|
||||||
fontSize: AppConstants()
|
.updateAll();
|
||||||
.middler_text_fontSize,
|
// setState / controller.update
|
||||||
letterSpacing: 0,
|
},
|
||||||
|
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(
|
SizedBox(
|
||||||
height: 30.rpx,
|
height: 30.rpx,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
|||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/common/util/requestWithLog.dart';
|
import 'package:vbvs_app/common/util/requestWithLog.dart';
|
||||||
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/model/api_response.dart';
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
import 'package:vbvs_app/model/user_data.dart';
|
import 'package:vbvs_app/model/user_data.dart';
|
||||||
|
|
||||||
@@ -112,9 +113,11 @@ class AuthBindTelController extends GetControllerEx<AuthBindTelModel> {
|
|||||||
String serviceName = ServiceConstant.server_service;
|
String serviceName = ServiceConstant.server_service;
|
||||||
String serviceApi = ServiceConstant.send_code;
|
String serviceApi = ServiceConstant.send_code;
|
||||||
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
var data = {
|
var data = {
|
||||||
"userName": model.phone!,
|
"userName": model.phone!,
|
||||||
'type': 5,
|
'type': 5,
|
||||||
|
"ccode":userInfoController.select_country_code.value,
|
||||||
};
|
};
|
||||||
if (img != null) {
|
if (img != null) {
|
||||||
if (img!['code'] != null) {
|
if (img!['code'] != null) {
|
||||||
|
|||||||
@@ -143,8 +143,8 @@ class BindTelWidget extends GetView<AuthBindTelController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
0, 16.rpx, 0, 0),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: bodysize!.maxWidth,
|
width: bodysize!.maxWidth,
|
||||||
height: bodysize!.maxHeight * 0.06,
|
height: bodysize!.maxHeight * 0.06,
|
||||||
@@ -469,8 +469,10 @@ class BindTelWidget extends GetView<AuthBindTelController> {
|
|||||||
text: message);
|
text: message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (authBindTelController.model.code == null ||
|
if (authBindTelController.model.code ==
|
||||||
authBindTelController.model.code!.isEmpty) {
|
null ||
|
||||||
|
authBindTelController
|
||||||
|
.model.code!.isEmpty) {
|
||||||
message = "请输入验证码".tr;
|
message = "请输入验证码".tr;
|
||||||
TopSlideNotification.show(context,
|
TopSlideNotification.show(context,
|
||||||
text: message);
|
text: message);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'package:vbvs_app/common/util/FitTool.dart';
|
|||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/language/AppLanguage.dart';
|
import 'package:vbvs_app/language/AppLanguage.dart';
|
||||||
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
||||||
|
|
||||||
@@ -1154,3 +1155,154 @@ Future<void> showIntervalPickerDialog(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future<void> showCountryCodePickerDialog(
|
||||||
|
BuildContext context, {
|
||||||
|
required String initialCode, // 初始区号,如 "+86"
|
||||||
|
required Function(String selectedCode) onConfirm,
|
||||||
|
String title = "选择区号",
|
||||||
|
}) async {
|
||||||
|
UserInfoController controller = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
|
||||||
|
final List<Map<String, String>> list = controller.country_code;
|
||||||
|
|
||||||
|
int selectedIndex =
|
||||||
|
list.indexWhere((e) => e["id"] == initialCode);
|
||||||
|
if (selectedIndex < 0) selectedIndex = 0;
|
||||||
|
|
||||||
|
final RxInt tempIndex = RxInt(selectedIndex);
|
||||||
|
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: true,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Dialog(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
insetPadding: EdgeInsets.zero,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.zero,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.fromLTRB(0, 0, 0, 90.rpx),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
/// 顶部栏
|
||||||
|
Container(
|
||||||
|
padding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 30.rpx),
|
||||||
|
color: themeController.currentColor.sc5,
|
||||||
|
height: 80.rpx,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.transparent,
|
||||||
|
onTap: Get.back,
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 110.rpx,
|
||||||
|
height: 60.rpx,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"取消".tr,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
title.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color:
|
||||||
|
themeController.currentColor.sc3,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClickableContainer(
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.transparent,
|
||||||
|
onTap: () {
|
||||||
|
onConfirm(
|
||||||
|
list[tempIndex.value]["id"]!);
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
|
width: 110.rpx,
|
||||||
|
height: 60.rpx,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"确定".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 20.rpx),
|
||||||
|
|
||||||
|
/// Picker
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
height: 90.rpx,
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 95.rpx),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc2,
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
16.rpx),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 240.rpx,
|
||||||
|
child: getOnePickers(
|
||||||
|
context,
|
||||||
|
list
|
||||||
|
.map((e) =>
|
||||||
|
"${e['name']}".tr+"(${e['id']})")
|
||||||
|
.toList(),
|
||||||
|
tempIndex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:vbvs_app/common/util/FitTool.dart';
|
|||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/common/util/requestWithLog.dart';
|
import 'package:vbvs_app/common/util/requestWithLog.dart';
|
||||||
import 'package:vbvs_app/component/base/GradientSwitch.dart';
|
import 'package:vbvs_app/component/base/GradientSwitch.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/NewTopSlideNotification.dart';
|
||||||
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
import 'package:vbvs_app/controller/message/common_message_setting_controller.dart';
|
import 'package:vbvs_app/controller/message/common_message_setting_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
@@ -204,6 +205,14 @@ class _CommonMessageSettingPageState extends State<CommonMessageSettingPage> {
|
|||||||
? true
|
? true
|
||||||
: false,
|
: false,
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
|
if (val == false) {
|
||||||
|
NewTopSlideNotification.show(
|
||||||
|
text: "注意!关闭后将无法接受任何消息".tr,
|
||||||
|
textColor: themeController
|
||||||
|
.currentColor.sc9,
|
||||||
|
duration: Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
}
|
||||||
String serviceAddress =
|
String serviceAddress =
|
||||||
ServiceConstant.service_address;
|
ServiceConstant.service_address;
|
||||||
String serviceName =
|
String serviceName =
|
||||||
|
|||||||
@@ -1,280 +1,3 @@
|
|||||||
// import 'dart:ui' as ui;
|
|
||||||
// import 'package:flutter/material.dart';
|
|
||||||
// import 'package:flutterflow_ui/flutterflow_ui.dart';
|
|
||||||
// import 'package:vbvs_app/common/util/FitTool.dart';
|
|
||||||
// import 'package:vbvs_app/common/util/MyUtils.dart';
|
|
||||||
// import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
// class SnoreChartContainer extends StatelessWidget {
|
|
||||||
// final List<dynamic> snoreValues;
|
|
||||||
// final List<dynamic> barData;
|
|
||||||
// final List<dynamic> showLabel;
|
|
||||||
// final int startTime;
|
|
||||||
// final int endTime;
|
|
||||||
|
|
||||||
// const SnoreChartContainer({
|
|
||||||
// required this.snoreValues,
|
|
||||||
// required this.barData,
|
|
||||||
// required this.showLabel,
|
|
||||||
// required this.startTime,
|
|
||||||
// required this.endTime,
|
|
||||||
// super.key,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// return Column(
|
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
// children: [
|
|
||||||
// SnoreBarOverlay(
|
|
||||||
// barData: barData,
|
|
||||||
// showLabel: showLabel,
|
|
||||||
// startTime: startTime,
|
|
||||||
// endTime: endTime,
|
|
||||||
// ),
|
|
||||||
// Container(height: 32.rpx),
|
|
||||||
// Container(
|
|
||||||
// height: 23.rpx,
|
|
||||||
// child: SnoreWaveform(
|
|
||||||
// snoreValues: snoreValues,
|
|
||||||
// startTime: startTime,
|
|
||||||
// endTime: endTime,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class SnoreBarOverlay extends StatelessWidget {
|
|
||||||
// final List<dynamic> barData;
|
|
||||||
// final List<dynamic> showLabel; // ✅ 加入
|
|
||||||
// final int startTime;
|
|
||||||
// final int endTime;
|
|
||||||
|
|
||||||
// const SnoreBarOverlay({
|
|
||||||
// required this.barData,
|
|
||||||
// required this.showLabel, // ✅ 加入
|
|
||||||
// required this.startTime,
|
|
||||||
// required this.endTime,
|
|
||||||
// super.key,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// const double barHeight = 50;
|
|
||||||
// return SizedBox(
|
|
||||||
// height: barHeight,
|
|
||||||
// child: CustomPaint(
|
|
||||||
// size: Size(double.infinity, barHeight),
|
|
||||||
// painter: SnoreBarPainter(
|
|
||||||
// barData: barData,
|
|
||||||
// showLabel: showLabel, // ✅ 加入
|
|
||||||
// startTime: startTime,
|
|
||||||
// endTime: endTime,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class SnoreBarPainter extends CustomPainter {
|
|
||||||
// final List<dynamic> barData;
|
|
||||||
// final List<dynamic> showLabel; // ✅ 加入
|
|
||||||
// final int startTime;
|
|
||||||
// final int endTime;
|
|
||||||
|
|
||||||
// SnoreBarPainter({
|
|
||||||
// required this.barData,
|
|
||||||
// required this.showLabel, // ✅ 加入
|
|
||||||
// required this.startTime,
|
|
||||||
// required this.endTime,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// void paint(Canvas canvas, Size size) {
|
|
||||||
// final double width = size.width;
|
|
||||||
// final double height = size.height;
|
|
||||||
// final double pixelPerMs = width / (endTime - startTime);
|
|
||||||
|
|
||||||
// for (var item in barData) {
|
|
||||||
// final int st = item['st'];
|
|
||||||
// final int et = item['et'];
|
|
||||||
// final int type = item['type'];
|
|
||||||
|
|
||||||
// // 查找匹配的颜色
|
|
||||||
// final match = showLabel.firstWhere(
|
|
||||||
// (e) => e['type'] == type,
|
|
||||||
// orElse: () => null,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Color barColor = Colors.transparent;
|
|
||||||
// if (match != null) {
|
|
||||||
// final dynamic colorStr = match['color'];
|
|
||||||
// if (colorStr != null && colorStr.toString().isNotEmpty) {
|
|
||||||
// barColor = stringToColor(colorStr);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// final Paint barPaint = Paint()
|
|
||||||
// ..color = barColor
|
|
||||||
// ..style = PaintingStyle.fill;
|
|
||||||
|
|
||||||
// final double leftX = (st - startTime) * pixelPerMs;
|
|
||||||
// final double rightX = (et - startTime) * pixelPerMs;
|
|
||||||
// final double barWidth = rightX - leftX;
|
|
||||||
|
|
||||||
// final double barHeight = (type + 5).toDouble() * 8;
|
|
||||||
// final double top = height - barHeight;
|
|
||||||
|
|
||||||
// final rect = Rect.fromLTWH(leftX, top, barWidth, barHeight);
|
|
||||||
// canvas.drawRect(rect, barPaint);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class SnoreWaveform extends StatelessWidget {
|
|
||||||
// final List<dynamic> snoreValues;
|
|
||||||
// final int startTime;
|
|
||||||
// final int endTime;
|
|
||||||
|
|
||||||
// const SnoreWaveform({
|
|
||||||
// required this.snoreValues,
|
|
||||||
// required this.startTime,
|
|
||||||
// required this.endTime,
|
|
||||||
// super.key,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// return SizedBox(
|
|
||||||
// height: 150,
|
|
||||||
// child: CustomPaint(
|
|
||||||
// size: Size(double.infinity, 150),
|
|
||||||
// painter: SnoreWaveformPainter(
|
|
||||||
// snoreValues: snoreValues,
|
|
||||||
// startTime: startTime,
|
|
||||||
// endTime: endTime,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class SnoreWaveformPainter extends CustomPainter {
|
|
||||||
// final List<dynamic> snoreValues;
|
|
||||||
// final int startTime;
|
|
||||||
// final int endTime;
|
|
||||||
|
|
||||||
// SnoreWaveformPainter({
|
|
||||||
// required this.snoreValues,
|
|
||||||
// required this.startTime,
|
|
||||||
// required this.endTime,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// void paint(Canvas canvas, Size size) {
|
|
||||||
// final double width = size.width;
|
|
||||||
// final double height = size.height;
|
|
||||||
// final double centerY = height / 2;
|
|
||||||
// final double totalDuration = (endTime - startTime).toDouble();
|
|
||||||
// final double pixelPerMs = width / totalDuration;
|
|
||||||
|
|
||||||
// final Paint wavePaint = Paint()
|
|
||||||
// ..color = stringToColor("#8E7DEF").withOpacity(0.8)
|
|
||||||
// ..strokeWidth = 1.5
|
|
||||||
// ..style = PaintingStyle.stroke;
|
|
||||||
|
|
||||||
// final Path upperPath = Path();
|
|
||||||
// final Path lowerPath = Path();
|
|
||||||
|
|
||||||
// // ✅ 获取最大值用于自适应比例
|
|
||||||
// double maxValue = snoreValues.fold<double>(0, (prev, e) {
|
|
||||||
// final value = e["value"]?.toDouble() ?? 0;
|
|
||||||
// return value > prev ? value : prev;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // ✅ 自适应缩放比例,限制波形最大高度为 height * 0.45
|
|
||||||
// final double maxWaveHeight = height * 1;
|
|
||||||
// final double scaleY = maxValue > 0 ? (maxWaveHeight / maxValue) : 1;
|
|
||||||
|
|
||||||
// for (int i = 0; i < snoreValues.length; i++) {
|
|
||||||
// final timestamp = snoreValues[i]["st"];
|
|
||||||
// final value = snoreValues[i]["value"]?.toDouble() ?? 0;
|
|
||||||
|
|
||||||
// final x = (timestamp - startTime) * pixelPerMs;
|
|
||||||
// final y = centerY - value * scaleY;
|
|
||||||
// final yMirror = centerY + value * scaleY;
|
|
||||||
|
|
||||||
// if (i == 0) {
|
|
||||||
// upperPath.moveTo(x, y);
|
|
||||||
// lowerPath.moveTo(x, yMirror);
|
|
||||||
// } else {
|
|
||||||
// upperPath.lineTo(x, y);
|
|
||||||
// lowerPath.lineTo(x, yMirror);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// canvas.drawPath(upperPath, wavePaint);
|
|
||||||
// canvas.drawPath(lowerPath, wavePaint);
|
|
||||||
|
|
||||||
// // ✅ 最后绘制中心线,防止被覆盖
|
|
||||||
// final Paint axisPaint = Paint()
|
|
||||||
// ..color = Colors.grey.withOpacity(0.6)
|
|
||||||
// ..strokeWidth = 0.5;
|
|
||||||
// canvas.drawLine(Offset(0, centerY), Offset(width, centerY), axisPaint);
|
|
||||||
|
|
||||||
// // ✅ 时间刻度绘制
|
|
||||||
// final textPainter = TextPainter(
|
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
// textDirection: ui.TextDirection.ltr,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// final int hourMs = 60 * 60 * 1000;
|
|
||||||
// for (int t = startTime; t < endTime; t += hourMs) {
|
|
||||||
// double x = (t - startTime) * pixelPerMs;
|
|
||||||
|
|
||||||
// DateTime dt = DateTime.fromMillisecondsSinceEpoch(t);
|
|
||||||
// String label = t == startTime
|
|
||||||
// ? DateFormat('HH:mm').format(dt)
|
|
||||||
// : DateFormat('h').format(dt); // 12小时制
|
|
||||||
|
|
||||||
// textPainter.text = TextSpan(
|
|
||||||
// text: label,
|
|
||||||
// style: TextStyle(fontSize: 10, color: Colors.grey),
|
|
||||||
// );
|
|
||||||
// textPainter.layout();
|
|
||||||
// textPainter.paint(
|
|
||||||
// canvas,
|
|
||||||
// Offset(x - textPainter.width / 2, height + 2), // 标签显示在底部
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // ✅ 画终点时间
|
|
||||||
// {
|
|
||||||
// double x = (endTime - startTime) * pixelPerMs;
|
|
||||||
// DateTime dt = DateTime.fromMillisecondsSinceEpoch(endTime);
|
|
||||||
// String label = DateFormat('HH:mm').format(dt);
|
|
||||||
|
|
||||||
// textPainter.text = TextSpan(
|
|
||||||
// text: label,
|
|
||||||
// style: TextStyle(fontSize: 10, color: Colors.grey),
|
|
||||||
// );
|
|
||||||
// textPainter.layout();
|
|
||||||
// textPainter.paint(
|
|
||||||
// canvas,
|
|
||||||
// Offset(x - textPainter.width / 2, height + 2),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
@@ -300,6 +23,11 @@ class SnoreChartContainer extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// barData.add({
|
||||||
|
// "type": 6,
|
||||||
|
// "et": 1765291778963,
|
||||||
|
// "st": 1765289341000,
|
||||||
|
// });
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -378,6 +106,7 @@ class SnoreBarPainter extends CustomPainter {
|
|||||||
final int st = item['st'];
|
final int st = item['st'];
|
||||||
final int et = item['et'];
|
final int et = item['et'];
|
||||||
final int type = item['type'];
|
final int type = item['type'];
|
||||||
|
int heightInit = 1;
|
||||||
|
|
||||||
final match = showLabel.firstWhere(
|
final match = showLabel.firstWhere(
|
||||||
(e) => e['type'] == type,
|
(e) => e['type'] == type,
|
||||||
@@ -400,7 +129,17 @@ class SnoreBarPainter extends CustomPainter {
|
|||||||
final double rightX = (et - startTime) * pixelPerMs;
|
final double rightX = (et - startTime) * pixelPerMs;
|
||||||
final double barWidth = rightX - leftX;
|
final double barWidth = rightX - leftX;
|
||||||
|
|
||||||
final double barHeight = (type + 5).toDouble() * 8;
|
//rem 深睡 中
|
||||||
|
//浅睡 低
|
||||||
|
//其他 高
|
||||||
|
if (type == 1) {
|
||||||
|
heightInit = 1;
|
||||||
|
} else if (type == 2 || type == 6) {
|
||||||
|
heightInit = 2;
|
||||||
|
} else {
|
||||||
|
heightInit = 3;
|
||||||
|
}
|
||||||
|
final double barHeight = (heightInit + 5).toDouble() * 8;
|
||||||
final double top = height - barHeight;
|
final double top = height - barHeight;
|
||||||
|
|
||||||
final rect = Rect.fromLTWH(leftX, top, barWidth, barHeight);
|
final rect = Rect.fromLTWH(leftX, top, barWidth, barHeight);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ Widget DailyDataWidget(
|
|||||||
GlobalKey breatheCardKey,
|
GlobalKey breatheCardKey,
|
||||||
dynamic data,
|
dynamic data,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
List<Widget> _buildSectionList() {
|
List<Widget> _buildSectionList() {
|
||||||
EdgeInsetsDirectional padding =
|
EdgeInsetsDirectional padding =
|
||||||
EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 25.rpx);
|
EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 25.rpx);
|
||||||
@@ -47,7 +46,7 @@ Widget DailyDataWidget(
|
|||||||
sleepReport: sleepReport,
|
sleepReport: sleepReport,
|
||||||
highlightItem: data['itemName'],
|
highlightItem: data['itemName'],
|
||||||
),
|
),
|
||||||
HeartChangeWidget(sleepReport: sleepReport),//心率变异性
|
HeartChangeWidget(sleepReport: sleepReport), //心率变异性
|
||||||
BreatheStandardWidget(sleepReport: sleepReport),
|
BreatheStandardWidget(sleepReport: sleepReport),
|
||||||
BreatheCard(
|
BreatheCard(
|
||||||
key: breatheCardKey,
|
key: breatheCardKey,
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ class _SleepViewWidgetState extends State<SleepViewWidget> {
|
|||||||
int minutes = time['minutes'];
|
int minutes = time['minutes'];
|
||||||
|
|
||||||
List stages = widget.sleepReport['sleepData']['stages'];
|
List stages = widget.sleepReport['sleepData']['stages'];
|
||||||
|
// showLabel.add({
|
||||||
|
// "type": 6,
|
||||||
|
// "name": "rem",
|
||||||
|
// "color": "#FFC0CB",
|
||||||
|
// });
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -95,7 +101,8 @@ class _SleepViewWidgetState extends State<SleepViewWidget> {
|
|||||||
14.rpx, 10.rpx, 14.rpx, 10.rpx), //
|
14.rpx, 10.rpx, 14.rpx, 10.rpx), //
|
||||||
borderRadius: 0.rpx, // 圆形点击区域
|
borderRadius: 0.rpx, // 圆形点击区域
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (AppConstants().ent_type == APPPackageType.MHT.code) {
|
if (AppConstants().ent_type ==
|
||||||
|
APPPackageType.MHT.code) {
|
||||||
showTipDialog(
|
showTipDialog(
|
||||||
context,
|
context,
|
||||||
Container(
|
Container(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
|||||||
import 'package:vbvs_app/pages/mh_page/homepage/controller/mht_home_controller.dart';
|
import 'package:vbvs_app/pages/mh_page/homepage/controller/mht_home_controller.dart';
|
||||||
import 'package:vbvs_app/pages/sleep_report/chart/SnoreWaveform.dart';
|
import 'package:vbvs_app/pages/sleep_report/chart/SnoreWaveform.dart';
|
||||||
|
|
||||||
//睡眠规律性
|
//睡眠规律性 眠花糖
|
||||||
class NewSleepViewWidget extends StatefulWidget {
|
class NewSleepViewWidget extends StatefulWidget {
|
||||||
var sleepReport;
|
var sleepReport;
|
||||||
final VoidCallback? onRefresh; // 添加回调函数
|
final VoidCallback? onRefresh; // 添加回调函数
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import 'package:vbvs_app/controller/time/countdown_controller.dart';
|
|||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/model/api_response.dart';
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
import 'package:vbvs_app/model/user_data.dart';
|
import 'package:vbvs_app/model/user_data.dart';
|
||||||
|
import 'package:vbvs_app/pages/person/select_time.dart';
|
||||||
|
|
||||||
class UpdateUserTelPage extends StatefulWidget {
|
class UpdateUserTelPage extends StatefulWidget {
|
||||||
const UpdateUserTelPage({super.key});
|
const UpdateUserTelPage({super.key});
|
||||||
@@ -231,25 +232,43 @@ class _UpdateUserTelPageState extends State<UpdateUserTelPage> {
|
|||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {},
|
onTap: () async {
|
||||||
child: Container(
|
await showCountryCodePickerDialog(
|
||||||
alignment: Alignment.center,
|
context,
|
||||||
// constraints: BoxConstraints(
|
initialCode: userInfoController
|
||||||
// minWidth: 150.rpx,
|
.select_country_code
|
||||||
// ),
|
.value, // ✅ 来自 controller
|
||||||
child: Text(
|
onConfirm: (String code) {
|
||||||
"+86",
|
print("选中的区号:$code");
|
||||||
style: TextStyle(
|
userInfoController
|
||||||
fontFamily: 'Readex Pro',
|
.select_country_code
|
||||||
color: themeController
|
.value = code;
|
||||||
.currentColor.sc4,
|
userInfoController
|
||||||
fontSize: AppConstants()
|
.updateAll();
|
||||||
.middler_text_fontSize,
|
// setState / controller.update
|
||||||
letterSpacing: 0,
|
},
|
||||||
|
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(
|
SizedBox(
|
||||||
height: 30.rpx,
|
height: 30.rpx,
|
||||||
child: VerticalDivider(
|
child: VerticalDivider(
|
||||||
|
|||||||
Reference in New Issue
Block a user