Merge remote-tracking branch 'origin/develop_liyi' into develop_liyi
This commit is contained in:
commit
07e7d1dc91
@ -97,6 +97,7 @@ class CatEyeWorkModeLogic extends BaseGetXController {
|
|||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
showToast('设置成功'.tr);
|
showToast('设置成功'.tr);
|
||||||
|
getLockSettingInfoData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -197,7 +197,7 @@ class _VideoSlotPageState extends State<VideoSlotPage> {
|
|||||||
Obx(() => Text(
|
Obx(() => Text(
|
||||||
isEndTime == false
|
isEndTime == false
|
||||||
? '${'当日'.tr}${state.startDate.value}'
|
? '${'当日'.tr}${state.startDate.value}'
|
||||||
: '${'次日'.tr}${state.endDate.value}',
|
: '${'当日'.tr}${state.endDate.value}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: state.isCustom.value == true
|
color: state.isCustom.value == true
|
||||||
? AppColors.blueTextTipsColor
|
? AppColors.blueTextTipsColor
|
||||||
|
|||||||
@ -75,6 +75,11 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
} else {
|
} else {
|
||||||
Get.offAllNamed(Routers.starLockMain);
|
Get.offAllNamed(Routers.starLockMain);
|
||||||
}
|
}
|
||||||
|
dismissEasyLoading();
|
||||||
|
if (state.loadingTimer != null) {
|
||||||
|
state.loadingTimer!.cancel();
|
||||||
|
state.loadingTimer = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +90,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
void _initReplySubscription() {
|
void _initReplySubscription() {
|
||||||
_replySubscription =
|
_replySubscription =
|
||||||
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||||
|
AppLog.log('收到蓝牙回调${EasyLoading.isShow}');
|
||||||
// WIFI配网结果
|
// WIFI配网结果
|
||||||
if (reply is GatewayConfiguringWifiResultReply) {
|
if (reply is GatewayConfiguringWifiResultReply) {
|
||||||
_replySenderConfiguringWifiResult(reply);
|
_replySenderConfiguringWifiResult(reply);
|
||||||
@ -95,6 +101,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
if (reply is GatewayGetStatusReply) {
|
if (reply is GatewayGetStatusReply) {
|
||||||
_replyStatusInfo(reply);
|
_replyStatusInfo(reply);
|
||||||
}
|
}
|
||||||
|
AppLog.log('蓝牙回调处理完毕${EasyLoading.isShow}');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,9 +113,6 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
//成功
|
|
||||||
cancelBlueConnetctToastTimer();
|
|
||||||
|
|
||||||
final int secretKeyJsonLength = (reply.data[4] << 8) + reply.data[3];
|
final int secretKeyJsonLength = (reply.data[4] << 8) + reply.data[3];
|
||||||
|
|
||||||
final List<int> secretKeyList =
|
final List<int> secretKeyList =
|
||||||
@ -126,7 +130,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
|
|
||||||
/// 配网成功后,赋值锁的peerId
|
/// 配网成功后,赋值锁的peerId
|
||||||
StartChartManage().lockPeerId = peerId ?? '';
|
StartChartManage().lockPeerId = peerId ?? '';
|
||||||
dismissEasyLoading();
|
|
||||||
state.isLoading.value = false;
|
state.isLoading.value = false;
|
||||||
// 保存到缓存
|
// 保存到缓存
|
||||||
await Storage.saveLockNetWorkInfo(jsonMap);
|
await Storage.saveLockNetWorkInfo(jsonMap);
|
||||||
@ -141,6 +145,10 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
default:
|
default:
|
||||||
//失败
|
//失败
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
|
if (state.loadingTimer != null) {
|
||||||
|
state.loadingTimer!.cancel();
|
||||||
|
state.loadingTimer = null;
|
||||||
|
}
|
||||||
cancelBlueConnetctToastTimer();
|
cancelBlueConnetctToastTimer();
|
||||||
showToast('配网失败'.tr);
|
showToast('配网失败'.tr);
|
||||||
state.isLoading.value = false;
|
state.isLoading.value = false;
|
||||||
@ -156,6 +164,8 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 点击配置wifi
|
// 点击配置wifi
|
||||||
Future<void> senderConfiguringWifiAction() async {
|
Future<void> senderConfiguringWifiAction() async {
|
||||||
|
AppLog.log('开始配网${EasyLoading.isShow}');
|
||||||
|
EasyLoading.show();
|
||||||
if (state.isLoading.isTrue) {
|
if (state.isLoading.isTrue) {
|
||||||
AppLog.log('正在配网中请勿重复点击');
|
AppLog.log('正在配网中请勿重复点击');
|
||||||
return;
|
return;
|
||||||
@ -175,7 +185,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
state.sureBtnState.value = 1;
|
state.sureBtnState.value = 1;
|
||||||
|
|
||||||
final GetGatewayConfigurationEntity entity =
|
final GetGatewayConfigurationEntity entity =
|
||||||
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
|
await ApiRepository.to.getGatewayConfigurationNotLoading(timeout: 60);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.getGatewayConfigurationStr = entity.data ?? '';
|
state.getGatewayConfigurationStr = entity.data ?? '';
|
||||||
}
|
}
|
||||||
@ -210,6 +220,8 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}";
|
state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppLog.log('获取到配网信息===开始发送蓝牙指令${EasyLoading.isShow}');
|
||||||
|
|
||||||
BlueManage().blueSendData(
|
BlueManage().blueSendData(
|
||||||
BlueManage().connectDeviceName,
|
BlueManage().connectDeviceName,
|
||||||
(BluetoothConnectionState connectionState) async {
|
(BluetoothConnectionState connectionState) async {
|
||||||
@ -223,8 +235,12 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
},
|
},
|
||||||
isAddEquipment: true,
|
isAddEquipment: true,
|
||||||
);
|
);
|
||||||
// 显示加载指示器
|
state.loadingTimer ??= Timer.periodic(Duration(milliseconds: 100), (timer) {
|
||||||
showEasyLoading();
|
if (!EasyLoading.isShow) {
|
||||||
|
EasyLoading.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
state.isLoading.value = true;
|
state.isLoading.value = true;
|
||||||
// 添加15秒超时检查
|
// 添加15秒超时检查
|
||||||
Future.delayed(const Duration(seconds: 15), () {
|
Future.delayed(const Duration(seconds: 15), () {
|
||||||
@ -232,9 +248,14 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
EasyLoading.dismiss();
|
EasyLoading.dismiss();
|
||||||
state.isLoading.value = false;
|
state.isLoading.value = false;
|
||||||
state.sureBtnState.value = 0;
|
state.sureBtnState.value = 0;
|
||||||
|
if (state.loadingTimer != null) {
|
||||||
|
state.loadingTimer!.cancel();
|
||||||
|
state.loadingTimer = null;
|
||||||
|
}
|
||||||
showToast('配网失败'.tr);
|
showToast('配网失败'.tr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
AppLog.log('发送方法执行完毕${EasyLoading.isShow}');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取设备状态
|
// 获取设备状态
|
||||||
@ -358,9 +379,24 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
//失败
|
//失败
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
showToast('配网失败'.tr);
|
showToast('配网失败'.tr);
|
||||||
|
if (state.loadingTimer != null) {
|
||||||
|
state.loadingTimer!.cancel();
|
||||||
|
state.loadingTimer = null;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _replyStatusInfo(reply) {}
|
void _replyStatusInfo(reply) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
state.isLoading.value = false;
|
||||||
|
if (state.loadingTimer != null) {
|
||||||
|
state.loadingTimer!.cancel();
|
||||||
|
state.loadingTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@ -30,4 +32,5 @@ class ConfiguringWifiState{
|
|||||||
String getGatewayConfigurationStr = '';
|
String getGatewayConfigurationStr = '';
|
||||||
|
|
||||||
RxBool isLoading=false.obs;
|
RxBool isLoading=false.obs;
|
||||||
|
Timer? loadingTimer;
|
||||||
}
|
}
|
||||||
@ -78,10 +78,10 @@ class _WifiListPageState extends State<WifiListPage> {
|
|||||||
borderRadius: 20.w,
|
borderRadius: 20.w,
|
||||||
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
|
padding: EdgeInsets.only(top: 25.w, bottom: 25.w),
|
||||||
onClick: () {
|
onClick: () {
|
||||||
Get.toNamed(Routers.configuringWifiPage,
|
Get.toNamed(Routers.configuringWifiPage, arguments: {
|
||||||
arguments: <String, LockSetInfoData>{
|
'lockSetInfoData': state.lockSetInfoData.value,
|
||||||
'lockSetInfoData': state.lockSetInfoData.value
|
'pageName': state.pageName.value,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 64.h,
|
height: 64.h,
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:star_lock/app_settings/app_settings.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_logic.dart';
|
||||||
import 'package:star_lock/network/api_repository.dart';
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
import 'package:star_lock/versionUndate/versionUndate_entity.dart';
|
import 'package:star_lock/versionUndate/versionUndate_entity.dart';
|
||||||
@ -14,6 +18,8 @@ import 'editVideoLog_state.dart';
|
|||||||
class EditVideoLogLogic extends BaseGetXController {
|
class EditVideoLogLogic extends BaseGetXController {
|
||||||
EditVideoLogState state = EditVideoLogState();
|
EditVideoLogState state = EditVideoLogState();
|
||||||
|
|
||||||
|
final VideoLogLogic videoLogLogic = Get.find<VideoLogLogic>();
|
||||||
|
|
||||||
Future<void> deleteLockCloudStorageList() async {
|
Future<void> deleteLockCloudStorageList() async {
|
||||||
final VersionUndateEntity entity =
|
final VersionUndateEntity entity =
|
||||||
await ApiRepository.to.deleteLockCloudStorageList(
|
await ApiRepository.to.deleteLockCloudStorageList(
|
||||||
@ -86,6 +92,146 @@ class EditVideoLogLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量删除指定文件路径列表中的文件
|
||||||
|
Future<bool> deleteDownloadsByPaths(List<String> filePaths) async {
|
||||||
|
try {
|
||||||
|
showEasyLoading();
|
||||||
|
// 获取应用专属目录
|
||||||
|
Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
final logFilePath = '${appDocDir.path}/download_log.json';
|
||||||
|
|
||||||
|
if (await File(logFilePath).exists()) {
|
||||||
|
final content = await File(logFilePath).readAsString();
|
||||||
|
Map<String, dynamic> logData =
|
||||||
|
Map<String, dynamic>.from(json.decode(content));
|
||||||
|
|
||||||
|
// 过滤出需要保留的文件
|
||||||
|
final filteredLogData = <String, dynamic>{};
|
||||||
|
|
||||||
|
for (final entry in logData.entries) {
|
||||||
|
final filePath = entry.key;
|
||||||
|
|
||||||
|
if (!filePaths.contains(filePath)) {
|
||||||
|
filteredLogData[filePath] = entry.value; // 保留其他文件
|
||||||
|
} else {
|
||||||
|
// 删除文件
|
||||||
|
final file = File(filePath);
|
||||||
|
if (await file.exists()) {
|
||||||
|
await file.delete();
|
||||||
|
print('已删除文件:$filePath');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新日志文件
|
||||||
|
await File(logFilePath).writeAsString(json.encode(filteredLogData));
|
||||||
|
showToast('删除成功'.tr);
|
||||||
|
|
||||||
|
// 重新分组统计下载文件
|
||||||
|
await videoLogLogic.groupDownloadsByDay();
|
||||||
|
|
||||||
|
Get.back();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
print('日志文件不存在');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('批量删除失败:$e');
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
dismissEasyLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据URL生成唯一的文件名(MD5哈希值)
|
||||||
|
String getFileNameFromUrl(String url, String extension) {
|
||||||
|
final hash = md5.convert(utf8.encode(url)).toString(); // 使用 md5 生成哈希值
|
||||||
|
return '$hash.$extension';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> recordDownloadTime(String filePath) async {
|
||||||
|
final appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
final logFilePath = '${appDocDir.path}/download_log.json';
|
||||||
|
|
||||||
|
// 读取现有的日志文件
|
||||||
|
Map<String, int> logData = {};
|
||||||
|
if (await File(logFilePath).exists()) {
|
||||||
|
final content = await File(logFilePath).readAsString();
|
||||||
|
logData = Map<String, int>.from(json.decode(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新的下载记录
|
||||||
|
logData[filePath] = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
|
||||||
|
// 写入日志文件
|
||||||
|
await File(logFilePath).writeAsString(json.encode(logData));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载文件方法(支持视频和图片)
|
||||||
|
Future<String?> downloadFile(String? url) async {
|
||||||
|
if (url == null || url.isEmpty) {
|
||||||
|
print('URL不能为空');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求存储权限
|
||||||
|
if (await Permission.storage.request().isGranted) {
|
||||||
|
try {
|
||||||
|
// 获取应用专属目录(避免与其他应用冲突)
|
||||||
|
Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
|
||||||
|
// 根据URL生成唯一文件名(自动识别扩展名)
|
||||||
|
String extension = _getFileTypeFromUrl(url); // 自动检测文件类型
|
||||||
|
String fileName = getFileNameFromUrl(url, extension); // 根据URL生成唯一文件名
|
||||||
|
String savePath = '${appDocDir.path}/downloads/$fileName'; // 自定义保存路径
|
||||||
|
|
||||||
|
// 确保目录存在
|
||||||
|
final dir = Directory('${appDocDir.path}/downloads');
|
||||||
|
if (!await dir.exists()) {
|
||||||
|
await dir.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件是否已存在
|
||||||
|
File file = File(savePath);
|
||||||
|
if (await file.exists()) {
|
||||||
|
print('文件已存在,无需重新下载:$savePath');
|
||||||
|
return savePath; // 文件已存在,直接返回路径
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
await Dio().download(url, savePath,
|
||||||
|
onReceiveProgress: (received, total) {
|
||||||
|
if (total != -1) {
|
||||||
|
print('下载进度: ${(received / total * 100).toStringAsFixed(0)}%');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 记录下载时间
|
||||||
|
await recordDownloadTime(savePath);
|
||||||
|
|
||||||
|
print('文件已成功下载到:$savePath');
|
||||||
|
|
||||||
|
// 返回下载路径以便后续使用
|
||||||
|
return savePath;
|
||||||
|
} catch (e) {
|
||||||
|
print('下载失败:$e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print('未获取存储权限');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据URL自动检测文件类型
|
||||||
|
String _getFileTypeFromUrl(String url) {
|
||||||
|
final uri = Uri.parse(url);
|
||||||
|
final path = uri.path;
|
||||||
|
final extension = path.split('.').last.toLowerCase();
|
||||||
|
return extension.isNotEmpty ? extension : 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
// 请求存储权限
|
// 请求存储权限
|
||||||
Future<bool> _requestPermission() async {
|
Future<bool> _requestPermission() async {
|
||||||
final status = await Permission.storage.request();
|
final status = await Permission.storage.request();
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
@ -180,55 +182,70 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
Widget bottomBottomBtnWidget() {
|
Widget bottomBottomBtnWidget() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
child:
|
child: Row(
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
bottomBtnItemWidget(
|
children: <Widget>[
|
||||||
'images/main/icon_lockDetail_monitoringDownloadVideo.png',
|
state.isNavLocal.value == false
|
||||||
'下载'.tr,
|
? bottomBtnItemWidget(
|
||||||
Colors.white,
|
'images/main/icon_lockDetail_monitoringDownloadVideo.png',
|
||||||
_onDownLoadClick,
|
'下载'.tr,
|
||||||
),
|
Colors.white,
|
||||||
SizedBox(width: 100.w),
|
_onDownLoadClick,
|
||||||
bottomBtnItemWidget(
|
)
|
||||||
'images/main/icon_lockDetail_monitoringDeletVideo.png',
|
: SizedBox.shrink(),
|
||||||
'删除'.tr,
|
state.isNavLocal.value == false
|
||||||
AppColors.mainColor,
|
? SizedBox(width: 100.w)
|
||||||
_onDelClick,
|
: SizedBox.shrink(),
|
||||||
)
|
bottomBtnItemWidget(
|
||||||
]),
|
'images/main/icon_lockDetail_monitoringDeletVideo.png',
|
||||||
|
'删除'.tr,
|
||||||
|
AppColors.mainColor,
|
||||||
|
_onDelClick,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onDownLoadClick() async {
|
Future<void> _onDownLoadClick() async {
|
||||||
if (state.selectVideoLogList.value.isNotEmpty) {
|
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||||
double _progress = 0.0;
|
state.selectVideoLogList.value.forEach((element) {
|
||||||
|
if (element.videoUrl != null && element.videoUrl != '') {
|
||||||
|
logic.downloadFile(element.videoUrl ?? '');
|
||||||
|
} else if (element.imagesUrl != null && element.imagesUrl != '') {
|
||||||
|
logic.downloadFile(element.imagesUrl ?? '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// double _progress = 0.0;
|
||||||
// 开始下载
|
// 开始下载
|
||||||
// 显示进度条
|
// 显示进度条
|
||||||
EasyLoading.showProgress(_progress, status: '加载数据中'.tr);
|
// EasyLoading.showProgress(_progress, status: '加载数据中'.tr);
|
||||||
|
//
|
||||||
// 模拟进度更新
|
// // 模拟进度更新
|
||||||
for (int i = 0; i <= state.selectVideoLogList.length - 1; i++) {
|
// for (int i = 0; i <= state.selectVideoLogList.length - 1; i++) {
|
||||||
final item = state.selectVideoLogList.value[i];
|
// final item = state.selectVideoLogList.value[i];
|
||||||
|
//
|
||||||
// 判断 imagesUrl 是否为空
|
// // 判断 imagesUrl 是否为空
|
||||||
if (item.imagesUrl != null && item.imagesUrl!.isNotEmpty) {
|
// if (item.imagesUrl != null && item.imagesUrl!.isNotEmpty) {
|
||||||
await logic.downloadAndSaveToGallery(item.imagesUrl!, 'image_$i.jpg');
|
// await logic.downloadAndSaveToGallery(item.imagesUrl!, 'image_$i.jpg');
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 判断 videoUrl 是否为空
|
// // 判断 videoUrl 是否为空
|
||||||
if (item.videoUrl != null && item.videoUrl!.isNotEmpty) {
|
// if (item.videoUrl != null && item.videoUrl!.isNotEmpty) {
|
||||||
await logic.downloadAndSaveToGallery(item.videoUrl!, 'video_$i.mp4');
|
// await logic.downloadAndSaveToGallery(item.videoUrl!, 'video_$i.mp4');
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 更新进度
|
// // 更新进度
|
||||||
_progress = (i + 1) / state.selectVideoLogList.length;
|
// _progress = (i + 1) / state.selectVideoLogList.length;
|
||||||
EasyLoading.showProgress(_progress, status: '加载数据中'.tr);
|
// EasyLoading.showProgress(_progress, status: '加载数据中'.tr);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 加载完成后隐藏进度条
|
// // 加载完成后隐藏进度条
|
||||||
EasyLoading.dismiss();
|
// EasyLoading.dismiss();
|
||||||
EasyLoading.showSuccess('下载完成,请到相册查看'.tr);
|
// EasyLoading.showSuccess('下载完成,请到相册查看'.tr);
|
||||||
|
EasyLoading.showSuccess('下载完成'.tr);
|
||||||
state.selectVideoLogList.clear();
|
state.selectVideoLogList.clear();
|
||||||
|
Get.back();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
// Get.toNamed(Routers.videoLogDownLoadPage,
|
// Get.toNamed(Routers.videoLogDownLoadPage,
|
||||||
// arguments: <String, List<RecordListData>>{
|
// arguments: <String, List<RecordListData>>{
|
||||||
@ -240,11 +257,28 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onDelClick() async {
|
Future<void> _onDelClick() async {
|
||||||
if (state.selectVideoLogList.value.isNotEmpty) {
|
if (state.isNavLocal.isFalse) {
|
||||||
await logic.deleteLockCloudStorageList();
|
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||||
setState(() {});
|
await logic.deleteLockCloudStorageList();
|
||||||
|
setState(() {});
|
||||||
|
} else {
|
||||||
|
logic.showToast('请选择要删除的视频'.tr);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logic.showToast('请选择要删除的视频'.tr);
|
if (state.selectVideoLogList.value.isNotEmpty) {
|
||||||
|
List<String> deletePaths = [];
|
||||||
|
state.selectVideoLogList.value.forEach((element) {
|
||||||
|
if (element.imagesUrl != null && element.imagesUrl != '') {
|
||||||
|
deletePaths.add(element.imagesUrl!);
|
||||||
|
}
|
||||||
|
if (element.videoUrl != null && element.videoUrl != '') {
|
||||||
|
deletePaths.add(element.videoUrl!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logic.deleteDownloadsByPaths(deletePaths);
|
||||||
|
} else {
|
||||||
|
logic.showToast('请选择要删除的视频'.tr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,21 +399,56 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
_buildImageItem(RecordListData recordData) {
|
_buildImageItem(RecordListData recordData) {
|
||||||
return RotatedBox(
|
return RotatedBox(
|
||||||
quarterTurns: -1,
|
quarterTurns: -1,
|
||||||
child: Image.network(
|
child: _buildImageWidget(recordData.imagesUrl),
|
||||||
recordData.imagesUrl!,
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据图片路径构建对应的 Image Widget
|
||||||
|
Widget _buildImageWidget(String? imageUrl) {
|
||||||
|
if (imageUrl == null || imageUrl.isEmpty) {
|
||||||
|
// 如果图片路径为空,返回错误图片
|
||||||
|
return Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为网络地址
|
||||||
|
if (_isNetworkUrl(imageUrl)) {
|
||||||
|
return Image.network(
|
||||||
|
imageUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
errorBuilder:
|
errorBuilder:
|
||||||
(BuildContext context, Object error, StackTrace? stackTrace) {
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
// 图片加载失败时显示错误图片
|
// 图片加载失败时显示错误图片
|
||||||
return RotatedBox(
|
return Image.asset(
|
||||||
quarterTurns: -1,
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
child: Image.asset(
|
fit: BoxFit.cover,
|
||||||
'images/icon_unHaveData.png', // 错误图片路径
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
);
|
} else {
|
||||||
|
// 如果是本地文件路径,则使用 FileImage 加载图片
|
||||||
|
return Image.file(
|
||||||
|
File(imageUrl),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
|
// 文件加载失败时显示错误图片
|
||||||
|
return Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为网络地址
|
||||||
|
bool _isNetworkUrl(String url) {
|
||||||
|
final uri = Uri.tryParse(url);
|
||||||
|
return uri != null &&
|
||||||
|
uri.scheme.isNotEmpty &&
|
||||||
|
uri.scheme.startsWith('http');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,13 @@ class EditVideoLogState {
|
|||||||
if (map['lockId'] != null) {
|
if (map['lockId'] != null) {
|
||||||
getLockId.value = map['lockId'];
|
getLockId.value = map['lockId'];
|
||||||
}
|
}
|
||||||
|
if (map['isNavLocal'] != null) {
|
||||||
|
isNavLocal.value = map['isNavLocal'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RxList<RecordListData> selectVideoLogList = <RecordListData>[].obs; //选中的视频列表
|
RxList<RecordListData> selectVideoLogList = <RecordListData>[].obs; //选中的视频列表
|
||||||
RxBool isSelectAll = false.obs;
|
RxBool isSelectAll = false.obs;
|
||||||
RxList videoLogList = [].obs; //全部的视频列表
|
RxList videoLogList = <CloudStorageData>[].obs; //全部的视频列表
|
||||||
RxInt getLockId = 0.obs;
|
RxInt getLockId = 0.obs;
|
||||||
|
var isNavLocal = false.obs;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
import 'package:star_lock/network/api_repository.dart';
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
@ -28,6 +31,117 @@ class VideoLogLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 列出已下载的视频文件
|
||||||
|
Future<void> listDownloadedVideos() async {
|
||||||
|
Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
Directory downloadsDir = Directory('${appDocDir.path}/downloads');
|
||||||
|
|
||||||
|
if (await downloadsDir.exists()) {
|
||||||
|
List<FileSystemEntity> files = downloadsDir.listSync();
|
||||||
|
final list =
|
||||||
|
files.where((file) => file is File).map((file) => file.path).toList();
|
||||||
|
list.forEach((element) async {
|
||||||
|
final downloadTime = await getDownloadTime(element);
|
||||||
|
// 获取每一个文件夹对应的下载时间
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按天分组统计下载文件
|
||||||
|
Future<List<CloudStorageData>> groupDownloadsByDay() async {
|
||||||
|
final appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
final logFilePath = '${appDocDir.path}/download_log.json';
|
||||||
|
|
||||||
|
// 初始化结果映射
|
||||||
|
Map<String, List<RecordListData>> groupedDownloads = {};
|
||||||
|
|
||||||
|
if (await File(logFilePath).exists()) {
|
||||||
|
final content = await File(logFilePath).readAsString();
|
||||||
|
final logData = Map<String, int>.from(json.decode(content));
|
||||||
|
|
||||||
|
// 遍历所有记录
|
||||||
|
logData.forEach((filePath, timestamp) {
|
||||||
|
final downloadDateTime = DateTime.fromMillisecondsSinceEpoch(timestamp);
|
||||||
|
final dateKey =
|
||||||
|
'${downloadDateTime.year}-${downloadDateTime.month.toString().padLeft(2, '0')}-${downloadDateTime.day.toString().padLeft(2, '0')}';
|
||||||
|
|
||||||
|
// 如果日期不存在于映射中,则初始化为空列表
|
||||||
|
if (!groupedDownloads.containsKey(dateKey)) {
|
||||||
|
groupedDownloads[dateKey] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将文件记录添加到对应日期的列表中
|
||||||
|
if (filePath.endsWith('.jpg')) {
|
||||||
|
groupedDownloads[dateKey]?.add(
|
||||||
|
RecordListData(operateDate: timestamp, imagesUrl: filePath),
|
||||||
|
);
|
||||||
|
} else if (filePath.endsWith('.mp4')) {
|
||||||
|
groupedDownloads[dateKey]?.add(
|
||||||
|
RecordListData(operateDate: timestamp, videoUrl: filePath),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将分组结果转换为 CloudStorageData 列表
|
||||||
|
List<CloudStorageData> cloudStorageData = [];
|
||||||
|
groupedDownloads.forEach((dateKey, recordList) {
|
||||||
|
cloudStorageData.add(
|
||||||
|
CloudStorageData(date: dateKey, recordList: recordList),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
state.lockVideoList.value = cloudStorageData;
|
||||||
|
return cloudStorageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件的下载时间
|
||||||
|
Future<int?> getDownloadTime(String filePath) async {
|
||||||
|
final appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
final logFilePath = '${appDocDir.path}/download_log.json';
|
||||||
|
|
||||||
|
if (await File(logFilePath).exists()) {
|
||||||
|
final content = await File(logFilePath).readAsString();
|
||||||
|
final logData = Map<String, int>.from(json.decode(content));
|
||||||
|
return logData[filePath];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空下载目录和日志文件
|
||||||
|
Future<bool> clearDownloads() async {
|
||||||
|
try {
|
||||||
|
// 获取应用专属目录
|
||||||
|
Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
|
||||||
|
// 删除下载目录中的所有文件
|
||||||
|
final downloadsDir = Directory('${appDocDir.path}/downloads');
|
||||||
|
if (await downloadsDir.exists()) {
|
||||||
|
await downloadsDir.list().forEach((entity) {
|
||||||
|
if (entity is File) {
|
||||||
|
entity.delete(recursive: true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
print('下载目录已清空');
|
||||||
|
} else {
|
||||||
|
print('下载目录不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除日志文件
|
||||||
|
final logFilePath = '${appDocDir.path}/download_log.json';
|
||||||
|
if (await File(logFilePath).exists()) {
|
||||||
|
await File(logFilePath).delete();
|
||||||
|
print('日志文件已删除');
|
||||||
|
} else {
|
||||||
|
print('日志文件不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
print('清空失败:$e');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
onReady() {
|
onReady() {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -30,6 +32,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
// TODO: implement initState
|
// TODO: implement initState
|
||||||
super.initState();
|
super.initState();
|
||||||
|
logic.groupDownloadsByDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -50,53 +53,94 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
Visibility(visible: state.isNavLocal.value, child: localTip()),
|
Visibility(visible: state.isNavLocal.value, child: localTip()),
|
||||||
// title加编辑按钮
|
// title加编辑按钮
|
||||||
editVideoTip(),
|
editVideoTip(),
|
||||||
Obx(() => Visibility(
|
Obx(
|
||||||
|
() => Visibility(
|
||||||
visible: !state.isNavLocal.value,
|
visible: !state.isNavLocal.value,
|
||||||
child: Expanded(
|
child: state.videoLogList.length > 0
|
||||||
child: ListView.builder(
|
? Expanded(
|
||||||
itemCount: state.videoLogList.length,
|
child: ListView.builder(
|
||||||
itemBuilder: (BuildContext c, int index) {
|
itemCount: state.videoLogList.length,
|
||||||
final CloudStorageData item = state.videoLogList[index];
|
itemBuilder: (BuildContext c, int index) {
|
||||||
return Column(
|
final CloudStorageData item =
|
||||||
children: <Widget>[
|
state.videoLogList[index];
|
||||||
Container(
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(
|
||||||
|
left: 20.w, top: 15.w, bottom: 15.w),
|
||||||
|
child: Row(children: <Widget>[
|
||||||
|
Text(item.date ?? '',
|
||||||
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
|
])),
|
||||||
|
mainListView(index, item)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: _buildNotData(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 本地顶部
|
||||||
|
Obx(
|
||||||
|
() => Visibility(
|
||||||
|
visible: state.isNavLocal.value,
|
||||||
|
child: state.lockVideoList.length > 0
|
||||||
|
? Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: state.lockVideoList.length,
|
||||||
|
itemBuilder: (BuildContext c, int index) {
|
||||||
|
final CloudStorageData item =
|
||||||
|
state.lockVideoList[index];
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
left: 20.w, top: 15.w, bottom: 15.w),
|
left: 20.w, top: 15.w, bottom: 15.w),
|
||||||
child: Row(children: <Widget>[
|
child: Row(
|
||||||
Text(item.date ?? '',
|
children: <Widget>[
|
||||||
style: TextStyle(fontSize: 20.sp)),
|
Text(item.date ?? '',
|
||||||
])),
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
mainListView(index, item)
|
],
|
||||||
],
|
),
|
||||||
);
|
),
|
||||||
})))),
|
lockMainListView(index, item)
|
||||||
// 本地顶部
|
],
|
||||||
Visibility(
|
);
|
||||||
visible: state.isNavLocal.value,
|
},
|
||||||
child: Expanded(
|
),
|
||||||
child: state.localList.isNotEmpty
|
)
|
||||||
? ListView.builder(
|
: _buildNotData(),
|
||||||
itemCount: 5,
|
),
|
||||||
itemBuilder: (BuildContext c, int index) {
|
),
|
||||||
return Column(
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(
|
|
||||||
left: 20.w, top: 15.w, bottom: 15.w),
|
|
||||||
child: Row(children: <Widget>[
|
|
||||||
Text('2023.10.2$index',
|
|
||||||
style: TextStyle(fontSize: 20.sp)),
|
|
||||||
])),
|
|
||||||
mainListView(index, CloudStorageData()),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: NoData())),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildNotData() {
|
||||||
|
return Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'images/icon_noData.png',
|
||||||
|
width: 160.w,
|
||||||
|
height: 180.h,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'暂无数据'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.darkGrayTextColor, fontSize: 22.sp),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// nav按钮
|
// nav按钮
|
||||||
Widget navBtn() {
|
Widget navBtn() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
@ -109,6 +153,8 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
state.isNavLocal.value = false;
|
state.isNavLocal.value = false;
|
||||||
|
state.lockVideoList.clear();
|
||||||
|
// logic.clearDownloads();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Obx(() => Text('云存'.tr,
|
child: Obx(() => Text('云存'.tr,
|
||||||
@ -122,21 +168,27 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
fontSize: 28.sp,
|
fontSize: 28.sp,
|
||||||
fontWeight: FontWeight.w600)))),
|
fontWeight: FontWeight.w600)))),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
state.isNavLocal.value = true;
|
state.isNavLocal.value = true;
|
||||||
});
|
logic.groupDownloadsByDay();
|
||||||
},
|
});
|
||||||
child: Obx(() => Text('本地'.tr,
|
},
|
||||||
style: state.isNavLocal.value == true
|
child: Obx(
|
||||||
? TextStyle(
|
() => Text(
|
||||||
color: Colors.white,
|
'已下载'.tr,
|
||||||
fontSize: 28.sp,
|
style: state.isNavLocal.value == true
|
||||||
fontWeight: FontWeight.w600)
|
? TextStyle(
|
||||||
: TextStyle(
|
color: Colors.white,
|
||||||
color: Colors.grey,
|
fontSize: 28.sp,
|
||||||
fontSize: 26.sp,
|
fontWeight: FontWeight.w600)
|
||||||
fontWeight: FontWeight.w600)))),
|
: TextStyle(
|
||||||
|
color: Colors.grey,
|
||||||
|
fontSize: 26.sp,
|
||||||
|
fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -243,10 +295,21 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
iconSize: 30,
|
iconSize: 30,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.toNamed(Routers.editVideoLogPage, arguments: <String, Object>{
|
if (state.isNavLocal.value) {
|
||||||
'videoDataList': state.videoLogList.value,
|
Get.toNamed(Routers.editVideoLogPage,
|
||||||
'lockId': state.getLockId.value
|
arguments: <String, Object>{
|
||||||
});
|
'videoDataList': state.lockVideoList.value,
|
||||||
|
'lockId': state.getLockId.value,
|
||||||
|
'isNavLocal': state.isNavLocal.value
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Get.toNamed(Routers.editVideoLogPage,
|
||||||
|
arguments: <String, Object>{
|
||||||
|
'videoDataList': state.videoLogList.value,
|
||||||
|
'lockId': state.getLockId.value,
|
||||||
|
'isNavLocal': state.isNavLocal.value
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// TextButton(
|
// TextButton(
|
||||||
@ -286,6 +349,28 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget lockMainListView(int index, CloudStorageData itemData) {
|
||||||
|
return GridView.builder(
|
||||||
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
|
itemCount: itemData.recordList!.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
//横轴元素个数
|
||||||
|
crossAxisCount: 3,
|
||||||
|
//纵轴间距
|
||||||
|
mainAxisSpacing: 15.w,
|
||||||
|
// 横轴间距
|
||||||
|
crossAxisSpacing: 15.w,
|
||||||
|
//子组件宽高长度比例
|
||||||
|
childAspectRatio: itemW / itemH),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
final RecordListData recordData = itemData.recordList![index];
|
||||||
|
return videoItem(recordData);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget videoItem(RecordListData recordData) {
|
Widget videoItem(RecordListData recordData) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -323,9 +408,10 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 5.h),
|
SizedBox(height: 5.h),
|
||||||
Text(
|
Text(
|
||||||
DateTool().dateToYMDHNString(recordData.operateDate.toString()),
|
DateTool().dateToYMDHNString(recordData.operateDate.toString()),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(fontSize: 18.sp))
|
style: TextStyle(fontSize: 18.sp),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -347,21 +433,56 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
_buildImageItem(RecordListData recordData) {
|
_buildImageItem(RecordListData recordData) {
|
||||||
return RotatedBox(
|
return RotatedBox(
|
||||||
quarterTurns: -1,
|
quarterTurns: -1,
|
||||||
child: Image.network(
|
child: _buildImageWidget(recordData.imagesUrl),
|
||||||
recordData.imagesUrl!,
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据图片路径构建对应的 Image Widget
|
||||||
|
Widget _buildImageWidget(String? imageUrl) {
|
||||||
|
if (imageUrl == null || imageUrl.isEmpty) {
|
||||||
|
// 如果图片路径为空,返回错误图片
|
||||||
|
return Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为网络地址
|
||||||
|
if (_isNetworkUrl(imageUrl)) {
|
||||||
|
return Image.network(
|
||||||
|
imageUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
errorBuilder:
|
errorBuilder:
|
||||||
(BuildContext context, Object error, StackTrace? stackTrace) {
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
// 图片加载失败时显示错误图片
|
// 图片加载失败时显示错误图片
|
||||||
return RotatedBox(
|
return Image.asset(
|
||||||
quarterTurns: -1,
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
child: Image.asset(
|
fit: BoxFit.cover,
|
||||||
'images/icon_unHaveData.png', // 错误图片路径
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
);
|
} else {
|
||||||
|
// 如果是本地文件路径,则使用 FileImage 加载图片
|
||||||
|
return Image.file(
|
||||||
|
File(imageUrl),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder:
|
||||||
|
(BuildContext context, Object error, StackTrace? stackTrace) {
|
||||||
|
// 文件加载失败时显示错误图片
|
||||||
|
return Image.asset(
|
||||||
|
'images/icon_unHaveData.png', // 错误图片路径
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为网络地址
|
||||||
|
bool _isNetworkUrl(String url) {
|
||||||
|
final uri = Uri.tryParse(url);
|
||||||
|
return uri != null &&
|
||||||
|
uri.scheme.isNotEmpty &&
|
||||||
|
uri.scheme.startsWith('http');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ class VideoLogState {
|
|||||||
var localList = [];
|
var localList = [];
|
||||||
var getLockId = 0.obs;
|
var getLockId = 0.obs;
|
||||||
var videoLogList = <CloudStorageData>[].obs;
|
var videoLogList = <CloudStorageData>[].obs;
|
||||||
|
var lockVideoList = <CloudStorageData>[].obs;
|
||||||
var videoCoverList = <Uint8List>[].obs;
|
var videoCoverList = <Uint8List>[].obs;
|
||||||
|
|
||||||
VideoLogState() {
|
VideoLogState() {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
import 'package:photo_view/photo_view_gallery.dart';
|
import 'package:photo_view/photo_view_gallery.dart';
|
||||||
@ -11,18 +13,42 @@ class FullScreenImagePage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
onTap: (){
|
onTap: () {
|
||||||
Navigator.pop(context); // 点击图片返回
|
Navigator.pop(context); // 点击图片返回
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
child: RotatedBox(
|
child: RotatedBox(
|
||||||
quarterTurns: -1,
|
quarterTurns: -1,
|
||||||
child: PhotoView(
|
child: PhotoView(
|
||||||
imageProvider: NetworkImage(imageUrl),
|
imageProvider:
|
||||||
|
_getImageProvider(imageUrl), // 根据 imageUrl 动态选择图片加载方式
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// 根据 imageUrl 判断并返回对应的 ImageProvider
|
||||||
|
ImageProvider<Object> _getImageProvider(String? imageUrl) {
|
||||||
|
if (imageUrl == null || imageUrl.isEmpty) {
|
||||||
|
// 如果图片路径为空,返回默认的占位图片
|
||||||
|
return AssetImage('images/icon_unHaveData.png'); // 默认占位图片路径
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为网络地址
|
||||||
|
if (_isNetworkUrl(imageUrl)) {
|
||||||
|
return NetworkImage(imageUrl); // 网络图片
|
||||||
|
} else {
|
||||||
|
return FileImage(File(imageUrl)); // 本地文件图片
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为网络地址
|
||||||
|
bool _isNetworkUrl(String url) {
|
||||||
|
final uri = Uri.tryParse(url);
|
||||||
|
return uri != null &&
|
||||||
|
uri.scheme.isNotEmpty &&
|
||||||
|
uri.scheme.startsWith('http');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -491,25 +491,12 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 查询锁设置信息
|
// 查询锁设置信息
|
||||||
final LockSetInfoEntity entity =
|
final LockSetInfoEntity entity =
|
||||||
await ApiRepository.to.getLockSettingInfoDataIsNotLoadingIcon(
|
await ApiRepository.to.getLockSettingInfoData(
|
||||||
lockId: state.lockId.toString(),
|
lockId: state.lockId.toString(),
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.lockSetInfoData.value = entity.data!;
|
state.lockSetInfoData.value = entity.data!;
|
||||||
if (state.lockSetInfoData.value.lockFeature?.wifi == 1) {
|
if (state.lockSetInfoData.value.lockFeature?.wifi == 1) {
|
||||||
// await Future<void>.delayed(const Duration(seconds: 1), () {c
|
|
||||||
// Get.close(state.isFromMap == 1
|
|
||||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
|
||||||
// : (CommonDataManage().seletLockType == 0 ? 5 : 6));
|
|
||||||
// });
|
|
||||||
// //刚刚配对完,需要对开锁页锁死 2 秒
|
|
||||||
// await Future<void>.delayed(const Duration(milliseconds: 200), () {
|
|
||||||
// if (Get.isRegistered<LockDetailLogic>()) {
|
|
||||||
// Get.find<LockDetailLogic>()
|
|
||||||
// .functionBlocker
|
|
||||||
// .countdownProhibited(duration: const Duration(seconds: 2));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// 如果是wifi锁,需要配置WIFI
|
// 如果是wifi锁,需要配置WIFI
|
||||||
Get.toNamed(Routers.wifiListPage, arguments: {
|
Get.toNamed(Routers.wifiListPage, arguments: {
|
||||||
'lockSetInfoData': state.lockSetInfoData.value,
|
'lockSetInfoData': state.lockSetInfoData.value,
|
||||||
|
|||||||
@ -1811,6 +1811,9 @@ class ApiProvider extends BaseProvider {
|
|||||||
Future<Response> getGatewayConfiguration(int timeout) =>
|
Future<Response> getGatewayConfiguration(int timeout) =>
|
||||||
post(getGatewayConfigURL.toUrl, jsonEncode({}), timeout: timeout);
|
post(getGatewayConfigURL.toUrl, jsonEncode({}), timeout: timeout);
|
||||||
|
|
||||||
|
Future<Response> getGatewayConfigurationNotLoading(int timeout) =>
|
||||||
|
post(getGatewayConfigURL.toUrl, jsonEncode({}), timeout: timeout,isUnShowLoading: true);
|
||||||
|
|
||||||
Future<Response> gatewayConnectionLockListLoadData(
|
Future<Response> gatewayConnectionLockListLoadData(
|
||||||
int gatewayId, int timeout) =>
|
int gatewayId, int timeout) =>
|
||||||
post(gatewayListByLockURL.toUrl, jsonEncode({'gatewayId': gatewayId}),
|
post(gatewayListByLockURL.toUrl, jsonEncode({'gatewayId': gatewayId}),
|
||||||
|
|||||||
@ -2010,6 +2010,14 @@ class ApiRepository {
|
|||||||
return GetGatewayConfigurationEntity.fromJson(res.body);
|
return GetGatewayConfigurationEntity.fromJson(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取网关配置
|
||||||
|
Future<GetGatewayConfigurationEntity> getGatewayConfigurationNotLoading(
|
||||||
|
{required int timeout}) async {
|
||||||
|
final res = await apiProvider.getGatewayConfigurationNotLoading(timeout);
|
||||||
|
return GetGatewayConfigurationEntity.fromJson(res.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 移除坏锁
|
// 移除坏锁
|
||||||
Future<RecipientInformationEntity> removeBrokenLockData(
|
Future<RecipientInformationEntity> removeBrokenLockData(
|
||||||
{required List lockIdList}) async {
|
{required List lockIdList}) async {
|
||||||
|
|||||||
@ -186,7 +186,7 @@ dependencies:
|
|||||||
lpinyin: ^2.0.3
|
lpinyin: ^2.0.3
|
||||||
#加密解密
|
#加密解密
|
||||||
# encrypt: ^5.0.1
|
# encrypt: ^5.0.1
|
||||||
# crypto: ^3.0.3
|
crypto: ^3.0.3
|
||||||
pointycastle: ^3.7.3 # 使用最新版本
|
pointycastle: ^3.7.3 # 使用最新版本
|
||||||
date_format: ^2.0.7
|
date_format: ^2.0.7
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user