1.更新消息阅读时间
2.修复配置wifi时wifi名称存在空格时配置失败 3.修复门店体验列表刷新失败
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:get_storage/get_storage.dart';
|
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/controller/login/login_controller.dart';
|
|
||||||
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
static Dio dio = Dio();
|
static Dio dio = Dio();
|
||||||
@@ -15,32 +12,35 @@ class ApiService {
|
|||||||
static Dio reservation = Dio();
|
static Dio reservation = Dio();
|
||||||
|
|
||||||
static void init() {
|
static void init() {
|
||||||
|
|
||||||
reservationInit();
|
reservationInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reservationInit() {
|
static void reservationInit() {
|
||||||
reservation.options.baseUrl = "https://crm-api.swes.com.cn";
|
try {
|
||||||
reservation.options.connectTimeout = const Duration(seconds: 15);
|
reservation.options.baseUrl = "https://crm-api.swes.com.cn";
|
||||||
reservation.options.receiveTimeout = const Duration(seconds: 10);
|
reservation.options.connectTimeout = const Duration(seconds: 15);
|
||||||
reservation.options.sendTimeout = const Duration(seconds: 10);
|
reservation.options.receiveTimeout = const Duration(seconds: 10);
|
||||||
reservation.interceptors.add(InterceptorsWrapper(
|
reservation.options.sendTimeout = const Duration(seconds: 10);
|
||||||
onRequest: (options, handler) {
|
reservation.interceptors.add(InterceptorsWrapper(
|
||||||
print("---> ${options.method}, ${options.path}, ${options.data}");
|
onRequest: (options, handler) {
|
||||||
options.headers['token'] =
|
print("---> ${options.method}, ${options.path}, ${options.data}");
|
||||||
"bMAQVR1x48t66u8EDYSftAJGo17r0rIB3z15JgyyoGz1rAEZHs1htHOCorYFJ2RT";
|
options.headers['token'] =
|
||||||
return handler.next(options);
|
"bMAQVR1x48t66u8EDYSftAJGo17r0rIB3z15JgyyoGz1rAEZHs1htHOCorYFJ2RT";
|
||||||
},
|
return handler.next(options);
|
||||||
onResponse: (response, ResponseInterceptorHandler handler) {
|
},
|
||||||
print("<--- ${response.statusCode} ${response.data}");
|
onResponse: (response, ResponseInterceptorHandler handler) {
|
||||||
return handler.next(response);
|
print("<--- ${response.statusCode} ${response.data}");
|
||||||
},
|
return handler.next(response);
|
||||||
onError: (e, handler) {
|
},
|
||||||
// 错误处理,例如打印错误信息
|
onError: (e, handler) {
|
||||||
showToast("网络异常或服务连接异常,请稍候再试", color: color_error);
|
// 错误处理,例如打印错误信息
|
||||||
print("DioError: $e");
|
showToast("网络异常或服务连接异常,请稍候再试", color: color_error);
|
||||||
return handler.reject(e);
|
print("DioError: $e");
|
||||||
},
|
return handler.reject(e);
|
||||||
));
|
},
|
||||||
|
));
|
||||||
|
} catch (e) {
|
||||||
|
ef.log("$e");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ Future<ApiResponse> requestWithLog({
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
EasyDartModule.logger.error("$logTitle 失败->$e");
|
EasyDartModule.logger.error("$logTitle 失败->$e");
|
||||||
DailyLogUtils.writeError("$logTitle 失败->$e");
|
DailyLogUtils.writeError("$logTitle 失败->$e");
|
||||||
onFailure?.call(apiResponse);
|
|
||||||
apiResponse.msg = e.toString();
|
apiResponse.msg = e.toString();
|
||||||
|
onFailure?.call(apiResponse);
|
||||||
return apiResponse;
|
return apiResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
|||||||
// wifi列表指令
|
// wifi列表指令
|
||||||
getWifiList(THapp tHapp) async {
|
getWifiList(THapp tHapp) async {
|
||||||
try {
|
try {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
print("wscan scan");
|
print("wscan scan");
|
||||||
edm.EasyDartModule.logger.info("发送请求网络列表指令");
|
edm.EasyDartModule.logger.info("发送请求网络列表指令");
|
||||||
DailyLogUtils.writeLog("发送请求网络列表指令");
|
DailyLogUtils.writeLog("发送请求网络列表指令");
|
||||||
@@ -54,7 +54,7 @@ getWifiList(THapp tHapp) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getWifiStatus(THapp tHapp) async {
|
getWifiStatus(THapp tHapp) async {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("发送请求设备网络状态指令");
|
edm.EasyDartModule.logger.info("发送请求设备网络状态指令");
|
||||||
DailyLogUtils.writeLog("发送请求设备网络状态指令");
|
DailyLogUtils.writeLog("发送请求设备网络状态指令");
|
||||||
var result = await tHapp.send(
|
var result = await tHapp.send(
|
||||||
@@ -85,7 +85,7 @@ getWifiStatus(THapp tHapp) async {
|
|||||||
|
|
||||||
Future<bool> sendWifiSetting(wifiItem, String password, THapp tHapp) async {
|
Future<bool> sendWifiSetting(wifiItem, String password, THapp tHapp) async {
|
||||||
try {
|
try {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("发送wifi配置指令");
|
edm.EasyDartModule.logger.info("发送wifi配置指令");
|
||||||
DailyLogUtils.writeLog("发送wifi配置指令->");
|
DailyLogUtils.writeLog("发送wifi配置指令->");
|
||||||
// String cmd = "vtouch save update -a -i .wifi.sta.auth=${wifiItem['auth']} "
|
// String cmd = "vtouch save update -a -i .wifi.sta.auth=${wifiItem['auth']} "
|
||||||
@@ -132,7 +132,7 @@ getDeviceWifiStatus(
|
|||||||
edm.EasyDartModule.logger.info("[aaa:配置开始]发送请求设备已配置网络状态指令:${currenttIme}");
|
edm.EasyDartModule.logger.info("[aaa:配置开始]发送请求设备已配置网络状态指令:${currenttIme}");
|
||||||
ef.log("[aaa:配置开始]:${currenttIme}");
|
ef.log("[aaa:配置开始]:${currenttIme}");
|
||||||
var stream = tHapp.logingStream.listen((data) {
|
var stream = tHapp.logingStream.listen((data) {
|
||||||
ef.log("[设备日志]:${data}");
|
ef.log("[设备日志1]:${data}");
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
var result = await tHapp.send("at+system info", true, (ss) {
|
var result = await tHapp.send("at+system info", true, (ss) {
|
||||||
@@ -153,8 +153,11 @@ getDeviceWifiStatus(
|
|||||||
// 如果设备连接状态是 "connect",继续检测
|
// 如果设备连接状态是 "connect",继续检测
|
||||||
if (status.contains('connect')) {
|
if (status.contains('connect')) {
|
||||||
// 匹配 Wi-Fi 连接信息
|
// 匹配 Wi-Fi 连接信息
|
||||||
|
// final wifiInfoMatch = RegExp(
|
||||||
|
// r'WIFI CONNECTED INFO:SSID=([^\s]+),RSSI=([-0-9]+),AUTH=([0-9]+),CH=([0-9]+),BSSID=([A-F0-9]+)')
|
||||||
|
// .firstMatch(log);
|
||||||
final wifiInfoMatch = RegExp(
|
final wifiInfoMatch = RegExp(
|
||||||
r'WIFI CONNECTED INFO:SSID=([^\s]+),RSSI=([-0-9]+),AUTH=([0-9]+),CH=([0-9]+),BSSID=([A-F0-9]+)')
|
r'WIFI CONNECTED INFO:SSID=(.+?),RSSI=([-0-9]+),AUTH=([0-9]+),CH=([0-9]+),BSSID=([A-F0-9]+)')
|
||||||
.firstMatch(log);
|
.firstMatch(log);
|
||||||
if (wifiInfoMatch != null) {
|
if (wifiInfoMatch != null) {
|
||||||
final ssid = wifiInfoMatch.group(1);
|
final ssid = wifiInfoMatch.group(1);
|
||||||
@@ -207,7 +210,7 @@ getDeviceWifiStatus(
|
|||||||
|
|
||||||
//只有4g并且没有wifi
|
//只有4g并且没有wifi
|
||||||
Future<String> getDeviceNetVersion(THapp tHapp, int times) async {
|
Future<String> getDeviceNetVersion(THapp tHapp, int times) async {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("发送请求设备的网络信息");
|
edm.EasyDartModule.logger.info("发送请求设备的网络信息");
|
||||||
DailyLogUtils.writeLog("发送请求设备的网络信息");
|
DailyLogUtils.writeLog("发送请求设备的网络信息");
|
||||||
print("ls /root/mnt");
|
print("ls /root/mnt");
|
||||||
@@ -245,7 +248,7 @@ Future<String> getDeviceNetVersion(THapp tHapp, int times) async {
|
|||||||
|
|
||||||
/// 发送关闭blog日志与开启业务日志的指令
|
/// 发送关闭blog日志与开启业务日志的指令
|
||||||
Future<bool> sendBlogAndDlogCommands(THapp tHapp) async {
|
Future<bool> sendBlogAndDlogCommands(THapp tHapp) async {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("发送 blog disable 与 dlog on business 指令");
|
edm.EasyDartModule.logger.info("发送 blog disable 与 dlog on business 指令");
|
||||||
DailyLogUtils.writeLog("发送 blog disable 与 dlog on business 指令");
|
DailyLogUtils.writeLog("发送 blog disable 与 dlog on business 指令");
|
||||||
try {
|
try {
|
||||||
@@ -299,7 +302,7 @@ Future<bool> sendBlogAndDlogCommands(THapp tHapp) async {
|
|||||||
|
|
||||||
/// 执行 wscan close -> 延迟 1s -> wscan open
|
/// 执行 wscan close -> 延迟 1s -> wscan open
|
||||||
Future<bool> sendCloseAndOpenWscanCommand(THapp tHapp) async {
|
Future<bool> sendCloseAndOpenWscanCommand(THapp tHapp) async {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("执行 wscan close -> wscan open 指令");
|
edm.EasyDartModule.logger.info("执行 wscan close -> wscan open 指令");
|
||||||
DailyLogUtils.writeLog("执行 wscan close -> wscan open 指令开始");
|
DailyLogUtils.writeLog("执行 wscan close -> wscan open 指令开始");
|
||||||
|
|
||||||
@@ -352,7 +355,7 @@ Future<bool> sendCloseAndOpenWscanCommand(THapp tHapp) async {
|
|||||||
/// 若匹配到“关键内存剩余:xxxx 字节”,其中 xxxx < 20000 返回 false,
|
/// 若匹配到“关键内存剩余:xxxx 字节”,其中 xxxx < 20000 返回 false,
|
||||||
/// 否则返回 true。
|
/// 否则返回 true。
|
||||||
Future<bool> queryMemory(THapp tHapp, {int times = 1}) async {
|
Future<bool> queryMemory(THapp tHapp, {int times = 1}) async {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("发送查询内存状态指令 (free all)");
|
edm.EasyDartModule.logger.info("发送查询内存状态指令 (free all)");
|
||||||
DailyLogUtils.writeLog("发送查询内存状态指令 (free all)");
|
DailyLogUtils.writeLog("发送查询内存状态指令 (free all)");
|
||||||
|
|
||||||
@@ -401,7 +404,7 @@ Future<bool> queryMemory(THapp tHapp, {int times = 1}) async {
|
|||||||
/// 发送 "reboot" 命令,若响应中包含 reboot / restart / ok / success 等关键字
|
/// 发送 "reboot" 命令,若响应中包含 reboot / restart / ok / success 等关键字
|
||||||
/// 视为执行成功,返回 true;否则返回 false。
|
/// 视为执行成功,返回 true;否则返回 false。
|
||||||
Future<bool> rebootDevice(THapp tHapp) async {
|
Future<bool> rebootDevice(THapp tHapp) async {
|
||||||
await openDlog(tHapp);
|
await openDlog(tHapp);
|
||||||
edm.EasyDartModule.logger.info("发送设备重启指令 (reboot)");
|
edm.EasyDartModule.logger.info("发送设备重启指令 (reboot)");
|
||||||
DailyLogUtils.writeLog("发送设备重启指令 (reboot)");
|
DailyLogUtils.writeLog("发送设备重启指令 (reboot)");
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:get_storage/get_storage.dart';
|
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
|
||||||
import 'package:vbvs_app/controller/login/login_controller.dart';
|
|
||||||
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
|
||||||
|
|
||||||
class ApiService {
|
|
||||||
static Dio dio = Dio();
|
|
||||||
|
|
||||||
static Dio request = Dio();
|
|
||||||
static Dio requestNoInfo = Dio();
|
|
||||||
static Dio requestNoError = Dio(); //不处理错误的请求,用于设备操作上报
|
|
||||||
|
|
||||||
static Dio reservation = Dio();
|
|
||||||
|
|
||||||
static void init() {
|
|
||||||
|
|
||||||
reservationInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reservationInit() {
|
|
||||||
reservation.options.baseUrl = "https://crm-api.swes.com.cn";
|
|
||||||
reservation.options.connectTimeout = const Duration(seconds: 15);
|
|
||||||
reservation.options.receiveTimeout = const Duration(seconds: 10);
|
|
||||||
reservation.options.sendTimeout = const Duration(seconds: 10);
|
|
||||||
reservation.interceptors.add(InterceptorsWrapper(
|
|
||||||
onRequest: (options, handler) {
|
|
||||||
print("---> ${options.method}, ${options.path}, ${options.data}");
|
|
||||||
options.headers['token'] =
|
|
||||||
"bMAQVR1x48t66u8EDYSftAJGo17r0rIB3z15JgyyoGz1rAEZHs1htHOCorYFJ2RT";
|
|
||||||
return handler.next(options);
|
|
||||||
},
|
|
||||||
onResponse: (response, ResponseInterceptorHandler handler) {
|
|
||||||
print("<--- ${response.statusCode} ${response.data}");
|
|
||||||
return handler.next(response);
|
|
||||||
},
|
|
||||||
onError: (e, handler) {
|
|
||||||
// 错误处理,例如打印错误信息
|
|
||||||
showToast("网络异常或服务连接异常,请稍候再试", color: color_error);
|
|
||||||
print("DioError: $e");
|
|
||||||
return handler.reject(e);
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -74,6 +74,7 @@ class ExperienceStoreListController
|
|||||||
.indexWhere((item2) => item2["id"] == item["id"]) ==
|
.indexWhere((item2) => item2["id"] == item["id"]) ==
|
||||||
-1) {
|
-1) {
|
||||||
model.experienceStoreModelList.add(item);
|
model.experienceStoreModelList.add(item);
|
||||||
|
attr.refresh();
|
||||||
} else {
|
} else {
|
||||||
model.experienceStoreModelList[index] = item;
|
model.experienceStoreModelList[index] = item;
|
||||||
}
|
}
|
||||||
@@ -82,10 +83,10 @@ class ExperienceStoreListController
|
|||||||
}
|
}
|
||||||
page = page_ + 1;
|
page = page_ + 1;
|
||||||
total = d.data["total"];
|
total = d.data["total"];
|
||||||
updateAll();
|
// updateAll();
|
||||||
|
attr.refresh();
|
||||||
}).catchError((d) {
|
}).catchError((d) {
|
||||||
lock = false;
|
lock = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import 'package:vbvs_app/common/pojo/city.dart';
|
|||||||
import 'package:vbvs_app/common/util/CheckNetwork.dart';
|
import 'package:vbvs_app/common/util/CheckNetwork.dart';
|
||||||
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
||||||
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
// import 'package:vbvs_app/common/util/Dio.dart';
|
import 'package:vbvs_app/common/util/Dio.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/JPushUtil.dart';
|
import 'package:vbvs_app/common/util/JPushUtil.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
@@ -32,7 +32,6 @@ import 'package:vbvs_app/controller/device/device_calibration_controller.dart';
|
|||||||
import 'package:vbvs_app/controller/device/device_share_controller.dart';
|
import 'package:vbvs_app/controller/device/device_share_controller.dart';
|
||||||
import 'package:vbvs_app/controller/device/device_share_list_controller.dart';
|
import 'package:vbvs_app/controller/device/device_share_list_controller.dart';
|
||||||
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
import 'package:vbvs_app/controller/home/Dio.dart';
|
|
||||||
import 'package:vbvs_app/controller/home/home_controller.dart';
|
import 'package:vbvs_app/controller/home/home_controller.dart';
|
||||||
import 'package:vbvs_app/controller/login/login_controller.dart';
|
import 'package:vbvs_app/controller/login/login_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
@@ -486,7 +485,7 @@ Future<void> startMessagePolling(int ent_type) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_messageTimer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
_messageTimer = Timer.periodic(Duration(seconds: 5), (timer) async {
|
||||||
try {
|
try {
|
||||||
if (ent_type == APPPackageType.MHT.code) {
|
if (ent_type == APPPackageType.MHT.code) {
|
||||||
if (Get.isRegistered<MhMessageController>()) {
|
if (Get.isRegistered<MhMessageController>()) {
|
||||||
|
|||||||
@@ -508,9 +508,10 @@ class _DeviceComponentWidgetState extends State<DeviceComponentWidget> {
|
|||||||
const int maxRetries = 2;
|
const int maxRetries = 2;
|
||||||
const Duration timeout = Duration(seconds: 5);
|
const Duration timeout = Duration(seconds: 5);
|
||||||
String? macAddress;
|
String? macAddress;
|
||||||
|
THapp bledevice = THapp(device: device.scanResult.device);
|
||||||
try {
|
try {
|
||||||
// 连接设备
|
// 连接设备
|
||||||
THapp bledevice = THapp(device: device.scanResult.device);
|
|
||||||
await bledevice.connect();
|
await bledevice.connect();
|
||||||
var res2 = bledevice.isConnected;
|
var res2 = bledevice.isConnected;
|
||||||
if (!res2) {
|
if (!res2) {
|
||||||
@@ -545,6 +546,7 @@ class _DeviceComponentWidgetState extends State<DeviceComponentWidget> {
|
|||||||
print('MAC地址: $macAddress');
|
print('MAC地址: $macAddress');
|
||||||
return macAddress;
|
return macAddress;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
bledevice.disconnect();
|
||||||
blueteethBindController.currentDeviceMac.value = "";
|
blueteethBindController.currentDeviceMac.value = "";
|
||||||
edm.EasyDartModule.logger.error("蓝牙获取MAC失败:$e");
|
edm.EasyDartModule.logger.error("蓝牙获取MAC失败:$e");
|
||||||
DailyLogUtils.printLog("蓝牙获取MAC失败:$e");
|
DailyLogUtils.printLog("蓝牙获取MAC失败:$e");
|
||||||
|
|||||||
@@ -870,6 +870,8 @@ class _MHTPeopleInfoPageState extends State<MHTPeopleInfoPage> {
|
|||||||
stringToColor("#84F5FF"),
|
stringToColor("#84F5FF"),
|
||||||
selectedCityColor:
|
selectedCityColor:
|
||||||
stringToColor("#84F5FF"),
|
stringToColor("#84F5FF"),
|
||||||
|
selectedTextColor:
|
||||||
|
stringToColor("#011D33"),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
].divide(SizedBox(width: 22.rpx)),
|
].divide(SizedBox(width: 22.rpx)),
|
||||||
),
|
),
|
||||||
Text('SWES2025.12.20',
|
Text('SWES2025.12.24',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 26.rpx,
|
fontSize: 26.rpx,
|
||||||
|
|||||||
@@ -627,6 +627,9 @@ Widget _buildCityPickerContent(
|
|||||||
PersonController personController = Get.find();
|
PersonController personController = Get.find();
|
||||||
personController.cityModel = fullCityData;
|
personController.cityModel = fullCityData;
|
||||||
personController.updateAll();
|
personController.updateAll();
|
||||||
|
if (onCityChanged != null) {
|
||||||
|
onCityChanged(fullCityData);
|
||||||
|
}
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,343 @@
|
|||||||
|
// import 'dart:ui' as ui;
|
||||||
|
// import 'package:flutter/material.dart';
|
||||||
|
// import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
// import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
// import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
// import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
// class SnoreChartContainer extends StatelessWidget {
|
||||||
|
// final List<dynamic> snoreValues;
|
||||||
|
// final List<dynamic> barData;
|
||||||
|
// final List<dynamic> showLabel;
|
||||||
|
// final int startTime;
|
||||||
|
// final int endTime;
|
||||||
|
|
||||||
|
// const SnoreChartContainer({
|
||||||
|
// required this.snoreValues,
|
||||||
|
// required this.barData,
|
||||||
|
// required this.showLabel,
|
||||||
|
// required this.startTime,
|
||||||
|
// required this.endTime,
|
||||||
|
// super.key,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// // barData.add({
|
||||||
|
// // "type": 6,
|
||||||
|
// // "et": 1765291778963,
|
||||||
|
// // "st": 1765289341000,
|
||||||
|
// // });
|
||||||
|
// return Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// SnoreBarOverlay(
|
||||||
|
// barData: barData,
|
||||||
|
// showLabel: showLabel,
|
||||||
|
// startTime: startTime,
|
||||||
|
// endTime: endTime,
|
||||||
|
// ),
|
||||||
|
// Container(height: 32.rpx),
|
||||||
|
// Container(
|
||||||
|
// height: 23.rpx,
|
||||||
|
// child: SnoreWaveform(
|
||||||
|
// snoreValues: snoreValues,
|
||||||
|
// startTime: startTime,
|
||||||
|
// endTime: endTime,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class SnoreBarOverlay extends StatelessWidget {
|
||||||
|
// final List<dynamic> barData;
|
||||||
|
// final List<dynamic> showLabel;
|
||||||
|
// final int startTime;
|
||||||
|
// final int endTime;
|
||||||
|
|
||||||
|
// const SnoreBarOverlay({
|
||||||
|
// required this.barData,
|
||||||
|
// required this.showLabel,
|
||||||
|
// required this.startTime,
|
||||||
|
// required this.endTime,
|
||||||
|
// super.key,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// const double barHeight = 50;
|
||||||
|
// return SizedBox(
|
||||||
|
// height: barHeight,
|
||||||
|
// child: CustomPaint(
|
||||||
|
// size: Size(double.infinity, barHeight),
|
||||||
|
// painter: SnoreBarPainter(
|
||||||
|
// barData: barData,
|
||||||
|
// showLabel: showLabel,
|
||||||
|
// startTime: startTime,
|
||||||
|
// endTime: endTime,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class SnoreBarPainter extends CustomPainter {
|
||||||
|
// final List<dynamic> barData;
|
||||||
|
// final List<dynamic> showLabel;
|
||||||
|
// final int startTime;
|
||||||
|
// final int endTime;
|
||||||
|
|
||||||
|
// SnoreBarPainter({
|
||||||
|
// required this.barData,
|
||||||
|
// required this.showLabel,
|
||||||
|
// required this.startTime,
|
||||||
|
// required this.endTime,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void paint(Canvas canvas, Size size) {
|
||||||
|
// final double width = size.width;
|
||||||
|
// final double height = size.height;
|
||||||
|
// final double pixelPerMs = width / (endTime - startTime);
|
||||||
|
|
||||||
|
// for (var item in barData) {
|
||||||
|
// final int st = item['st'];
|
||||||
|
// final int et = item['et'];
|
||||||
|
// final int type = item['type'];
|
||||||
|
// int heightInit = 1;
|
||||||
|
|
||||||
|
// final match = showLabel.firstWhere(
|
||||||
|
// (e) => e['type'] == type,
|
||||||
|
// orElse: () => null,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// Color barColor = Colors.transparent;
|
||||||
|
// if (match != null) {
|
||||||
|
// final dynamic colorStr = match['color'];
|
||||||
|
// if (colorStr != null && colorStr.toString().isNotEmpty) {
|
||||||
|
// barColor = stringToColor(colorStr);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// final Paint barPaint = Paint()
|
||||||
|
// ..color = barColor
|
||||||
|
// ..style = PaintingStyle.fill;
|
||||||
|
|
||||||
|
// final double leftX = (st - startTime) * pixelPerMs;
|
||||||
|
// final double rightX = (et - startTime) * pixelPerMs;
|
||||||
|
// final double barWidth = rightX - leftX;
|
||||||
|
|
||||||
|
// //rem 深睡 中
|
||||||
|
// //浅睡 低
|
||||||
|
// //其他 高
|
||||||
|
// if (type == 1) {
|
||||||
|
// heightInit = 1;
|
||||||
|
// } else if (type == 2 || type == 6) {
|
||||||
|
// heightInit = 2;
|
||||||
|
// } else {
|
||||||
|
// heightInit = 3;
|
||||||
|
// }
|
||||||
|
// final double barHeight = (heightInit + 5).toDouble() * 8;
|
||||||
|
// final double top = height - barHeight;
|
||||||
|
|
||||||
|
// final rect = Rect.fromLTWH(leftX, top, barWidth, barHeight);
|
||||||
|
// canvas.drawRect(rect, barPaint);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class SnoreWaveform extends StatelessWidget {
|
||||||
|
// final List<dynamic> snoreValues;
|
||||||
|
// final int startTime;
|
||||||
|
// final int endTime;
|
||||||
|
|
||||||
|
// const SnoreWaveform({
|
||||||
|
// required this.snoreValues,
|
||||||
|
// required this.startTime,
|
||||||
|
// required this.endTime,
|
||||||
|
// super.key,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return SizedBox(
|
||||||
|
// height: 150,
|
||||||
|
// child: CustomPaint(
|
||||||
|
// size: Size(double.infinity, 150),
|
||||||
|
// painter: SnoreWaveformPainter(
|
||||||
|
// snoreValues: snoreValues,
|
||||||
|
// startTime: startTime,
|
||||||
|
// endTime: endTime,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class SnoreWaveformPainter extends CustomPainter {
|
||||||
|
// final List<dynamic> snoreValues;
|
||||||
|
// final int startTime;
|
||||||
|
// final int endTime;
|
||||||
|
|
||||||
|
// SnoreWaveformPainter({
|
||||||
|
// required this.snoreValues,
|
||||||
|
// required this.startTime,
|
||||||
|
// required this.endTime,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void paint(Canvas canvas, Size size) {
|
||||||
|
// final double width = size.width;
|
||||||
|
// final double height = size.height;
|
||||||
|
// final double centerY = height / 2;
|
||||||
|
// final double totalDuration = (endTime - startTime).toDouble();
|
||||||
|
// final double pixelPerMs = width / totalDuration;
|
||||||
|
|
||||||
|
// final Paint wavePaint = Paint()
|
||||||
|
// ..color = stringToColor("#8E7DEF").withOpacity(0.8)
|
||||||
|
// ..strokeWidth = 1.5
|
||||||
|
// ..style = PaintingStyle.stroke;
|
||||||
|
|
||||||
|
// final Path upperPath = Path();
|
||||||
|
// final Path lowerPath = Path();
|
||||||
|
|
||||||
|
// double maxValue = snoreValues.fold<double>(0, (prev, e) {
|
||||||
|
// final value = e["value"]?.toDouble() ?? 0;
|
||||||
|
// return value > prev ? value : prev;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// final double maxWaveHeight = height * 1;
|
||||||
|
// final double scaleY = maxValue > 0 ? (maxWaveHeight / maxValue) : 1;
|
||||||
|
|
||||||
|
// for (int i = 0; i < snoreValues.length; i++) {
|
||||||
|
// final timestamp = snoreValues[i]["st"];
|
||||||
|
// final value = snoreValues[i]["value"]?.toDouble() ?? 0;
|
||||||
|
|
||||||
|
// final x = (timestamp - startTime) * pixelPerMs;
|
||||||
|
// final y = centerY - value * scaleY;
|
||||||
|
// final yMirror = centerY + value * scaleY;
|
||||||
|
|
||||||
|
// if (i == 0) {
|
||||||
|
// upperPath.moveTo(x, y);
|
||||||
|
// lowerPath.moveTo(x, yMirror);
|
||||||
|
// } else {
|
||||||
|
// upperPath.lineTo(x, y);
|
||||||
|
// lowerPath.lineTo(x, yMirror);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// canvas.drawPath(upperPath, wavePaint);
|
||||||
|
// canvas.drawPath(lowerPath, wavePaint);
|
||||||
|
|
||||||
|
// final Paint axisPaint = Paint()
|
||||||
|
// ..color = Colors.grey.withOpacity(0.6)
|
||||||
|
// ..strokeWidth = 0.5;
|
||||||
|
// canvas.drawLine(Offset(0, centerY), Offset(width, centerY), axisPaint);
|
||||||
|
|
||||||
|
// final textPainter = TextPainter(
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// textDirection: ui.TextDirection.ltr,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// final int hourMs = 60 * 60 * 1000;
|
||||||
|
// final int totalHours = (endTime - startTime) ~/ hourMs;
|
||||||
|
|
||||||
|
// // 1. 始终显示开始时间
|
||||||
|
// double x = 0;
|
||||||
|
// DateTime startDt = DateTime.fromMillisecondsSinceEpoch(startTime);
|
||||||
|
// String label = DateFormat('HH:mm').format(startDt);
|
||||||
|
|
||||||
|
// textPainter.text = TextSpan(
|
||||||
|
// text: label,
|
||||||
|
// style: TextStyle(fontSize: 10, color: Colors.grey),
|
||||||
|
// );
|
||||||
|
// textPainter.layout();
|
||||||
|
// textPainter.paint(
|
||||||
|
// canvas,
|
||||||
|
// Offset(x - textPainter.width / 2, height + 2),
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // 2. 决定显示策略
|
||||||
|
// if (totalHours <= 8) {
|
||||||
|
// // 小时间段:显示所有整点小时
|
||||||
|
// for (int t = startTime + hourMs; t < endTime; t += hourMs) {
|
||||||
|
// x = (t - startTime) * pixelPerMs;
|
||||||
|
// DateTime dt = DateTime.fromMillisecondsSinceEpoch(t);
|
||||||
|
|
||||||
|
// // 判断是否接近边界(30分钟内不显示)
|
||||||
|
// if (t - startTime < 30 * 60 * 1000 || endTime - t < 30 * 60 * 1000) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// label = dt.hour == 0 ? "0" : "${dt.hour}";
|
||||||
|
|
||||||
|
// textPainter.text = TextSpan(
|
||||||
|
// text: label,
|
||||||
|
// style: TextStyle(fontSize: 10, color: Colors.grey),
|
||||||
|
// );
|
||||||
|
// textPainter.layout();
|
||||||
|
// textPainter.paint(
|
||||||
|
// canvas,
|
||||||
|
// Offset(x - textPainter.width / 2, height + 2),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // 长时间段:使用自适应间隔
|
||||||
|
// int labelInterval = (totalHours / 6).ceil();
|
||||||
|
|
||||||
|
// // 计算第一个标签位置(对齐整点)
|
||||||
|
// int firstLabelMs =
|
||||||
|
// ((startTime ~/ (labelInterval * hourMs))) * labelInterval * hourMs;
|
||||||
|
// if (firstLabelMs <= startTime) {
|
||||||
|
// firstLabelMs += labelInterval * hourMs;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 绘制中间标签
|
||||||
|
// for (int t = firstLabelMs; t < endTime; t += labelInterval * hourMs) {
|
||||||
|
// // 跳过太接近边界的时间点(1小时内不显示)
|
||||||
|
// if (t - startTime < hourMs || endTime - t < hourMs) continue;
|
||||||
|
|
||||||
|
// x = (t - startTime) * pixelPerMs;
|
||||||
|
// DateTime dt = DateTime.fromMillisecondsSinceEpoch(t);
|
||||||
|
// label = dt.hour == 0 ? "0" : "${dt.hour}";
|
||||||
|
|
||||||
|
// textPainter.text = TextSpan(
|
||||||
|
// text: label,
|
||||||
|
// style: TextStyle(fontSize: 10, color: Colors.grey),
|
||||||
|
// );
|
||||||
|
// textPainter.layout();
|
||||||
|
// textPainter.paint(
|
||||||
|
// canvas,
|
||||||
|
// Offset(x - textPainter.width / 2, height + 2),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 3. 始终显示结束时间
|
||||||
|
// x = (endTime - startTime) * pixelPerMs;
|
||||||
|
// DateTime endDt = DateTime.fromMillisecondsSinceEpoch(endTime);
|
||||||
|
// label = DateFormat('HH:mm').format(endDt);
|
||||||
|
|
||||||
|
// textPainter.text = TextSpan(
|
||||||
|
// text: label,
|
||||||
|
// style: TextStyle(fontSize: 10, color: Colors.grey),
|
||||||
|
// );
|
||||||
|
// textPainter.layout();
|
||||||
|
// textPainter.paint(
|
||||||
|
// canvas,
|
||||||
|
// Offset(x - textPainter.width / 2, height + 2),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||||
|
// }
|
||||||
|
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
@@ -23,11 +363,6 @@ class SnoreChartContainer extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// barData.add({
|
|
||||||
// "type": 6,
|
|
||||||
// "et": 1765291778963,
|
|
||||||
// "st": 1765289341000,
|
|
||||||
// });
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -167,13 +502,17 @@ class SnoreWaveform extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 150,
|
height: 150,
|
||||||
child: CustomPaint(
|
child: LayoutBuilder(
|
||||||
size: Size(double.infinity, 150),
|
builder: (context, constraints) {
|
||||||
painter: SnoreWaveformPainter(
|
return CustomPaint(
|
||||||
snoreValues: snoreValues,
|
size: Size(constraints.maxWidth, constraints.maxHeight),
|
||||||
startTime: startTime,
|
painter: SnoreWaveformPainter(
|
||||||
endTime: endTime,
|
snoreValues: snoreValues,
|
||||||
),
|
startTime: startTime,
|
||||||
|
endTime: endTime,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -194,51 +533,94 @@ class SnoreWaveformPainter extends CustomPainter {
|
|||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final double width = size.width;
|
final double width = size.width;
|
||||||
final double height = size.height;
|
final double height = size.height;
|
||||||
final double centerY = height / 2;
|
|
||||||
|
if (width <= 0 || height <= 0) return;
|
||||||
|
|
||||||
final double totalDuration = (endTime - startTime).toDouble();
|
final double totalDuration = (endTime - startTime).toDouble();
|
||||||
|
if (totalDuration <= 0) return;
|
||||||
|
|
||||||
final double pixelPerMs = width / totalDuration;
|
final double pixelPerMs = width / totalDuration;
|
||||||
|
|
||||||
final Paint wavePaint = Paint()
|
// 过滤在时间范围内的有效事件
|
||||||
..color = stringToColor("#8E7DEF").withOpacity(0.8)
|
final validEvents = snoreValues.where((e) {
|
||||||
..strokeWidth = 1.5
|
final int st = e['st'];
|
||||||
..style = PaintingStyle.stroke;
|
final int et = e['et'];
|
||||||
|
// 事件与时间范围有重叠
|
||||||
|
return !(et <= startTime || st >= endTime);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
final Path upperPath = Path();
|
if (validEvents.isEmpty) {
|
||||||
final Path lowerPath = Path();
|
// 绘制无数据提示
|
||||||
|
final textPainter = TextPainter(
|
||||||
double maxValue = snoreValues.fold<double>(0, (prev, e) {
|
text: TextSpan(
|
||||||
final value = e["value"]?.toDouble() ?? 0;
|
text: '无打鼾数据',
|
||||||
return value > prev ? value : prev;
|
style: TextStyle(color: Colors.grey, fontSize: 12),
|
||||||
});
|
),
|
||||||
|
textDirection: ui.TextDirection.ltr,
|
||||||
final double maxWaveHeight = height * 1;
|
);
|
||||||
final double scaleY = maxValue > 0 ? (maxWaveHeight / maxValue) : 1;
|
textPainter.layout();
|
||||||
|
textPainter.paint(
|
||||||
for (int i = 0; i < snoreValues.length; i++) {
|
canvas, Offset(width / 2 - textPainter.width / 2, height / 2 - 10));
|
||||||
final timestamp = snoreValues[i]["st"];
|
return;
|
||||||
final value = snoreValues[i]["value"]?.toDouble() ?? 0;
|
|
||||||
|
|
||||||
final x = (timestamp - startTime) * pixelPerMs;
|
|
||||||
final y = centerY - value * scaleY;
|
|
||||||
final yMirror = centerY + value * scaleY;
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
upperPath.moveTo(x, y);
|
|
||||||
lowerPath.moveTo(x, yMirror);
|
|
||||||
} else {
|
|
||||||
upperPath.lineTo(x, y);
|
|
||||||
lowerPath.lineTo(x, yMirror);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.drawPath(upperPath, wavePaint);
|
// 计算中心线位置
|
||||||
canvas.drawPath(lowerPath, wavePaint);
|
final double centerY = height / 2;
|
||||||
|
|
||||||
|
// 统一使用一个颜色(打鼾颜色)
|
||||||
|
final Color snoreColor = stringToColor("#8E7DEF").withOpacity(0.8);
|
||||||
|
final Paint barPaint = Paint()
|
||||||
|
..color = snoreColor
|
||||||
|
..style = PaintingStyle.fill;
|
||||||
|
|
||||||
|
final Paint borderPaint = Paint()
|
||||||
|
..color = snoreColor.withOpacity(0.9)
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = 0.5;
|
||||||
|
|
||||||
|
// 固定高度(上下对称)
|
||||||
|
final double fixedBarHeight = height * 0.3; // 固定为画布高度的30%
|
||||||
|
|
||||||
|
// 绘制每个打鼾事件(上下对称的柱状图)
|
||||||
|
for (final event in validEvents) {
|
||||||
|
final int st = event['st'];
|
||||||
|
final int et = event['et'];
|
||||||
|
|
||||||
|
// 计算绘制位置(裁剪到可视范围内)
|
||||||
|
final double startX = (st - startTime) * pixelPerMs;
|
||||||
|
final double endX = (et - startTime) * pixelPerMs;
|
||||||
|
|
||||||
|
// 确保在画布范围内
|
||||||
|
if (endX < 0 || startX > width) continue;
|
||||||
|
|
||||||
|
final double drawStartX = startX.clamp(0, width);
|
||||||
|
final double drawEndX = endX.clamp(0, width);
|
||||||
|
final double drawWidth = drawEndX - drawStartX;
|
||||||
|
|
||||||
|
if (drawWidth <= 0) continue;
|
||||||
|
|
||||||
|
// 绘制上方的柱状图
|
||||||
|
final double topBarTop = centerY - fixedBarHeight;
|
||||||
|
final Rect topRect =
|
||||||
|
Rect.fromLTWH(drawStartX, topBarTop, drawWidth, fixedBarHeight);
|
||||||
|
canvas.drawRect(topRect, barPaint);
|
||||||
|
canvas.drawRect(topRect, borderPaint);
|
||||||
|
|
||||||
|
// 绘制下方的柱状图(对称)
|
||||||
|
final double bottomBarTop = centerY;
|
||||||
|
final Rect bottomRect =
|
||||||
|
Rect.fromLTWH(drawStartX, bottomBarTop, drawWidth, fixedBarHeight);
|
||||||
|
canvas.drawRect(bottomRect, barPaint);
|
||||||
|
canvas.drawRect(bottomRect, borderPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制中心线
|
||||||
final Paint axisPaint = Paint()
|
final Paint axisPaint = Paint()
|
||||||
..color = Colors.grey.withOpacity(0.6)
|
..color = Colors.grey.withOpacity(0.3)
|
||||||
..strokeWidth = 0.5;
|
..strokeWidth = 0.5;
|
||||||
canvas.drawLine(Offset(0, centerY), Offset(width, centerY), axisPaint);
|
canvas.drawLine(Offset(0, centerY), Offset(width, centerY), axisPaint);
|
||||||
|
|
||||||
|
// 绘制时间轴标签
|
||||||
final textPainter = TextPainter(
|
final textPainter = TextPainter(
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
textDirection: ui.TextDirection.ltr,
|
textDirection: ui.TextDirection.ltr,
|
||||||
@@ -335,5 +717,9 @@ class SnoreWaveformPainter extends CustomPainter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
bool shouldRepaint(covariant SnoreWaveformPainter oldDelegate) {
|
||||||
|
return oldDelegate.snoreValues != snoreValues ||
|
||||||
|
oldDelegate.startTime != startTime ||
|
||||||
|
oldDelegate.endTime != endTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user