import 'dart:async'; import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:vbvs_app/common/color/ServiceConstant.dart'; import 'package:vbvs_app/common/color/appConstants.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/common/util/requestWithLog.dart'; import 'package:vbvs_app/component/tool/ClickableContainer.dart'; import 'package:vbvs_app/component/tool/CustomCard.dart'; import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; import 'package:vbvs_app/pages/device_bind/componnet/CalibrationProgressWidget.dart'; import 'package:vbvs_app/pages/mh_page/component/mht_bind_dialog.dart'; import 'package:vbvs_app/pages/mh_page/device/component/mht_device_calibration_controller.dart'; import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart'; class MHTCalibrationAfterPage extends StatefulWidget { var deviceInfo; MHTCalibrationAfterPage({super.key, required this.deviceInfo}); @override State createState() => _MHTCalibrationAfterPageState(); } class _MHTCalibrationAfterPageState extends State { final MHTDeviceCalibrationController deviceCalibrationController = Get.find(); final MHTBlueToothController blueteethBindController = Get.find(); final ValueNotifier progressNotifier = ValueNotifier(0.0); final ValueNotifier failureNotifier = ValueNotifier(false); Timer? _pollingTimer; bool exit = false; final currentCalibrationStep = 0.obs; // 0:离床校准 1:A侧位置校准 2:B侧位置校准 @override void initState() { super.initState(); _resetCalibrationState(); final macA = widget.deviceInfo.value['bind_mac_a']; final macB = widget.deviceInfo.value['bind_mac_b']; deviceCalibrationController.bed_type.value = (macA != null && macA.toString().isNotEmpty && macB != null && macB.toString().isNotEmpty) ? 1 : 0; } @override void dispose() { _pollingTimer?.cancel(); blueteethBindController.cid!.value = ""; super.dispose(); } void _resetCalibrationState() { deviceCalibrationController.process.value = 0; deviceCalibrationController.cd.value = 10000; deviceCalibrationController.flag.value = 0; deviceCalibrationController.bed_calibration.value = 0; deviceCalibrationController.position_calibration.value = 0; blueteethBindController.cid!.value = ""; deviceCalibrationController.motionTips.value = 0; deviceCalibrationController.inBedTips.value = 0; deviceCalibrationController.statusContext.value = ""; currentCalibrationStep.value = 0; deviceCalibrationController.another.value = false; deviceCalibrationController.updateAll(); } @override Widget build(BuildContext context) { return WillPopScope( child: LayoutBuilder( builder: (context, bodySize) => GestureDetector( // onTap: () => FocusScope.of(context).unfocus(),, child: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/new_background.png'), fit: BoxFit.fill, ), ), child: Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( backgroundColor: Colors.transparent, automaticallyImplyLeading: false, iconTheme: IconThemeData(color: themeController.currentColor.sc3), titleSpacing: 0, title: Container( width: double.infinity, height: 180.rpx, child: Stack( alignment: Alignment.center, children: [ Text( '设备校准'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: themeController.currentColor.sc3, letterSpacing: 0, fontSize: 30.rpx, ), ), Positioned( left: 0, child: returnIconButtomAddCallback(() { if (deviceCalibrationController.flag.value != 2) { try { showConfirmDialog( context, Container(), "校准未完成提示".tr, onConfirm: () async { exit = true; _resetCalibrationState(); Get.back(); }, onCancel: () { exit = false; }); } catch (e) { print(e); } } else { exit = true; } if (exit) { Get.back(); } }, enableBack: exit), ), // Positioned( // right: 20.rpx, // child: CustomCard( // borderRadius: 20.rpx, // onTap: () async { // if (deviceCalibrationController.flag.value != 2) { // showConfirmDialog( // context, Container(), "校准未完成提示".tr, // onConfirm: () async { // // Get.offNamed("/bindDeviceSuccess"); // Get.toNamed("/mHTPeopleInfoPage"); // _resetCalibrationState(); // }, onCancel: () {}); // } else { // // Get.offNamed("/bindDeviceSuccess"); // Get.toNamed("/mHTPeopleInfoPage"); // _resetCalibrationState(); // } // }, // colors: AppConstants().mhtButtongradientColors, // gradientDirection: GradientDirection.vertical, // child: Container( // width: 140.rpx, // height: 60.rpx, // alignment: Alignment.center, // padding: EdgeInsetsDirectional.fromSTEB( // 16.rpx, 0, 16.rpx, 0), // child: Text( // '下一步'.tr, // style: TextStyle( // fontFamily: 'Inter Tight', // color: stringToColor("#003058"), // letterSpacing: 0.0, // ), // ), // ), // ), // ), ], ), ), actions: [], centerTitle: false, ), body: SafeArea( top: true, child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 30.rpx, 0.rpx, 30.rpx, 0.rpx), child: Column( mainAxisSize: MainAxisSize.max, children: [ Padding( padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 30.rpx, 0, 0), child: Container( width: double.infinity, decoration: BoxDecoration( color: stringToColor("#003058"), borderRadius: BorderRadius.circular(16.rpx), ), child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 10.rpx, 20.rpx, 34.rpx, 20.rpx), child: Column( mainAxisSize: MainAxisSize.max, children: [ ClickableContainer( backgroundColor: Colors.transparent, highlightColor: themeController.currentColor.sc21, borderRadius: 0, padding: EdgeInsets.symmetric(vertical: 10.rpx), onTap: () {}, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Obx(() { return Visibility( maintainState: true, maintainAnimation: true, maintainSize: true, visible: deviceCalibrationController .process.value == 0, child: SvgPicture.asset( 'assets/img/icon/select_arrow.svg', width: 17.rpx, height: 17.rpx, color: themeController .currentColor.sc9, ), ); }), SizedBox(width: 8.rpx), Text( '离床校准'.tr, style: TextStyle( fontSize: 30.rpx, letterSpacing: 0.0, color: themeController .currentColor.sc3, ), ), ], ), Obx(() { return Text( deviceCalibrationController .bed_calibration.value == 0 ? '未完成'.tr : "已完成".tr, style: TextStyle( fontSize: 26.rpx, letterSpacing: 0.0, color: deviceCalibrationController .bed_calibration .value == 0 ? themeController .currentColor.sc3 : themeController .currentColor.sc1, ), ); }), ], ), ), SizedBox(height: 41.rpx), ClickableContainer( backgroundColor: Colors.transparent, highlightColor: themeController.currentColor.sc21, borderRadius: 0, padding: EdgeInsets.symmetric(vertical: 10.rpx), onTap: () {}, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Obx(() { return Visibility( maintainState: true, maintainAnimation: true, maintainSize: true, visible: deviceCalibrationController .process.value == 1, child: SvgPicture.asset( 'assets/img/icon/select_arrow.svg', width: 17.rpx, height: 17.rpx, color: themeController .currentColor.sc9, ), ); }), SizedBox(width: 8.rpx), Text( '位置校准'.tr, style: TextStyle( fontSize: 30.rpx, letterSpacing: 0.0, color: themeController .currentColor.sc3, ), ), ], ), Obx(() { return Text( deviceCalibrationController .position_calibration .value == 0 ? '未完成'.tr : "已完成".tr, style: TextStyle( fontSize: 26.rpx, letterSpacing: 0.0, color: deviceCalibrationController .position_calibration .value == 0 ? themeController .currentColor.sc3 : themeController .currentColor.sc1, ), ); }), ], ), ), ], ), ), ), ), Obx(() { return Expanded( child: SizedBox( width: double.infinity, child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 100.rpx, 55.rpx, 100.rpx, 0), child: Stack( clipBehavior: Clip.none, children: [ Container( width: MediaQuery.sizeOf(context).width * 0.65, height: MediaQuery.sizeOf(context).height * 0.3, child: Stack( children: [ Image.asset( deviceCalibrationController .process.value == 1 && deviceCalibrationController .position_calibration .value == 1 ? (deviceCalibrationController .bed_type.value == 0 ? "assets/img/single_person.png" : "assets/img/double_person.png") : (deviceCalibrationController .bed_type.value == 0 ? "assets/img/single_pillow.png" : "assets/img/double_pillow.png"), width: double.infinity, height: double.infinity, fit: BoxFit.contain, ), Positioned( top: 23.rpx, left: (MediaQuery.sizeOf(context) .width * 0.65) / 2 - 26.rpx, child: Text( '床头'.tr, style: TextStyle( fontSize: 26.rpx, color: themeController .currentColor.sc4, ), ), ), ], ), ), Obx(() { final double centerLeft = (bodySize.maxWidth * 0.56) / 2; if (deviceCalibrationController .bed_type.value == 0 && deviceCalibrationController .process.value == 1) { return Positioned( top: -40.rpx, left: centerLeft - 0.rpx, child: Container( width: bodySize.maxWidth * 0.087, height: bodySize.maxHeight * 0.06, constraints: BoxConstraints( minWidth: 65.rpx, minHeight: 76.rpx, ), decoration: BoxDecoration( image: DecorationImage( image: AssetImage( 'assets/img/tip_arrow.gif'), fit: BoxFit.cover, ), ), ), ); } if (deviceCalibrationController .bed_type.value == 1 && deviceCalibrationController .process.value == 1 && deviceCalibrationController .another.value == false) { return Positioned( top: -40.rpx, left: (MediaQuery.sizeOf(context).width * 0.65) * 0.22 - 0.rpx, child: Container( width: bodySize.maxWidth * 0.087, height: bodySize.maxHeight * 0.06, constraints: BoxConstraints( minWidth: 65.rpx, minHeight: 76.rpx, ), decoration: BoxDecoration( image: DecorationImage( image: AssetImage( 'assets/img/tip_arrow.gif'), fit: BoxFit.cover, ), ), ), ); } if (deviceCalibrationController .bed_type.value == 1 && deviceCalibrationController .process.value == 1 && deviceCalibrationController .another.value == true) { return Positioned( top: -40.rpx, left: (MediaQuery.sizeOf(context).width * 0.65) * 0.22 * 3 - 0.rpx, child: Container( width: bodySize.maxWidth * 0.087, height: bodySize.maxHeight * 0.06, constraints: BoxConstraints( minWidth: 65.rpx, minHeight: 76.rpx, ), decoration: BoxDecoration( image: DecorationImage( image: AssetImage( 'assets/img/tip_arrow.gif'), fit: BoxFit.cover, ), ), ), ); } return Container(); }), Positioned( top: MediaQuery.sizeOf(context).height * 0.3 + 82.rpx, left: 0, right: 0, child: Obx(() { return Column( children: [ getBodyMontion(), SizedBox(height: 10.rpx), getInBedMontion(), SizedBox(height: 10.rpx), Text( (deviceCalibrationController.cd.value == 10000) ? ((deviceCalibrationController.process.value == 0 && deviceCalibrationController .bed_calibration .value == 1) || (deviceCalibrationController .process .value == 1 && deviceCalibrationController .position_calibration .value == 1) ? (deviceCalibrationController.flag.value == 2 ? '校准完成'.tr : (deviceCalibrationController.bed_type.value == 1 && currentCalibrationStep.value == 2 ? '请开始B侧校准'.tr : "校准失败".tr)) : deviceCalibrationController .statusContext .value .isEmpty == true ? (deviceCalibrationController.process.value == 0 ? '离床校准提示'.tr : (deviceCalibrationController.bed_type.value == 1 && currentCalibrationStep.value == 1 ? '请校准人员到箭头指定一侧平躺 保持静止后点击开始,保持10秒' .tr : '位置校准提示'.tr)) : deviceCalibrationController .statusContext .value) : "${deviceCalibrationController.cd.value}" + "s后超时".tr, style: TextStyle( fontSize: 38.rpx, letterSpacing: 0.0, color: ((deviceCalibrationController .process .value == 0 && deviceCalibrationController .bed_calibration.value == 1) || (deviceCalibrationController .process .value == 1 && deviceCalibrationController .position_calibration .value == 1)) ? (deviceCalibrationController .flag.value == 2 ? themeController .currentColor.sc1 : themeController .currentColor.sc9) : themeController .currentColor.sc9, ), ), ], ); }), ), ], ), ), ), ); }), Obx(() { if (deviceCalibrationController.flag.value == 1) { return Padding( padding: EdgeInsetsDirectional.fromSTEB( 100.rpx, 0.rpx, 100.rpx, 60.rpx), child: CalibrationProgressWidget( progressNotifier: progressNotifier, failureNotifier: failureNotifier, ), ); } return Container(); }), Obx(() { if (deviceCalibrationController.flag.value != 1) { return Padding( padding: EdgeInsetsDirectional.fromSTEB( 100.rpx, 0.rpx, 100.rpx, 60.rpx), child: CustomCard( borderRadius: AppConstants().normal_container_radius, onTap: () async { if (deviceCalibrationController.flag.value == 2) { _resetCalibrationState(); deviceCalibrationController.flag.value = 1; _startCalibration(false); } else { deviceCalibrationController.flag.value = 1; progressNotifier.value = 0; failureNotifier.value = false; _pollingTimer?.cancel(); _startCalibration(blueteethBindController .cid?.value.isNotEmpty ?? false); } }, colors: AppConstants().mhtButtongradientColors, gradientDirection: GradientDirection.vertical, child: Container( width: bodySize.maxWidth, height: MediaQuery.sizeOf(context).height * 0.055, constraints: BoxConstraints( minWidth: 500.rpx, minHeight: 90.rpx, ), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() { if (deviceCalibrationController .flag.value == 0) { if (deviceCalibrationController .bed_type.value == 1 && currentCalibrationStep.value == 2) { return Text( '开始另外一侧校准'.tr, style: TextStyle( color: stringToColor("#003058"), fontFamily: 'Inter', fontSize: AppConstants() .normal_text_fontSize, letterSpacing: 0.0, ), ); } return Text( '开始校准'.tr, style: TextStyle( color: stringToColor("#003058"), fontFamily: 'Inter', fontSize: AppConstants() .normal_text_fontSize, letterSpacing: 0.0, ), ); } if (deviceCalibrationController .flag.value == 1) { deviceCalibrationController .statusContext.value = ""; return Text( '校准中...'.tr, style: TextStyle( color: themeController .currentColor.sc3, fontFamily: 'Inter', fontSize: AppConstants() .normal_text_fontSize, letterSpacing: 0.0, ), ); } if (deviceCalibrationController .flag.value == 2) { return Text( '重新校准'.tr, style: TextStyle( color: stringToColor("#003058"), fontFamily: 'Inter', fontSize: AppConstants() .normal_text_fontSize, letterSpacing: 0.0, ), ); } return Container(); }), ].divide(SizedBox(width: 17.rpx)), ), ), ), ); } return Container(); }), ], ), ), ), ), ), ), ), onWillPop: () async { bool exit = false; if (deviceCalibrationController.flag.value != 2) { showConfirmDialog(context, Container(), "校准未完成提示".tr, onConfirm: () async { exit = true; _resetCalibrationState(); }, onCancel: () { exit = false; }); } else { exit = true; } return exit; }, ); } void _startPollingProgress( String serviceAddress, String progressApi, bool isSecondStep) { // _requestProgress(serviceAddress, progressApi, isSecondStep); _pollingTimer = Timer.periodic(Duration(seconds: 1), (_) { _requestProgress(serviceAddress, progressApi, isSecondStep); }); } void _requestProgress( String serviceAddress, String progressApi, bool isSecondStep) { String cid = blueteethBindController.cid!.value; String progressUrl = "$serviceAddress$progressApi?id=$cid"; requestWithLog( logTitle: "设备校准进度", method: MyHttpMethod.get, queryUrl: progressUrl, onSuccess: (res) { final data = res.data; double per = (data['per'] ?? 0).toDouble(); int currStep = data['currStep'] ?? -1; String tips = data['statusText'] ?? ''; try { if (data['mattress'] != null) { deviceCalibrationController.inBedTips.value = data['mattress']['inBed']; deviceCalibrationController.motionTips.value = data['mattress']['bm']; } } catch (e) { print(e); } if (data['status'] == null) { if (data['cd'] != null) { int cd = data['cd'] ?? 0; deviceCalibrationController.cd.value = cd; deviceCalibrationController.statusContext.value = ""; } } else { if (data['status'] == true) { deviceCalibrationController.tips.value = ""; deviceCalibrationController.cd.value = 10000; if (isSecondStep) { deviceCalibrationController.statusContext.value = data['statusText']; deviceCalibrationController.updateAll(); } } else { _handleCalibrationFailure(tips); return; } } bool status = data['status'] ?? false; progressNotifier.value = per; if (per != 100 && per != 20 && per != 40) { deviceCalibrationController.tips.value = tips; } else { deviceCalibrationController.tips.value = ""; } deviceCalibrationController.updateAll(); if (deviceCalibrationController.bed_type.value == 0) { _handleSingleBedProgress(isSecondStep, per, currStep, status, tips); } else { _handleDoubleBedProgress(isSecondStep, per, currStep, status, tips); } }, onFailure: (res) { _handleCalibrationFailure(res.msg ?? "服务器.失败".tr); }, ); } void _handleSingleBedProgress( bool isSecondStep, double per, int currStep, bool status, String tips) { if (!isSecondStep && per >= 20) { _pollingTimer?.cancel(); progressNotifier.value = 100; TopSlideNotification.show(context, text: tips); deviceCalibrationController.process.value = 1; deviceCalibrationController.bed_calibration.value = 1; deviceCalibrationController.flag.value = 0; currentCalibrationStep.value = 1; } else if (isSecondStep && per >= 100 && currStep == 5 && status) { _completeCalibration(); } } void _handleDoubleBedProgress( bool isSecondStep, double per, int currStep, bool status, String tips) { if (!isSecondStep && per >= 20) { _pollingTimer?.cancel(); progressNotifier.value = 100; TopSlideNotification.show(context, text: tips); deviceCalibrationController.process.value = 1; deviceCalibrationController.bed_calibration.value = 1; deviceCalibrationController.flag.value = 0; currentCalibrationStep.value = 1; } else if (isSecondStep && per >= 40 && currentCalibrationStep.value == 1) { _pollingTimer?.cancel(); TopSlideNotification.show(context, text: "单侧校准完成,请移动到另外一侧".tr); deviceCalibrationController.flag.value = 0; currentCalibrationStep.value = 2; progressNotifier.value = 0; failureNotifier.value = false; deviceCalibrationController.another.value = true; } else if (isSecondStep && per >= 100 && currStep == 5 && status && currentCalibrationStep.value == 2) { _completeCalibration(); } } void _completeCalibration() { _pollingTimer?.cancel(); TopSlideNotification.show(context, text: "设备校准完成".tr); deviceCalibrationController.bed_calibration.value = 1; deviceCalibrationController.position_calibration.value = 1; deviceCalibrationController.process.value = 1; deviceCalibrationController.flag.value = 2; deviceCalibrationController.another.value = false; progressNotifier.value = 0; failureNotifier.value = false; updateDeviceBindStatus(blueteethBindController.currentDeviceMac!.value); } void _handleCalibrationFailure(String message) { _pollingTimer?.cancel(); if (deviceCalibrationController.cd.value != 10000) { TopSlideNotification.show( context, text: message, textColor: themeController.currentColor.sc9, ); } deviceCalibrationController.statusContext.value = ""; deviceCalibrationController.bed_calibration.value == 0; blueteethBindController.cid?.value = ""; deviceCalibrationController.process.value = 0; deviceCalibrationController.flag.value = 0; deviceCalibrationController.tips.value = ""; deviceCalibrationController.cd.value = 10000; deviceCalibrationController.updateAll(); failureNotifier.value = true; } void _startCalibration(bool isSecondStep) { String serviceAddress = "https://caibration.he-info.cn"; String calibrationApi = ServiceConstant.start_calibration; String progressApi = ServiceConstant.calibration_process; String queryUrl = "$serviceAddress$calibrationApi"; Map data = { "macA": widget.deviceInfo.value['bind_mac_a'], }; if (deviceCalibrationController.bed_type.value == 1) { data["macB"] = widget.deviceInfo.value['bind_mac_b']; } if (isSecondStep) { data["id"] = blueteethBindController.cid!.value; if (deviceCalibrationController.bed_type.value == 1) { data["side"] = currentCalibrationStep.value == 1 ? "A" : "B"; } } // data['cancel'] = true; requestWithLog( logTitle: "设备校准", method: MyHttpMethod.post, queryUrl: queryUrl, data: data, onSuccess: (res) { if (!isSecondStep) { String cid = res.rawResponse.data['cid']; blueteethBindController.cid!.value = cid; } _startPollingProgress(serviceAddress, progressApi, isSecondStep); }, onFailure: (res) { _handleCalibrationFailure(res.msg ?? "服务器.失败".tr); }, ); } Widget getInBedMontion() { if (deviceCalibrationController.cd.value == 10000) { return Container(); } if (deviceCalibrationController.process.value == 1) { if (deviceCalibrationController.inBedTips.value == 0) { return Text( "请校准人员保持在床状态".tr, style: TextStyle( fontSize: AppConstants().normal_text_fontSize, color: themeController.currentColor.sc9, ), ); } } else { if (deviceCalibrationController.inBedTips.value != 0) { return Text( "请校准人员暂时离开床铺".tr, style: TextStyle( fontSize: AppConstants().normal_text_fontSize, color: themeController.currentColor.sc9, ), ); } } return Container(); } Widget getBodyMontion() { if (deviceCalibrationController.cd.value == 10000) { return Container(); } if (deviceCalibrationController.process.value == 1) { if (deviceCalibrationController.motionTips.value != 0) { return Text( "请保持身体静止".tr, style: TextStyle( fontSize: AppConstants().normal_text_fontSize, color: themeController.currentColor.sc9, ), ); } } return Container(); } void updateDeviceBindStatus(String mac) { String serviceAddress = ServiceConstant.service_address; String serviceName = ServiceConstant.server_service; String serviceApi = ServiceConstant.user_setting; String type = "device_bind_status_$mac"; String queryUrl = "${serviceAddress}${serviceName}${serviceApi}?type=${type}"; requestWithLog( logTitle: "查询绑定流程", method: MyHttpMethod.get, queryUrl: queryUrl, onSuccess: (res) { Map data = { "type": type, "mac": mac, "wifi": res.data['wifi'], "celibration": true, "person_info": false, "time": DateTime.now().millisecondsSinceEpoch, }; requestWithLog( logTitle: "更新绑定流程", method: MyHttpMethod.put, queryUrl: queryUrl, data: data, onSuccess: (res) {}, onFailure: (res) {}, ); }, onFailure: (res) {}, ); } }