更新首页数据滚动效果

This commit is contained in:
wyf
2026-01-12 15:16:36 +08:00
parent 0ef8ddee8a
commit e841ee887a
19 changed files with 1160 additions and 400 deletions

View File

@@ -108,7 +108,7 @@
"人员资料": { "人员资料": {
"标题": "User Information", "标题": "User Information",
"保存": "Save", "保存": "Save",
"名字输入提示": "User name (required)", "名字输入提示": "User name",
"生日输入提示": "Birthday (required)", "生日输入提示": "Birthday (required)",
"体重输入提示": "Weight kg (required)", "体重输入提示": "Weight kg (required)",
"疾病标题": "Chronic disease management", "疾病标题": "Chronic disease management",
@@ -628,5 +628,13 @@
"请检查网络连接后重试": "Please check the network connection and try again", "请检查网络连接后重试": "Please check the network connection and try again",
"开始": "startTime", "开始": "startTime",
"结束": "endTime", "结束": "endTime",
"时长": "duration" "时长": "duration",
"检测到新版本!": "New version detected!",
"正在下载更新...": "Downloading update...",
"当前版本号": "Current version",
"升级后版本": "Updated version",
"升级内容": "Update content",
"升级": "Upgrade",
"前往AppStore": "Go to AppStore",
"下载中...": "Downloading..."
} }

View File

@@ -108,7 +108,7 @@
"人员资料": { "人员资料": {
"标题": "人员资料", "标题": "人员资料",
"保存": "保存", "保存": "保存",
"名字输入提示": "使用人员姓名(必填)", "名字输入提示": "使用人员姓名",
"生日输入提示": "生日(必填)", "生日输入提示": "生日(必填)",
"体重输入提示": "体重kg(必填)", "体重输入提示": "体重kg(必填)",
"疾病标题": "慢病管理", "疾病标题": "慢病管理",
@@ -628,5 +628,13 @@
"隐私协议加载失败": "隐私协议加载失败", "隐私协议加载失败": "隐私协议加载失败",
"请检查网络连接后重试": "请检查网络连接后重试", "请检查网络连接后重试": "请检查网络连接后重试",
"开始": "开始", "开始": "开始",
"结束": "结束" "结束": "结束",
"检测到新版本!": "检测到新版本!",
"正在下载更新...": "正在下载更新...",
"当前版本号": "当前版本号",
"升级后版本": "升级后版本",
"升级内容": "升级内容",
"升级": "升级",
"前往AppStore": "前往AppStore",
"下载中...": "下载中..."
} }

View File

@@ -108,7 +108,7 @@
"人员资料": { "人员资料": {
"标题": "人員資料", "标题": "人員資料",
"保存": "保存", "保存": "保存",
"名字输入提示": "使用人員姓名(必填)", "名字输入提示": "使用人員姓名",
"生日输入提示": "生日(必填)", "生日输入提示": "生日(必填)",
"体重输入提示": "體重kg(必填)", "体重输入提示": "體重kg(必填)",
"疾病标题": "慢病管理", "疾病标题": "慢病管理",
@@ -626,5 +626,13 @@
"请检查网络连接后重试": "請檢查網絡連接後重試", "请检查网络连接后重试": "請檢查網絡連接後重試",
"开始": "開始", "开始": "開始",
"结束": "結束", "结束": "結束",
"时长": "時長:" "时长": "時長:",
"检测到新版本!": "檢測到新版本!",
"正在下载更新...": "正在下載更新...",
"当前版本号": "目前版本號",
"升级后版本": "升級後版本",
"升级内容": "升級內容",
"升级": "升級",
"前往AppStore": "前往AppStore",
"下载中...": "下載中..."
} }

View File

@@ -61,4 +61,7 @@ class ServiceConstant {
"https://vsbst-api.he-info.cn/vsbs_sotrage/background-image/taihe.png"; "https://vsbst-api.he-info.cn/vsbs_sotrage/background-image/taihe.png";
static const String localTimeZone = static const String localTimeZone =
"/api/city/data/utc/info"; "/api/city/data/utc/info";
//todo 检查app更新
static const String checkAPPVersion =
"/api/app/update/check";
} }

View File

@@ -9,7 +9,7 @@ class AppConstants {
// App-related constants // App-related constants
static const String zhmht_app_version = "SWES_1.2026.1.8";//眠花糖 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. 纯字符串列表格式 // 1. 纯字符串列表格式
static const List<String> integerTimeZones = [ static const List<String> integerTimeZones = [

View File

@@ -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/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/NewTopSlideNotification.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart'; import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/home/home_controller.dart'; import 'package:vbvs_app/controller/home/home_controller.dart';
@@ -47,6 +48,7 @@ class UserInfoModel {
String? img_bucket = 'user'; String? img_bucket = 'user';
int? login = 0; //0未登录 1 登录 int? login = 0; //0未登录 1 登录
int? deviceBindNum = 0; //绑定设备数量 int? deviceBindNum = 0; //绑定设备数量
int? loginPhone = 0; //0 本机号码 1其他手机号 int? loginPhone = 0; //0 本机号码 1其他手机号
@@ -73,6 +75,7 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
int initLocationpermission = 0; //未初始化 int initLocationpermission = 0; //未初始化
FluwxCancelable? fluwxCancelable; FluwxCancelable? fluwxCancelable;
final Fluwx fluwx = Fluwx(); final Fluwx fluwx = Fluwx();
// RxInt login = 0.obs; //0未登录 1 登录
List<Map<String, String>> country_code = [ List<Map<String, String>> country_code = [
{ {
@@ -86,7 +89,7 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
]; ];
RxString select_country_code = "+86".obs; RxString select_country_code = "+86".obs;
RxInt select_login_method = 1.obs;//1手机 2邮箱 RxInt select_login_method = 1.obs; //1手机 2邮箱
Future<ApiResponse> uploadImg() async { Future<ApiResponse> uploadImg() async {
EasyDartModule.logger.info("请求上传图片"); EasyDartModule.logger.info("请求上传图片");
@@ -386,4 +389,42 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
ef.log("微信解绑失败-》$e"); 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;
}
} }

View File

@@ -367,7 +367,13 @@ class _DeviceDetailPageState extends State<DeviceDetailPage> {
alignment: alignment:
AlignmentDirectional(-1.rpx, 0.rpx), AlignmentDirectional(-1.rpx, 0.rpx),
child: Text( child: Text(
'${widget.device['person']?['name'] ?? '未命名'.tr}', ((widget.device['person']?['name']
as String?)
?.trim()
.isNotEmpty ??
false)
? widget.device['person']['name']
: '体征检测设备'.tr,
style: TextStyle( style: TextStyle(
fontFamily: 'Inter', fontFamily: 'Inter',
fontSize: 26.rpx, fontSize: 26.rpx,

View File

@@ -335,7 +335,19 @@ class _InstantBodyPageState extends State<InstantBodyPage>
.width * .width *
0.2, 0.2,
child: Text( 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( style: TextStyle(
fontFamily: 'Inter', fontFamily: 'Inter',
fontSize: 26.rpx, fontSize: 26.rpx,

View File

@@ -147,7 +147,14 @@ class _MessageReviewPageState extends State<MessageReviewPage> {
.width * .width *
0.2, 0.2,
child: Text( child: Text(
'${widget.data['person']?['name'] ?? '未命名'.tr}', ((widget.data['person']?['name']
as String?)
?.trim()
.isNotEmpty ??
false)
? widget.data['person']
['name']
: '体征检测设备'.tr,
style: TextStyle( style: TextStyle(
fontFamily: 'Inter', fontFamily: 'Inter',
fontSize: 26.rpx, fontSize: 26.rpx,

View File

@@ -128,14 +128,29 @@ class _DeviceSharePageState extends State<DeviceSharePage> {
deviceShareController.updateAll(); deviceShareController.updateAll();
}, },
)), )),
Text( Expanded(
'主设备'.tr + child: Text(
"${device['person']?['name'] == null ? '未命名'.tr : device['person']['name']}", '主设备'.tr +
style: TextStyle( (device['person'] != null &&
fontFamily: 'Inter', device['person'] is Map &&
fontSize: 26.rpx, device['person']['name'] !=
letterSpacing: 0.0, null &&
color: themeController.currentColor.sc3, 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)), ].divide(SizedBox(width: 20.rpx)),
@@ -216,7 +231,9 @@ class _DeviceSharePageState extends State<DeviceSharePage> {
height: height:
33.rpx * 33.rpx *
0.6, 0.6,
color: themeController.currentColor.sc2, color: themeController
.currentColor
.sc2,
), ),
), ),
) )

View File

@@ -728,8 +728,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
weatherModelController = Get.find(); weatherModelController = Get.find();
await weatherModelController await weatherModelController
.getCurrentLocation(); .getCurrentLocation();
// await weatherModelController await weatherModelController
// .getCurrentWeather(); .getCurrentWeather();
} }
} }
} catch (e) { } catch (e) {

View File

@@ -103,35 +103,6 @@ class _EPageState extends State<EPage> 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<bool>(
// valueListenable: isPageLoading,
// builder: (context, isLoading, child) {
// return isLoading
// ? Center(child: CircularProgressIndicator())
// : SizedBox.shrink();
// },
// ),
// ],
// );
// });
// }
Widget _buildLoggedInContent() { Widget _buildLoggedInContent() {
return Obx(() { return Obx(() {
if (finalUri.isEmpty) { if (finalUri.isEmpty) {
@@ -233,7 +204,7 @@ class _EPageState extends State<EPage> with AutomaticKeepAliveClientMixin {
item['person']['name'] != null && item['person']['name'] != null &&
item['person']['name'].toString().trim().isNotEmpty) item['person']['name'].toString().trim().isNotEmpty)
? item['person']['name'] + "_${mac}" ? item['person']['name'] + "_${mac}"
: '未命名'.tr + "_${mac}"; : '体征检测设备'.tr + "_${mac}";
return { return {
'mac': mac, 'mac': mac,
'name': name, 'name': name,
@@ -274,71 +245,4 @@ class _EPageState extends State<EPage> with AutomaticKeepAliveClientMixin {
ef.log(e.toString()); ef.log(e.toString());
} }
} }
// Future<void> 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<dynamic> 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<Map<String, dynamic>> newList =
// rawList.whereType<Map>().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());
// }
// }
} }

View File

@@ -1,3 +1,4 @@
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
import 'package:ef/ef.dart'; import 'package:ef/ef.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
@@ -184,7 +185,7 @@ class _HomePageState extends State<HomePage> {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (userInfoController.model.login == 1) { if (userInfoController.model.login == 1) {
homeController.getSleepReport(); // deviceController.getSleepReport();
deviceController.getDeviceNum().then((apiResponse) { deviceController.getDeviceNum().then((apiResponse) {
if (apiResponse.code != HttpStatusCodes.ok) { if (apiResponse.code != HttpStatusCodes.ok) {
TopSlideNotification.show( TopSlideNotification.show(
@@ -203,7 +204,9 @@ class _HomePageState extends State<HomePage> {
); );
} else { } else {
//请求睡眠报告 //请求睡眠报告
deviceController.getSleepReport(); deviceController.getSleepReport().then((value) {
homeController.updateAll();
});
} }
}); });
} }
@@ -1006,7 +1009,13 @@ class _HomePageState extends State<HomePage> {
Map<String, List<dynamic>> reportData = Map<String, List<dynamic>> reportData =
deviceController.sleepReportData.value; deviceController.sleepReportData.value;
var deviceList = deviceController.deviceList.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(); .toList();
if (deviceList.isEmpty) { if (deviceList.isEmpty) {
return Expanded(child: NullDataWidget()); return Expanded(child: NullDataWidget());
@@ -1022,11 +1031,30 @@ class _HomePageState extends State<HomePage> {
) )
.toList(); .toList();
if (macList.length != deviceList.length) { 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( return Expanded(
child: Center( child: Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: themeController.currentColor.sc1, 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),
// )
// ],
// ),
); );
} }

View File

@@ -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<MainPageController> {
GlobalController globalController = Get.find();
ThemeController themeController = Get.find();
MessageController messageController = Get.find();
final getStorage = GetStorage();
late final List<Widget> arr;
late final List<BottomNavigationBarItem> 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<bool> _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;
}
}
}

View File

@@ -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<MainPageController> {
// 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<Widget> 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<bool> _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:async';
import 'dart:io'; import 'dart:io';
// 添加新的导入
import 'package:dio/dio.dart';
import 'package:ef/ef.dart'; import 'package:ef/ef.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:get_storage/get_storage.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/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.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/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.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/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/message_page.dart';
import 'package:vbvs_app/pages/main_bottom/mine_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<MainPageController> { class MainPageBottomChange extends GetView<MainPageController> {
GlobalController globalController = Get.find(); GlobalController globalController = Get.find();
ThemeController themeController = Get.find(); ThemeController themeController = Get.find();
@@ -304,6 +86,10 @@ class MainPageBottomChange extends GetView<MainPageController> {
late final List<BottomNavigationBarItem> bottomItems; late final List<BottomNavigationBarItem> bottomItems;
DateTime? _lastBackPressedTime; DateTime? _lastBackPressedTime;
LanguageController languageController = Get.find(); LanguageController languageController = Get.find();
bool select = false; // 是否已经提示过升级弹窗
// 使用GetX Controller来管理下载状态
final DownloadController downloadController = Get.put(DownloadController());
MainPageBottomChange({super.key}) { MainPageBottomChange({super.key}) {
// ✅ 根据是否测试账号动态生成页面 // ✅ 根据是否测试账号动态生成页面
@@ -344,6 +130,393 @@ class MainPageBottomChange extends GetView<MainPageController> {
} }
} }
// iOS跳转AppStore方法
Future<void> _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<bool> _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<void> _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<void> _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<Color>(
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, getBottomNavigationBarItem(String svgPath, String actSvgPath, String label,
{double size = 0, bool isEmpty = false, bool showBadge = false}) { {double size = 0, bool isEmpty = false, bool showBadge = false}) {
if (size == 0) size = 36.rpx; if (size == 0) size = 36.rpx;
@@ -402,13 +575,62 @@ class MainPageBottomChange extends GetView<MainPageController> {
showCustomConfirmOfWebViewDialog(context, "隐私协议".tr, getPrivacy(1), showCustomConfirmOfWebViewDialog(context, "隐私协议".tr, getPrivacy(1),
btnName: btnName, showCancel: true, cancelName: cancelName) btnName: btnName, showCancel: true, cancelName: cancelName)
.then((e) { .then((e) async {
if (e == "confirm") { if (e == "confirm") {
getStorage.write("isShowYingShiDialog", "true"); 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 { } else {
if (cancelName == "退出") SystemNavigator.pop(); 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<MainPageController> {
return; return;
} }
// if (Platform.isAndroid) {
// Get.back();
// }
if (Platform.isAndroid) { if (Platform.isAndroid) {
var flag = await _handleBackPressed(context); var flag = await _handleBackPressed(context);
if (flag) { if (flag) {

View File

@@ -1221,3 +1221,137 @@ Future<void> showTipUpgradeDialog(
}, },
); );
} }
Future<void> 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,
);
},
);
}

View File

@@ -150,7 +150,7 @@ class _MHTBindDeviceTypePageState extends State<MHTBindDeviceTypePage> {
Widget _buildDeviceCard(BuildContext context, Widget _buildDeviceCard(BuildContext context,
{required String title, {required String title,
required String imageUrl, required String imageUrl,
required double type, required int type,
required List<dynamic>? desc, required List<dynamic>? desc,
required List<dynamic>? reg}) { required List<dynamic>? reg}) {
if (type == 1) { if (type == 1) {

View File

@@ -437,7 +437,7 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
? widget ? widget
.data['person']!['name'] .data['person']!['name']
.toString() .toString()
: '未知数据'.tr, : '体征检测设备'.tr,
themeController: themeController, themeController: themeController,
), ),
// SizedBox(height: 34.rpx), // SizedBox(height: 34.rpx),

View File

@@ -86,6 +86,9 @@ dependencies:
git: git:
url: https://gitea.wslpc.real.he-info.cn:94/flutter/mhtctrl.git url: https://gitea.wslpc.real.he-info.cn:94/flutter/mhtctrl.git
ref: main ref: main
open_file: ^3.5.11
device_info_plus: ^10.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: