diff --git a/assets/langs/en_US.json b/assets/langs/en_US.json index 4c3738b..7259f4e 100644 --- a/assets/langs/en_US.json +++ b/assets/langs/en_US.json @@ -108,7 +108,7 @@ "人员资料": { "标题": "User Information", "保存": "Save", - "名字输入提示": "User name (required)", + "名字输入提示": "User name", "生日输入提示": "Birthday (required)", "体重输入提示": "Weight kg (required)", "疾病标题": "Chronic disease management", @@ -628,5 +628,13 @@ "请检查网络连接后重试": "Please check the network connection and try again", "开始": "startTime", "结束": "endTime", - "时长": "duration:" + "时长": "duration:", + "检测到新版本!": "New version detected!", + "正在下载更新...": "Downloading update...", + "当前版本号": "Current version", + "升级后版本": "Updated version", + "升级内容": "Update content", + "升级": "Upgrade", + "前往AppStore": "Go to AppStore", + "下载中...": "Downloading..." } \ No newline at end of file diff --git a/assets/langs/zh_CN.json b/assets/langs/zh_CN.json index a466b6f..93dc838 100644 --- a/assets/langs/zh_CN.json +++ b/assets/langs/zh_CN.json @@ -108,7 +108,7 @@ "人员资料": { "标题": "人员资料", "保存": "保存", - "名字输入提示": "使用人员姓名(必填)", + "名字输入提示": "使用人员姓名", "生日输入提示": "生日(必填)", "体重输入提示": "体重kg(必填)", "疾病标题": "慢病管理", @@ -628,5 +628,13 @@ "隐私协议加载失败": "隐私协议加载失败", "请检查网络连接后重试": "请检查网络连接后重试", "开始": "开始", - "结束": "结束" + "结束": "结束", + "检测到新版本!": "检测到新版本!", + "正在下载更新...": "正在下载更新...", + "当前版本号": "当前版本号", + "升级后版本": "升级后版本", + "升级内容": "升级内容", + "升级": "升级", + "前往AppStore": "前往AppStore", + "下载中...": "下载中..." } \ No newline at end of file diff --git a/assets/langs/zh_TW.json b/assets/langs/zh_TW.json index ef4e4d1..2520005 100644 --- a/assets/langs/zh_TW.json +++ b/assets/langs/zh_TW.json @@ -108,7 +108,7 @@ "人员资料": { "标题": "人員資料", "保存": "保存", - "名字输入提示": "使用人員姓名(必填)", + "名字输入提示": "使用人員姓名", "生日输入提示": "生日(必填)", "体重输入提示": "體重kg(必填)", "疾病标题": "慢病管理", @@ -626,5 +626,13 @@ "请检查网络连接后重试": "請檢查網絡連接後重試", "开始": "開始", "结束": "結束", - "时长": "時長:" + "时长": "時長:", + "检测到新版本!": "檢測到新版本!", + "正在下载更新...": "正在下載更新...", + "当前版本号": "目前版本號", + "升级后版本": "升級後版本", + "升级内容": "升級內容", + "升级": "升級", + "前往AppStore": "前往AppStore", + "下载中...": "下載中..." } \ No newline at end of file diff --git a/lib/common/color/ServiceConstant.dart b/lib/common/color/ServiceConstant.dart index d28a99c..ee2384b 100644 --- a/lib/common/color/ServiceConstant.dart +++ b/lib/common/color/ServiceConstant.dart @@ -61,4 +61,7 @@ class ServiceConstant { "https://vsbst-api.he-info.cn/vsbs_sotrage/background-image/taihe.png"; static const String localTimeZone = "/api/city/data/utc/info"; + //todo 检查app更新 + static const String checkAPPVersion = + "/api/app/update/check"; } diff --git a/lib/common/color/appConstants.dart b/lib/common/color/appConstants.dart index 7841385..fba565c 100644 --- a/lib/common/color/appConstants.dart +++ b/lib/common/color/appConstants.dart @@ -9,7 +9,7 @@ class AppConstants { // App-related constants static const String zhmht_app_version = "SWES_1.2026.1.8";//眠花糖 - static const String theh_app_version = "1.2601.08";//太和 + static const String theh_app_version = "1.2601.12";//太和 // 1. 纯字符串列表格式 static const List integerTimeZones = [ diff --git a/lib/controller/user_info_controller.dart b/lib/controller/user_info_controller.dart index 59dc03a..6c1cdf4 100644 --- a/lib/controller/user_info_controller.dart +++ b/lib/controller/user_info_controller.dart @@ -13,6 +13,7 @@ import 'package:vbvs_app/common/color/app_uri_status.dart'; import 'package:vbvs_app/common/util/DailyLogUtils.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/common/util/requestWithLog.dart'; +import 'package:vbvs_app/component/tool/NewTopSlideNotification.dart'; import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; import 'package:vbvs_app/controller/device/body_device_controller.dart'; import 'package:vbvs_app/controller/home/home_controller.dart'; @@ -47,6 +48,7 @@ class UserInfoModel { String? img_bucket = 'user'; int? login = 0; //0未登录 1 登录 + int? deviceBindNum = 0; //绑定设备数量 int? loginPhone = 0; //0 本机号码 1其他手机号 @@ -73,6 +75,7 @@ class UserInfoController extends GetControllerEx { int initLocationpermission = 0; //未初始化 FluwxCancelable? fluwxCancelable; final Fluwx fluwx = Fluwx(); + // RxInt login = 0.obs; //0未登录 1 登录 List> country_code = [ { @@ -86,7 +89,7 @@ class UserInfoController extends GetControllerEx { ]; RxString select_country_code = "+86".obs; - RxInt select_login_method = 1.obs;//1手机 2邮箱 + RxInt select_login_method = 1.obs; //1手机 2邮箱 Future uploadImg() async { EasyDartModule.logger.info("请求上传图片"); @@ -386,4 +389,42 @@ class UserInfoController extends GetControllerEx { ef.log("微信解绑失败-》$e"); } } + + // 查询是否需要更新APP + checkAPPUpdate(String currentVersion) async { + String serviceAddress = ServiceConstant.service_address; + String serviceName = ServiceConstant.server_service; + String serviceApi = ServiceConstant.checkAPPVersion; + + // 拼接 query 参数 ver + String queryUrl = + "${serviceAddress}${serviceName}${serviceApi}?ver=${AppConstants.theh_app_version}"; + + var data = null; + try { + final res = await requestWithLog( + logTitle: "检测APP更新", + method: MyHttpMethod.get, + queryUrl: queryUrl, + onSuccess: (res) { + data = res.data; + }, + onFailure: (res) { + NewTopSlideNotification.show( + text: res.msg!, + textColor: themeController.currentColor.sc9, + ); + }, + ); + } catch (e) { + ef.log("检测APP更新-》$e"); + + NewTopSlideNotification.show( + text: "检测异常".tr, + textColor: themeController.currentColor.sc9, + ); + } + + return data; + } } diff --git a/lib/pages/device/device_detail.dart b/lib/pages/device/device_detail.dart index cb13b2a..07565d5 100644 --- a/lib/pages/device/device_detail.dart +++ b/lib/pages/device/device_detail.dart @@ -367,7 +367,13 @@ class _DeviceDetailPageState extends State { alignment: AlignmentDirectional(-1.rpx, 0.rpx), child: Text( - '${widget.device['person']?['name'] ?? '未命名'.tr}', + ((widget.device['person']?['name'] + as String?) + ?.trim() + .isNotEmpty ?? + false) + ? widget.device['person']['name'] + : '体征检测设备'.tr, style: TextStyle( fontFamily: 'Inter', fontSize: 26.rpx, diff --git a/lib/pages/device/instant_body_page.dart b/lib/pages/device/instant_body_page.dart index f802efc..2430c01 100644 --- a/lib/pages/device/instant_body_page.dart +++ b/lib/pages/device/instant_body_page.dart @@ -335,7 +335,19 @@ class _InstantBodyPageState extends State .width * 0.2, child: Text( - '${device['person']?['name'] ?? '未命名'.tr}', + device['person'] != null && + device['person'] + ['name'] != + null && + device['person'] + ['name'] + .toString() + .trim() + .isNotEmpty + ? device['person'] + ['name'] + .toString() + : '体征检测设备'.tr, style: TextStyle( fontFamily: 'Inter', fontSize: 26.rpx, diff --git a/lib/pages/device/message_review_page.dart b/lib/pages/device/message_review_page.dart index 01be645..f6ade05 100644 --- a/lib/pages/device/message_review_page.dart +++ b/lib/pages/device/message_review_page.dart @@ -147,7 +147,14 @@ class _MessageReviewPageState extends State { .width * 0.2, child: Text( - '${widget.data['person']?['name'] ?? '未命名'.tr}', + ((widget.data['person']?['name'] + as String?) + ?.trim() + .isNotEmpty ?? + false) + ? widget.data['person'] + ['name'] + : '体征检测设备'.tr, style: TextStyle( fontFamily: 'Inter', fontSize: 26.rpx, diff --git a/lib/pages/device_bind/device_share_page.dart b/lib/pages/device_bind/device_share_page.dart index 0f55a0a..e3c68f8 100644 --- a/lib/pages/device_bind/device_share_page.dart +++ b/lib/pages/device_bind/device_share_page.dart @@ -128,14 +128,29 @@ class _DeviceSharePageState extends State { deviceShareController.updateAll(); }, )), - Text( - '主设备'.tr + - "${device['person']?['name'] == null ? '未命名'.tr : device['person']['name']}", - style: TextStyle( - fontFamily: 'Inter', - fontSize: 26.rpx, - letterSpacing: 0.0, - color: themeController.currentColor.sc3, + Expanded( + child: Text( + '主设备'.tr + + (device['person'] != null && + device['person'] is Map && + device['person']['name'] != + null && + device['person']['name'] + .toString() + .trim() + .isNotEmpty + ? device['person']['name'] + .toString() + : '体征监测设备'.tr) + + "(" + + "${device['mac']}" + + ")", + style: TextStyle( + fontFamily: 'Inter', + fontSize: 26.rpx, + letterSpacing: 0.0, + color: themeController.currentColor.sc3, + ), ), ), ].divide(SizedBox(width: 20.rpx)), @@ -216,7 +231,9 @@ class _DeviceSharePageState extends State { height: 33.rpx * 0.6, - color: themeController.currentColor.sc2, + color: themeController + .currentColor + .sc2, ), ), ) diff --git a/lib/pages/login/other_login.dart b/lib/pages/login/other_login.dart index 7698ae9..e8a45d2 100644 --- a/lib/pages/login/other_login.dart +++ b/lib/pages/login/other_login.dart @@ -728,8 +728,8 @@ class _OtherLoginPageState extends State { weatherModelController = Get.find(); await weatherModelController .getCurrentLocation(); - // await weatherModelController - // .getCurrentWeather(); + await weatherModelController + .getCurrentWeather(); } } } catch (e) { diff --git a/lib/pages/main_bottom/e_page.dart b/lib/pages/main_bottom/e_page.dart index c7bd14c..12b3733 100644 --- a/lib/pages/main_bottom/e_page.dart +++ b/lib/pages/main_bottom/e_page.dart @@ -103,35 +103,6 @@ class _EPageState extends State with AutomaticKeepAliveClientMixin { ); } - // Widget _buildLoggedInContent() { - // return Obx(() { - // if (finalUri.isEmpty) { - // return Center(child: CircularProgressIndicator()); - // } - - // return Stack( - // children: [ - // InAppWebView( - // initialUrlRequest: URLRequest(url: WebUri(finalUri.value)), - // onLoadStart: (controller, url) { - // isPageLoading.value = true; - // }, - // onLoadStop: (controller, url) { - // isPageLoading.value = false; - // }, - // ), - // ValueListenableBuilder( - // valueListenable: isPageLoading, - // builder: (context, isLoading, child) { - // return isLoading - // ? Center(child: CircularProgressIndicator()) - // : SizedBox.shrink(); - // }, - // ), - // ], - // ); - // }); - // } Widget _buildLoggedInContent() { return Obx(() { if (finalUri.isEmpty) { @@ -233,7 +204,7 @@ class _EPageState extends State with AutomaticKeepAliveClientMixin { item['person']['name'] != null && item['person']['name'].toString().trim().isNotEmpty) ? item['person']['name'] + "_${mac}" - : '未命名'.tr + "_${mac}"; + : '体征检测设备'.tr + "_${mac}"; return { 'mac': mac, 'name': name, @@ -274,71 +245,4 @@ class _EPageState extends State with AutomaticKeepAliveClientMixin { ef.log(e.toString()); } } - - // Future getDeviceList() async { - // try { - // BodyDeviceController bodyDeviceController = Get.find(); - // ApiResponse apiResponse = - // await bodyDeviceController.getDeviceList(isAllDevice: true); - - // // 调试:打印返回的数据结构 - // print('API响应数据: $apiResponse'); - // print('API响应数据类型: ${apiResponse.data.runtimeType}'); - // print('API响应数据内容: ${apiResponse.data}'); - - // if (apiResponse.code == HttpStatusCodes.ok) { - // List rawList = apiResponse.data; - - // // 调试:检查 rawList 的类型和内容 - // print('rawList 类型: ${rawList.runtimeType}'); - // print('rawList 长度: ${rawList.length}'); - // if (rawList.isNotEmpty) { - // print('rawList[0] 类型: ${rawList[0].runtimeType}'); - // print('rawList[0] 内容: ${rawList[0]}'); - // } - - // // 安全处理:确保每个元素都是 Map - // List> newList = - // rawList.whereType().map((item) { - // // 调试每个 item - // print('处理 item: $item'); - // print('item 类型: ${item.runtimeType}'); - - // String mac = (item['mac'] ?? '').toString(); - // String name = '未命名'.tr + "_${mac}"; - - // if (item['person'] != null && item['person'] is Map) { - // var person = item['person'] as Map; - // if (person['name'] != null && - // person['name'].toString().trim().isNotEmpty) { - // name = '${person['name']}_${mac}'; - // } - // } - - // return { - // 'mac': mac, - // 'name': name, - // }; - // }).toList(); - - // deviceList.value = newList; - - // // 拼接参数 person - // if (deviceList.isNotEmpty) { - // // JSON 编码整个 deviceList 对象数组 - // String personParam = Uri.encodeComponent(jsonEncode(deviceList)); - // finalUri.value = "${widget.sleepUri}?person=$personParam"; - // } else { - // finalUri.value = widget.sleepUri; - // } - // } - - // // ... 后续语言处理代码不变 - // } catch (e) { - // print('getDeviceList 错误详情: $e'); - // print('错误堆栈: ${e}'); - // ef.log(e.toString()); - // } - // } - } diff --git a/lib/pages/main_bottom/home_page.dart b/lib/pages/main_bottom/home_page.dart index f3d9109..c17db0c 100644 --- a/lib/pages/main_bottom/home_page.dart +++ b/lib/pages/main_bottom/home_page.dart @@ -1,3 +1,4 @@ +import 'package:EasyDartModule/EasyDartModule.dart' as edm; import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; @@ -184,7 +185,7 @@ class _HomePageState extends State { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (userInfoController.model.login == 1) { - homeController.getSleepReport(); + // deviceController.getSleepReport(); deviceController.getDeviceNum().then((apiResponse) { if (apiResponse.code != HttpStatusCodes.ok) { TopSlideNotification.show( @@ -203,7 +204,9 @@ class _HomePageState extends State { ); } else { //请求睡眠报告 - deviceController.getSleepReport(); + deviceController.getSleepReport().then((value) { + homeController.updateAll(); + }); } }); } @@ -1006,7 +1009,13 @@ class _HomePageState extends State { Map> reportData = deviceController.sleepReportData.value; var deviceList = deviceController.deviceList.value - .where((device) => device['show'] == true) + .where((device) => (device['show'] == true && + device['bind_type'] == + homeController.model.type)) + .toList(); + var newList = deviceList + .map((device) => + {'mac': device['mac'], 'show': device['show']}) .toList(); if (deviceList.isEmpty) { return Expanded(child: NullDataWidget()); @@ -1022,11 +1031,30 @@ class _HomePageState extends State { ) .toList(); if (macList.length != deviceList.length) { + edm.EasyDartModule.logger.info( + "[首页睡眠报告问题]reportData数量: ${macList.length}"); + edm.EasyDartModule.logger.info( + "[首页睡眠报告问题]reportData信息: ${macList.toString()}"); + edm.EasyDartModule.logger.info( + "[首页睡眠报告问题]deviceList数量: ${deviceList.length}"); + edm.EasyDartModule.logger.info( + "[首页睡眠报告问题]deviceList信息: ${newList.toString()}"); return Expanded( child: Center( child: CircularProgressIndicator( color: themeController.currentColor.sc1, )), + // child: Column( + // children: [ + // Text( + // "[首页睡眠报告问题]reportData数量: ${macList.length}\n" + + // "[首页睡眠报告问题]reportData信息: ${macList.toString()}\n" + + // "[首页睡眠报告问题]deviceList数量: ${deviceList.length}\n" + + // "[首页睡眠报告问题]deviceList信息: ${deviceList.toString()}\n", + // style: TextStyle(color: Colors.red), + // ) + // ], + // ), ); } diff --git a/lib/pages/main_bottom/main_page_bottom_change copy.dart b/lib/pages/main_bottom/main_page_bottom_change copy.dart new file mode 100644 index 0000000..c265bb6 --- /dev/null +++ b/lib/pages/main_bottom/main_page_bottom_change copy.dart @@ -0,0 +1,362 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:ef/ef.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:get_storage/get_storage.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/component/tool/TopSlideNotification.dart'; +import 'package:vbvs_app/controller/main_bottom/global_controller.dart'; +import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart'; +import 'package:vbvs_app/controller/message/message_controller.dart'; +import 'package:vbvs_app/controller/setting/language/language_controller.dart'; +import 'package:vbvs_app/controller/theme_controller/ThemeController.dart'; +import 'package:vbvs_app/controller/user_info_controller.dart'; +import 'package:vbvs_app/enum/APPPackageType.dart'; +import 'package:vbvs_app/enum/LoginStatus.dart'; +import 'package:vbvs_app/pages/common/selectDialog.dart'; +import 'package:vbvs_app/pages/main_bottom/e_page.dart'; +import 'package:vbvs_app/pages/main_bottom/home_page.dart'; +import 'package:vbvs_app/pages/main_bottom/message_page.dart'; +import 'package:vbvs_app/pages/main_bottom/mine_page.dart'; +import 'package:vbvs_app/pages/mh_page/component/mht_bind_dialog.dart'; + +class MainPageBottomChange extends GetView { + GlobalController globalController = Get.find(); + ThemeController themeController = Get.find(); + MessageController messageController = Get.find(); + final getStorage = GetStorage(); + + late final List arr; + late final List bottomItems; + DateTime? _lastBackPressedTime; + LanguageController languageController = Get.find(); + bool select = false;//是否已经提示过升级弹窗 + + MainPageBottomChange({super.key}) { + // ✅ 根据是否测试账号动态生成页面 + if (!AppConstants.is_test_account) { + arr = [ + HomePage(), + EPage(sleepUri: "https://xiaoe.he-info.cn/"), + MessagePage(), + MinePage(), + ]; + bottomItems = [ + getBottomNavigationBarItem("assets/img/menu/home.svg", + "assets/img/menu/n_home.svg", "菜单.首页".tr), + getBottomNavigationBarItem( + "assets/img/menu/e.svg", "assets/img/menu/n_e.svg", "菜单.小e".tr), + getBottomNavigationBarItem("assets/img/menu/message.svg", + "assets/img/menu/n_message.svg", "菜单.消息".tr, + showBadge: true), + getBottomNavigationBarItem("assets/img/menu/mine.svg", + "assets/img/menu/n_mine.svg", "菜单.我的".tr), + ]; + } else { + arr = [ + HomePage(), + MessagePage(), + MinePage(), + ]; + bottomItems = [ + getBottomNavigationBarItem("assets/img/menu/home.svg", + "assets/img/menu/n_home.svg", "菜单.首页".tr), + getBottomNavigationBarItem("assets/img/menu/message.svg", + "assets/img/menu/n_message.svg", "菜单.消息".tr, + showBadge: (messageController.model.body_message_read == 1 || + messageController.model.system_message_read == 1)), + getBottomNavigationBarItem("assets/img/menu/mine.svg", + "assets/img/menu/n_mine.svg", "菜单.我的".tr), + ]; + } + } + + getBottomNavigationBarItem(String svgPath, String actSvgPath, String label, + {double size = 0, bool isEmpty = false, bool showBadge = false}) { + if (size == 0) size = 36.rpx; + + Widget buildIcon(String path) { + return Obx(() { + int type1 = messageController.model.body_message_read!; + int type2 = messageController.model.system_message_read!; + return Padding( + padding: EdgeInsets.only(bottom: 6.rpx), + child: isEmpty + ? Container() + : Stack( + clipBehavior: Clip.none, + children: [ + SvgPicture.asset( + path, + width: size, + height: size, + ), + if ((type1 == 1 || type2 == 1) && showBadge) + Positioned( + right: -20.rpx, + top: -2.rpx, + child: Container( + width: 14.rpx, + height: 14.rpx, + decoration: const BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + ), + ), + ], + ), + ); + }); + } + + return BottomNavigationBarItem( + icon: buildIcon(actSvgPath), + activeIcon: buildIcon(svgPath), + label: label, + ); + } + + @override + Widget build(BuildContext context) { + if (AppConstants().ent_type == APPPackageType.TH.code) { + Future.delayed(const Duration(milliseconds: 0), () { + String? isShowYingShiDialog = getStorage.read("isShowYingShiDialog"); + if (isShowYingShiDialog == null || isShowYingShiDialog != "true") { + String btnName = "同意".tr; + String cancelName = "取消".tr; + if (Platform.isAndroid) cancelName = "退出".tr; + + showCustomConfirmOfWebViewDialog(context, "隐私协议".tr, getPrivacy(1), + btnName: btnName, showCancel: true, cancelName: cancelName) + .then((e) { + if (e == "confirm") { + getStorage.write("isShowYingShiDialog", "true"); + } else { + if (cancelName == "退出") SystemNavigator.pop(); + } + }); + } + if (select != true) { + //todo 判断APP是否需要更新 + UserInfoController userInfoController = Get.find(); + userInfoController + .checkAPPUpdate(AppConstants.theh_app_version) + .then((data) { + if (data != null) { + if (data['update'] != null && data['update'] == true) { + //需要更新 + String updateUrl = data['updateUrl']; + try { + select = true; + showAPPUpgradeDialog( + // backgroundColor:themeController.currentColor.sc5, + context, + Column( + children: [ + /// 上半部分:居中对齐 + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 94.rpx, + height: 70.rpx, + child: SvgPicture.asset( + 'assets/img/icon/upgrade.svg', + fit: BoxFit.cover, + ), + ), + SizedBox(height: 37.rpx), + Text( + "检测到新版本!".tr, + style: TextStyle( + color: stringToColor("#333333"), + fontSize: AppConstants().title_text_fontSize, + ), + ), + ], + ), + + SizedBox(height: 37.rpx), + + /// 下半部分:左对齐 + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("当前版本号".tr + ":" + "1.2.0"), + Text("升级后版本".tr + ":" + "1.2.0"), + Text( + "升级内容".tr + + ":" + + "更新更新更新更新更新更新更新更新更新更新更新更新更新更新更新更新更新更新等...", + ), + ], + ), + ], + ), onUpgradeTap: () { + if (Platform.isIOS) { + // 跳转AppStore + ef.log("msg"); + } else { + //本地安装 + ef.log("msg"); + } + Get.back(); + }); + } catch (e) { + ef.log("msg"); + } + } + } + }); + } + }); + } + + return Obx(() { + final currentLanguage = + languageController.selectLanguage.value; // 监听此变量变化 + return PopScope( + canPop: false, + onPopInvokedWithResult: (disposition, result) async { + UserInfoController userInfoController = Get.find(); + if (userInfoController.model.isProgrammaticPop) { + userInfoController.model.isProgrammaticPop = false; + return; + } + + // if (Platform.isAndroid) { + // Get.back(); + // } + if (Platform.isAndroid) { + var flag = await _handleBackPressed(context); + if (flag) { + SystemNavigator.pop(); + } + } + }, + child: Obx(() { + int currentIndex = controller.model.currentIndex; + + // ✅ 防止 index 超出范围(例如测试账号少一个 tab) + if (currentIndex >= arr.length) { + currentIndex = 0; + controller.model.currentIndex = 0; + } + + if (globalController.model.hideBottomNavigationBar == true) { + return Scaffold( + body: IndexedStack( + index: currentIndex, + children: + arr.map((page) => SizedBox.expand(child: page)).toList(), + ), + ); + } else { + return Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/img/bgImage.png'), + fit: BoxFit.fill, + ), + ), + child: Scaffold( + backgroundColor: Colors.transparent, + body: IndexedStack( + index: currentIndex, + children: + arr.map((page) => SizedBox.expand(child: page)).toList(), + ), + bottomNavigationBar: Theme( + data: Theme.of(context).copyWith( + splashFactory: NoSplash.splashFactory, + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + ), + child: Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: + themeController.currentColor.sc4.withOpacity(0.5), + width: AppConstants().border_width, + ), + ), + ), + child: BottomNavigationBar( + unselectedItemColor: themeController.currentColor.sc4, + selectedItemColor: themeController.currentColor.sc1, + backgroundColor: themeController.currentColor.sc5, + selectedFontSize: 26.rpx, + unselectedFontSize: 26.rpx, + type: BottomNavigationBarType.fixed, + currentIndex: currentIndex, + onTap: (index) { + Future.delayed(const Duration(milliseconds: 100), () { + UserInfoController userInfoController = Get.find(); + bool isLoggedIn = userInfoController.model.login == + LoginStatus.LOGIN.code; + + // ✅ 仅非测试账号检查登录状态 + if (!AppConstants.is_test_account && + (index == 2) && + !isLoggedIn) { + TopSlideNotification.show( + context, + text: "必须登录提示".tr, + textColor: themeController.currentColor.sc9, + ); + Future.delayed(const Duration(milliseconds: 50), + () { + if (Get.currentRoute == '/ePage' || + Get.currentRoute == '/messagePage') { + Get.back(); + } + Future.delayed(const Duration(milliseconds: 100), + () { + Get.toNamed("/otherLoginPage"); + }); + }); + return; + } + + if (controller.model.currentIndex != index) { + globalController.model.hideBottomNavigationBar = + false; + globalController.updateAll(); + } + + controller.model.currentIndex = index; + controller.updateAll(); + }); + }, + items: bottomItems, + ), + ), + ), + ), + ); + } + }), + ); + }); + } + + Future _handleBackPressed(BuildContext context) async { + final currentTime = DateTime.now(); + if (_lastBackPressedTime == null || + currentTime.difference(_lastBackPressedTime!) > + const Duration(seconds: 2)) { + _lastBackPressedTime = currentTime; + TopSlideNotification.show(context, text: "滑动退出提醒".tr); + return false; + } else { + return true; + } + } +} diff --git a/lib/pages/main_bottom/main_page_bottom_change.dart b/lib/pages/main_bottom/main_page_bottom_change.dart index 4b03c8d..f3b4090 100644 --- a/lib/pages/main_bottom/main_page_bottom_change.dart +++ b/lib/pages/main_bottom/main_page_bottom_change.dart @@ -1,284 +1,24 @@ -// import 'dart:async'; -// import 'dart:io'; - -// import 'package:ef/ef.dart'; -// import 'package:flutter/material.dart'; -// import 'package:flutter/services.dart'; -// import 'package:flutter_svg/svg.dart'; -// import 'package:get_storage/get_storage.dart'; -// import 'package:vbvs_app/common/color/appConstants.dart'; -// import 'package:vbvs_app/common/util/FitTool.dart'; -// import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; -// import 'package:vbvs_app/controller/main_bottom/global_controller.dart'; -// import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart'; -// import 'package:vbvs_app/controller/message/message_controller.dart'; -// import 'package:vbvs_app/controller/theme_controller/ThemeController.dart'; -// import 'package:vbvs_app/controller/user_info_controller.dart'; -// import 'package:vbvs_app/enum/LoginStatus.dart'; -// import 'package:vbvs_app/pages/common/selectDialog.dart'; -// import 'package:vbvs_app/pages/main_bottom/e_page.dart'; -// import 'package:vbvs_app/pages/main_bottom/home_page.dart'; -// import 'package:vbvs_app/pages/main_bottom/message_page.dart'; -// import 'package:vbvs_app/pages/main_bottom/mine_page.dart'; - -// class MainPageBottomChange extends GetView { -// GlobalController globalController = Get.find(); -// ThemeController themeController = Get.find(); -// MessageController messageController = Get.find(); -// getBottomNavigationBarItem(String svgPath, String actSvgPath, String label, -// {double size = 0, bool isEmpty = false, bool showBadge = false}) { -// if (size == 0) { -// size = 36.rpx; -// } -// Widget buildIcon(String path) { -// return Padding( -// padding: EdgeInsets.only(bottom: 6.rpx), -// child: isEmpty -// ? Container() -// : Stack( -// clipBehavior: Clip.none, -// children: [ -// SvgPicture.asset( -// path, -// width: size, -// height: size, -// ), -// if (showBadge) -// Positioned( -// right: -20.rpx, -// top: -2.rpx, -// child: Container( -// width: 14.rpx, -// height: 14.rpx, -// decoration: BoxDecoration( -// color: Colors.red, -// shape: BoxShape.circle, -// ), -// ), -// ) -// ], -// ), -// ); -// } - -// return BottomNavigationBarItem( -// icon: buildIcon(actSvgPath), -// activeIcon: buildIcon(svgPath), -// label: label, -// ); -// } - -// List arr = [ -// HomePage(), -// // SleepReportPage(), -// // EPage(), -// EPage(sleepUri: "https://xiaoe.he-info.cn/"), -// MessagePage(), -// MinePage(), -// ]; - -// DateTime? _lastBackPressedTime; // 记录上一次返回的时间 -// final getStorage = GetStorage(); -// @override -// Widget build(BuildContext context) { -// Future.delayed(const Duration(milliseconds: 0), () { -// String? isShowYingShiDialog = getStorage.read("isShowYingShiDialog"); -// if (isShowYingShiDialog == null || isShowYingShiDialog != "true") { -// String btnName = "同意".tr; -// String cancelName = "取消".tr; -// if (Platform.isAndroid) { -// cancelName = "退出".tr; -// } -// showCustomConfirmOfWebViewDialog(context, "隐私协议".tr, getPrivacy(1), -// btnName: btnName, showCancel: true, cancelName: cancelName) -// .then((e) { -// if (e == "confirm") { -// getStorage.write("isShowYingShiDialog", "true"); -// } else { -// if (cancelName == "退出") { -// SystemNavigator.pop(); -// } -// } -// }); -// } -// }); - -// return PopScope( -// canPop: false, - -// // onPopInvokedWithResult: (disposition, result) async { -// // if (Platform.isAndroid) { -// // var flag = await _handleBackPressed(context); // 自定义返回逻辑 -// // if (flag) { -// // SystemNavigator.pop(); -// // } -// // } -// // }, -// onPopInvokedWithResult: (disposition, result) async { -// UserInfoController userInfoController = Get.find(); -// if (userInfoController.model.isProgrammaticPop) { -// // 如果是程序触发,重置标记并忽略 -// userInfoController.model.isProgrammaticPop = false; -// return; // 阻止处理 -// } - -// if (Platform.isAndroid) { -// // var flag = await _handleBackPressed(context); // 自定义返回逻辑 -// // if (flag) { -// // SystemNavigator.pop(); -// // } -// Get.back(); -// } -// }, -// child: Obx( -// () { -// if (globalController.model.hideBottomNavigationBar == true) { -// return Scaffold( -// // body: arr[controller.model.currentIndex], -// body: IndexedStack( -// // ✅ 改成 IndexedStack -// index: controller.model.currentIndex, -// children: -// arr.map((page) => SizedBox.expand(child: page)).toList(), -// ), -// floatingActionButtonAnimator: -// FloatingActionButtonAnimator.noAnimation, -// floatingActionButton: Container(), -// ); -// } else { -// return Container( -// decoration: BoxDecoration( -// image: DecorationImage( -// image: AssetImage('assets/img/bgImage.png'), // 本地图片 -// fit: BoxFit.fill, // 填满整个 Container -// ), -// ), -// child: Scaffold( -// backgroundColor: Colors.transparent, -// // body: arr[controller.model.currentIndex], -// body: IndexedStack( -// // ✅ 改成 IndexedStack -// index: controller.model.currentIndex??3, -// children: arr -// .map((page) => SizedBox.expand(child: page)) -// .toList(), -// ), -// floatingActionButtonAnimator: -// FloatingActionButtonAnimator.noAnimation, -// floatingActionButtonLocation: -// FloatingActionButtonLocation.centerDocked, -// bottomNavigationBar: Theme( -// data: Theme.of(context).copyWith( -// splashFactory: NoSplash.splashFactory, -// splashColor: Colors.transparent, -// highlightColor: Colors.transparent, -// ), -// child: Container( -// decoration: BoxDecoration( -// border: Border( -// top: BorderSide( -// color: themeController.currentColor.sc4 -// .withOpacity(0.5), -// width: AppConstants().border_width, -// ), -// ), -// ), -// child: BottomNavigationBar( -// unselectedItemColor: themeController.currentColor.sc4, -// selectedItemColor: themeController.currentColor.sc1, -// backgroundColor: themeController.currentColor.sc5, -// selectedFontSize: 26.rpx, -// unselectedFontSize: 26.rpx, -// type: BottomNavigationBarType.fixed, -// currentIndex: controller.model.currentIndex, -// onTap: (index) { -// Future.delayed(const Duration(milliseconds: 100), () { -// UserInfoController userInfoController = Get.find(); -// bool isLoggedIn = userInfoController.model.login == -// LoginStatus.LOGIN.code; - -// // if ((index == 1 || index == 2) && !isLoggedIn) { -// if ((index == 2) && !isLoggedIn) { -// TopSlideNotification.show( -// context, -// text: "必须登录提示".tr, -// textColor: themeController.currentColor.sc9, -// ); -// Future.delayed(Duration(milliseconds: 50), () { -// if (Get.currentRoute == '/ePage' || -// Get.currentRoute == '/messagePage') { -// Get.back(); -// } -// Future.delayed(Duration(milliseconds: 100), () { -// Get.toNamed("/otherLoginPage"); -// }); -// }); -// return; -// } - -// if (controller.model.currentIndex != index) { -// globalController.model.hideBottomNavigationBar = -// false; -// globalController.updateAll(); -// } - -// controller.model.currentIndex = index; -// controller.updateAll(); -// }); -// }, -// items: [ -// getBottomNavigationBarItem("assets/img/menu/home.svg", -// "assets/img/menu/n_home.svg", "菜单.首页".tr), -// getBottomNavigationBarItem("assets/img/menu/e.svg", -// "assets/img/menu/n_e.svg", "菜单.小e".tr), -// getBottomNavigationBarItem( -// "assets/img/menu/message.svg", -// "assets/img/menu/n_message.svg", -// "菜单.消息".tr, -// showBadge: (messageController -// .model.body_message_read == -// 1 || -// messageController.model.system_message_read == -// 1)), -// getBottomNavigationBarItem("assets/img/menu/mine.svg", -// "assets/img/menu/n_mine.svg", "菜单.我的".tr), -// ], -// ), -// ), -// ), -// )); -// } -// }, -// ), -// ); -// } - -// Future _handleBackPressed(BuildContext context) async { -// final currentTime = DateTime.now(); - -// // 如果上次点击返回键时间为空,或者间隔超过 1 秒 -// if (_lastBackPressedTime == null || -// currentTime.difference(_lastBackPressedTime!) > Duration(seconds: 2)) { -// _lastBackPressedTime = currentTime; -// // showToast("再按一次退出程序", color: color_warning, closeTime: 2); -// TopSlideNotification.show(context, text: "滑动退出提醒".tr); -// return false; // 阻止退出程序 -// } else { -// return true; // 允许退出程序 -// } -// } -// } - import 'dart:async'; import 'dart:io'; +// 添加新的导入 +import 'package:dio/dio.dart'; import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:get_storage/get_storage.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:url_launcher/url_launcher.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/component/tool/CustomCard.dart'; +import 'package:vbvs_app/component/tool/FrostedDialog.dart'; +import 'package:vbvs_app/component/tool/NewTopSlideNotification.dart'; import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; import 'package:vbvs_app/controller/main_bottom/global_controller.dart'; import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart'; @@ -294,6 +34,48 @@ import 'package:vbvs_app/pages/main_bottom/home_page.dart'; import 'package:vbvs_app/pages/main_bottom/message_page.dart'; import 'package:vbvs_app/pages/main_bottom/mine_page.dart'; +// 创建一个专门管理下载状态的Controller +class DownloadController extends GetxController { + RxDouble downloadProgress = 0.0.obs; + RxBool isDownloading = false.obs; + RxString downloadStatus = '等待下载'.obs; + CancelToken? cancelToken; + String? downloadFilePath; + + void startDownload() { + isDownloading.value = true; + downloadProgress.value = 0.0; + downloadStatus.value = '开始下载'; + } + + void updateProgress(double progress) { + downloadProgress.value = progress; + downloadStatus.value = '下载中: ${(progress * 100).toStringAsFixed(1)}%'; + } + + void completeDownload(String filePath) { + isDownloading.value = false; + downloadProgress.value = 1.0; + downloadStatus.value = '下载完成'; + downloadFilePath = filePath; + } + + void cancelDownload() { + if (cancelToken != null) { + cancelToken!.cancel(); + cancelToken = null; + } + isDownloading.value = false; + downloadProgress.value = 0.0; + downloadStatus.value = '下载已取消'; + } + + void errorDownload(String error) { + isDownloading.value = false; + downloadStatus.value = '下载失败: $error'; + } +} + class MainPageBottomChange extends GetView { GlobalController globalController = Get.find(); ThemeController themeController = Get.find(); @@ -304,6 +86,10 @@ class MainPageBottomChange extends GetView { late final List bottomItems; DateTime? _lastBackPressedTime; LanguageController languageController = Get.find(); + bool select = false; // 是否已经提示过升级弹窗 + + // 使用GetX Controller来管理下载状态 + final DownloadController downloadController = Get.put(DownloadController()); MainPageBottomChange({super.key}) { // ✅ 根据是否测试账号动态生成页面 @@ -344,6 +130,393 @@ class MainPageBottomChange extends GetView { } } + // iOS跳转AppStore方法 + Future _openAppStore() async { + const appStoreId = '6746246837'; // 你的 App ID + + // 优先尝试使用 App Store 应用打开 + final directUrl = + Uri.parse('itms-apps://itunes.apple.com/app/id$appStoreId'); + final webUrl = Uri.parse('https://apps.apple.com/app/id$appStoreId'); + + try { + // 使用新版本的 canLaunchUrl 和 launchUrl + if (await canLaunchUrl(directUrl)) { + await launchUrl( + directUrl, + mode: LaunchMode.externalApplication, // 重要:使用外部应用打开 + ); + } else if (await canLaunchUrl(webUrl)) { + // 备用:使用网页版 + await launchUrl( + webUrl, + mode: LaunchMode.externalApplication, + ); + } else { + // 如果都无法打开 + NewTopSlideNotification.show( + text: "无法打开AppStore链接".tr, + textColor: themeController.currentColor.sc9, + ); + } + } catch (e) { + print('打开 App Store 失败: $e'); + NewTopSlideNotification.show( + text: "打开AppStore失败".tr, + textColor: themeController.currentColor.sc9, + ); + } + } + + // 检查并请求存储权限(Android) + Future _requestStoragePermission() async { + return true; + if (!Platform.isAndroid) return true; + + var status = await Permission.storage.status; + if (!status.isGranted) { + status = await Permission.storage.request(); + } + + if (Platform.isAndroid && status.isGranted) { + // Android 11及以上需要请求管理外部存储权限 + if (await Permission.manageExternalStorage.isRestricted) { + status = await Permission.manageExternalStorage.request(); + } + } + + return status.isGranted; + } + + // 下载APK文件 + Future _downloadApk({ + required String url, + required String version, + }) async { + try { + // 请求存储权限 + bool hasPermission = await _requestStoragePermission(); + if (!hasPermission) { + downloadController.errorDownload("需要存储权限才能下载应用更新"); + NewTopSlideNotification.show( + text: "需要存储权限才能下载应用更新".tr, + textColor: themeController.currentColor.sc9); + return; + } + + // 创建下载目录 + Directory? externalDir = await getExternalStorageDirectory(); + String downloadDir = '${externalDir!.path}/Download'; + + // 确保目录存在 + await Directory(downloadDir).create(recursive: true); + + // 生成文件名 + String fileName = 'app_update_$version.apk'; + String filePath = '$downloadDir/$fileName'; + + // 如果文件已存在,先删除 + File existingFile = File(filePath); + if (await existingFile.exists()) { + await existingFile.delete(); + } + + // 创建Dio实例 + Dio dio = Dio(); + downloadController.cancelToken = CancelToken(); + downloadController.startDownload(); + + // 开始下载 + try { + await dio.download( + url, + filePath, + cancelToken: downloadController.cancelToken, + onReceiveProgress: (received, total) { + if (total != -1) { + double progress = received / total; + downloadController.updateProgress(progress); + } + }, + options: Options( + headers: { + 'User-Agent': 'Dart/2.18 (dart:io)', + }, + receiveTimeout: const Duration(minutes: 5), + ), + ); + } catch (e) { + ef.log("msg"); + } + + downloadController.completeDownload(filePath); + } catch (e) { + if (e is DioException && e.type == DioExceptionType.cancel) { + downloadController.errorDownload("下载已取消"); + } else { + downloadController.errorDownload("下载失败: ${e.toString()}"); + } + NewTopSlideNotification.show( + text: "服务器错误,请稍后再试".tr, textColor: themeController.currentColor.sc9); + } finally { + downloadController.cancelToken = null; + } + } + + // 安装APK文件(Android) + Future _installApk(String filePath) async { + if (!Platform.isAndroid) return; + + try { + // Android 8.0+ 需要「允许安装未知来源应用」权限 + var status = await Permission.requestInstallPackages.status; + if (!status.isGranted) { + status = await Permission.requestInstallPackages.request(); + if (!status.isGranted) { + Get.snackbar("权限被拒绝", "需要安装应用的权限"); + return; + } + } + + // 使用 open_file 打开 APK(系统安装器) + final result = await OpenFile.open( + filePath, + type: "application/vnd.android.package-archive", + ); + + if (result.type == ResultType.done) { + // Get.snackbar("提示", "正在打开安装程序..."); + } else { + Get.defaultDialog( + title: "安装提示".tr, + middleText: "无法自动安装,请手动安装\n路径:\n$filePath".tr, + textConfirm: "确定".tr, + onConfirm: () => Get.back(), + ); + } + } catch (e) { + // Get.snackbar("安装失败", "错误: $e\n请手动安装: $filePath"); + // SystemNavigator.pop(); + } + } + + // 显示更新对话框 + void _showUpdateDialog( + BuildContext context, + String newVersion, + String updateContent, + String updateUrl, + ) { + select = true; + + // 使用Obx来包装对话框内容 + Get.dialog( + WillPopScope( + onWillPop: () async => false, // 禁止返回键关闭 + child: FrostedDialog( + blurSigma: 3.0, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0), + ), + padding: EdgeInsetsDirectional.fromSTEB(64.rpx, 0, 64.rpx, 0), + child: Container( + width: double.infinity, + constraints: BoxConstraints( + maxHeight: MediaQuery.sizeOf(context).height * 0.656, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 使用Obx监听下载状态 + Obx(() { + return Align( + alignment: AlignmentDirectional(0, 0), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.rpx, 93.rpx, 0, 74.rpx), + child: Column( + children: [ + /// 上半部分:居中对齐 + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 94.rpx, + height: 70.rpx, + child: SvgPicture.asset( + 'assets/img/icon/upgrade.svg', + fit: BoxFit.cover, + ), + ), + SizedBox(height: 37.rpx), + Text( + downloadController.isDownloading.value + ? "正在下载更新...".tr + : "检测到新版本!".tr, + style: TextStyle( + color: stringToColor("#333333"), + fontSize: + AppConstants().title_text_fontSize, + ), + ), + ], + ), + + SizedBox(height: 37.rpx), + + /// 显示下载进度 + if (downloadController.isDownloading.value) + Column( + children: [ + LinearProgressIndicator( + value: downloadController + .downloadProgress.value, + backgroundColor: Colors.grey[200], + valueColor: AlwaysStoppedAnimation( + Colors.blue), + ), + SizedBox(height: 10), + Text( + downloadController.downloadStatus.value, + style: TextStyle( + fontSize: 14, + color: Colors.grey[600], + ), + ), + SizedBox(height: 20), + ], + ), + + /// 更新信息 + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("当前版本号".tr + + ":" + + AppConstants.theh_app_version), + Text("升级后版本".tr + ":" + newVersion), + SizedBox(height: 10), + Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(8), + ), + child: Text( + "升级内容".tr + ":" + updateContent, + style: TextStyle( + fontSize: 14, + color: Colors.grey[700], + ), + ), + ), + ], + ), + ], + ), + ), + ); + }), + + // 按钮区域 + Padding( + padding: + EdgeInsetsDirectional.fromSTEB(0, 19.rpx, 0, 60.rpx), + child: Obx(() { + return Column( + children: [ + // 主要按钮(升级/下载按钮) + CustomCard( + gradientDirection: GradientDirection.vertical, + borderRadius: + AppConstants().button_container_radius, + onTap: () async { + if (Platform.isIOS) { + // 跳转AppStore + await _openAppStore(); + Get.back(); + } else if (!downloadController + .isDownloading.value) { + // 开始下载 + _downloadApk( + url: updateUrl, + version: newVersion, + ); + } + }, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + child: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height * 0.055, + constraints: BoxConstraints( + minWidth: 500.rpx, + minHeight: 90.rpx, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + downloadController.isDownloading.value + ? "下载中...".tr + : Platform.isIOS + ? "前往AppStore".tr + : "升级".tr, + style: TextStyle( + color: Colors.white, + fontFamily: 'Inter', + fontSize: + AppConstants().normal_text_fontSize, + letterSpacing: 0.0, + ), + ), + ].divide(SizedBox(width: 17.rpx)), + ), + ), + ), + ], + ); + }), + ), + ], + ), + ), + ), + ), + ), + ); + + // 监听下载完成 + ever(downloadController.isDownloading, (isDownloading) async { + if (!isDownloading && downloadController.downloadProgress.value >= 1.0) { + // 下载完成,关闭对话框并安装 + Get.back(); + // Get.defaultDialog( + // title: "下载完成".tr, + // middleText: "新版本已下载完成,是否立即安装?".tr, + // textConfirm: "安装".tr, + // textCancel: "稍后".tr, + // onConfirm: () { + // Get.back(); + // _installApk(downloadController.downloadFilePath!); + // }, + // onCancel: () { + // Get.back(); + // Get.snackbar( + // "提示", "安装文件保存在: ${downloadController.downloadFilePath}"); + // }, + // ); + await Future.delayed(Duration(milliseconds: 2000)); + _installApk(downloadController.downloadFilePath!); + } + }); + } + getBottomNavigationBarItem(String svgPath, String actSvgPath, String label, {double size = 0, bool isEmpty = false, bool showBadge = false}) { if (size == 0) size = 36.rpx; @@ -402,13 +575,62 @@ class MainPageBottomChange extends GetView { showCustomConfirmOfWebViewDialog(context, "隐私协议".tr, getPrivacy(1), btnName: btnName, showCancel: true, cancelName: cancelName) - .then((e) { + .then((e) async { if (e == "confirm") { getStorage.write("isShowYingShiDialog", "true"); + await Future.delayed(const Duration(milliseconds: 1000)); + if (select != true) { + // 判断APP是否需要更新 + UserInfoController userInfoController = Get.find(); + userInfoController + .checkAPPUpdate(AppConstants.theh_app_version) + .then((data) { + if (data != null) { + if (data['update'] != null && data['update'] == true) { + // 需要更新 + String updateUrl = data['file']['path']; + String currentVersion = AppConstants.theh_app_version; + String newVersion = data['file']['version'] ?? "1.2.0"; + String updateContent = + data['file']['desc'] ?? "修复已知bug".tr; + try { + _showUpdateDialog( + context, newVersion, updateContent, updateUrl); + } catch (e) { + ef.log("更新对话框显示失败: $e"); + } + } + } + }); + } } else { if (cancelName == "退出") SystemNavigator.pop(); } }); + } else { + if (select != true) { + // 判断APP是否需要更新 + UserInfoController userInfoController = Get.find(); + userInfoController + .checkAPPUpdate(AppConstants.theh_app_version) + .then((data) { + if (data != null) { + if (data['update'] != null && data['update'] == true) { + // 需要更新 + String updateUrl = data['file']['path']; + String currentVersion = AppConstants.theh_app_version; + String newVersion = data['file']['version'] ?? "1.2.0"; + String updateContent = data['file']['desc'] ?? "修复已知bug".tr; + try { + _showUpdateDialog( + context, newVersion, updateContent, updateUrl); + } catch (e) { + ef.log("更新对话框显示失败: $e"); + } + } + } + }); + } } }); } @@ -425,9 +647,6 @@ class MainPageBottomChange extends GetView { return; } - // if (Platform.isAndroid) { - // Get.back(); - // } if (Platform.isAndroid) { var flag = await _handleBackPressed(context); if (flag) { diff --git a/lib/pages/mh_page/component/mht_bind_dialog.dart b/lib/pages/mh_page/component/mht_bind_dialog.dart index ae3e7c0..50e3c3a 100644 --- a/lib/pages/mh_page/component/mht_bind_dialog.dart +++ b/lib/pages/mh_page/component/mht_bind_dialog.dart @@ -1221,3 +1221,137 @@ Future showTipUpgradeDialog( }, ); } + +Future showAPPUpgradeDialog( + BuildContext context, + Widget widget, { + Color? backgroundColor, + required VoidCallback onUpgradeTap, + String? secondaryButtonText, // 👈 新增:次要按钮文本 + VoidCallback? onSecondaryTap, // 👈 新增:次要按钮点击回调 +}) { + ThemeController themeController = Get.find(); + BlueteethBindController blueteethBindController = Get.find(); + + return showDialog( + context: context, + barrierDismissible: false, + barrierColor: Colors.black.withOpacity(0.5), + builder: (BuildContext context) { + return WillPopScope( + child: FrostedDialog( + blurSigma: 3.0, + child: Container( + decoration: BoxDecoration( + color: backgroundColor ?? Colors.white, + borderRadius: BorderRadius.circular(8.0), + ), + padding: EdgeInsetsDirectional.fromSTEB(64.rpx, 0, 64.rpx, 0), + child: Container( + width: double.infinity, + constraints: BoxConstraints( + maxHeight: MediaQuery.sizeOf(context).height * 0.656, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: AlignmentDirectional(0, 0), + child: Padding( + padding: EdgeInsetsDirectional.fromSTEB( + 0.rpx, 93.rpx, 0, 74.rpx), + child: widget, + ), + ), + + // 👇 修改按钮布局,支持两个按钮 + Padding( + padding: + EdgeInsetsDirectional.fromSTEB(0, 19.rpx, 0, 60.rpx), + child: Column( + children: [ + // 主要按钮(升级按钮) + CustomCard( + gradientDirection: GradientDirection.vertical, + borderRadius: AppConstants().button_container_radius, + onTap: onUpgradeTap, + colors: [ + themeController.currentColor.sc1, + themeController.currentColor.sc2, + ], + child: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height * 0.055, + constraints: BoxConstraints( + minWidth: 500.rpx, + minHeight: 90.rpx, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '升级'.tr, + style: TextStyle( + color: Colors.white, + fontFamily: 'Inter', + fontSize: + AppConstants().normal_text_fontSize, + letterSpacing: 0.0, + ), + ), + ].divide(SizedBox(width: 17.rpx)), + ), + ), + ), + + // 如果有次要按钮,显示次要按钮 + // if (secondaryButtonText != null && onSecondaryTap != null) + // Padding( + // padding: EdgeInsets.only(top: 20.rpx), + // child: CustomCard( + // gradientDirection: GradientDirection.vertical, + // borderRadius: AppConstants().button_container_radius, + // onTap: onSecondaryTap, + // colors: [ + // Colors.grey[300]!, + // Colors.grey[400]!, + // ], + // child: Container( + // width: MediaQuery.sizeOf(context).width, + // height: MediaQuery.sizeOf(context).height * 0.055, + // constraints: BoxConstraints( + // minWidth: 500.rpx, + // minHeight: 90.rpx, + // ), + // child: Row( + // mainAxisSize: MainAxisSize.max, + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text( + // secondaryButtonText, + // style: TextStyle( + // color: Colors.white, + // fontFamily: 'Inter', + // fontSize: AppConstants().normal_text_fontSize, + // letterSpacing: 0.0, + // ), + // ), + // ].divide(SizedBox(width: 17.rpx)), + // ), + // ), + // ), + // ), + ], + ), + ), + ], + ), + ), + ), + ), + onWillPop: () async => false, + ); + }, + ); +} diff --git a/lib/pages/mh_page/device/mht_bind_device_type.dart b/lib/pages/mh_page/device/mht_bind_device_type.dart index 1a68ef8..5dc2f69 100644 --- a/lib/pages/mh_page/device/mht_bind_device_type.dart +++ b/lib/pages/mh_page/device/mht_bind_device_type.dart @@ -150,7 +150,7 @@ class _MHTBindDeviceTypePageState extends State { Widget _buildDeviceCard(BuildContext context, {required String title, required String imageUrl, - required double type, + required int type, required List? desc, required List? reg}) { if (type == 1) { diff --git a/lib/pages/sleep_report/new_sleep_report_page.dart b/lib/pages/sleep_report/new_sleep_report_page.dart index 2d05c6b..7fbf6be 100644 --- a/lib/pages/sleep_report/new_sleep_report_page.dart +++ b/lib/pages/sleep_report/new_sleep_report_page.dart @@ -437,7 +437,7 @@ class _NewSleepReportPageState extends State { ? widget .data['person']!['name'] .toString() - : '未知数据'.tr, + : '体征检测设备'.tr, themeController: themeController, ), // SizedBox(height: 34.rpx), @@ -843,7 +843,7 @@ class _NewSleepReportPageState extends State { ], ), ), - ), + ), Obx(() { if (sleepReportController.isLoading.value) { return Center( diff --git a/pubspec.yaml b/pubspec.yaml index ea10f00..e52ab25 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,6 +86,9 @@ dependencies: git: url: https://gitea.wslpc.real.he-info.cn:94/flutter/mhtctrl.git ref: main + open_file: ^3.5.11 + device_info_plus: ^10.0.0 + dev_dependencies: flutter_test: