import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:star_lock/appRouters.dart'; import 'package:star_lock/main/lockDetail/videoLog/editVideoLog/editVideoLog_state.dart'; import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart'; import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart'; import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart'; import 'package:star_lock/tools/dateTool.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../tools/titleAppBar.dart'; import 'editVideoLog_logic.dart'; class EditVideoLogPage extends StatefulWidget { const EditVideoLogPage({Key? key}) : super(key: key); @override State createState() => _EditVideoLogPageState(); } class _EditVideoLogPageState extends State { final EditVideoLogLogic logic = Get.put(EditVideoLogLogic()); final EditVideoLogState state = Get.find().state; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: TitleAppBar( barTitle: '${'已选'.tr}${state.selectVideoLogList.value.length}${'项'.tr}', haveBack: true, backgroundColor: AppColors.mainColor, actionsList: [ TextButton( child: Text( '全选'.tr, style: TextStyle(color: Colors.white, fontSize: 24.sp), ), onPressed: () async { state.isSelectAll.value = !state.isSelectAll.value; if (state.selectVideoLogList.isEmpty) { state.isSelectAll.value = true; } if (state.selectVideoLogList.length == state.videoLogList.length) { state.isSelectAll.value = false; } if (state.isSelectAll.value == true) { state.selectVideoLogList.clear(); for (var element in state.videoLogList) { element.recordList!.forEach((element) { element.isSelect = true; state.selectVideoLogList.add(element); }); } } else { state.selectVideoLogList.clear(); for (var element in state.videoLogList) { element.recordList!.forEach((element) { element.isSelect = false; state.selectVideoLogList.remove(element); }); } } setState(() {}); }, ), ], ), body: Column( children: [ Expanded( child: Obx( () => ListView.builder( itemCount: state.videoLogList.length, itemBuilder: (BuildContext c, int index) { final CloudStorageData item = state.videoLogList[index]; return ExpansionTile( shape: Border(), collapsedShape: Border(), expansionAnimationStyle: AnimationStyle( curve: Curves.easeInOut, duration: Duration(milliseconds: 400), ), initiallyExpanded: true, title: Text( item.date ?? '', style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.w600, ), ), children: mainListView(index, item), ); }, ), ), ), bottomBottomBtnWidget() ], ), ); } 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), ) ], ), ), ); } double itemW = (1.sw - 15.w * 4) / 3; double itemH = (1.sw - 15.w * 4) / 3 + 40.h; // 云存列表 List mainListView(int index, CloudStorageData itemData) { return itemData.recordList!.map((e) => videoItem(e)).toList(); } // Widget videoItem(RecordListData recordData, int index) { // return Container( // width: itemW, // height: itemH, // color: Colors.white, // child: GestureDetector( // onTap: () { // recordData.isSelect = !recordData.isSelect!; // if (recordData.isSelect! == true) { // state.selectVideoLogList.add(recordData); // } else { // state.selectVideoLogList.remove(recordData); // } // setState(() {}); // }, // child: Stack( // children: [ // Column( // children: [ // Container( // width: itemW, // height: itemW, // margin: const EdgeInsets.all(0), // color: Colors.white, // child: ClipRRect( // borderRadius: BorderRadius.circular(10.w), // child: Image( // fit: BoxFit.cover, // image: Image.network(recordData.imagesUrl ?? // 'images/icon_video_placeholder.jpg') // .image), // ), // ), // SizedBox(height: 5.h), // Text( // DateTool() // .dateToYMDHNString(recordData.operateDate.toString()), // textAlign: TextAlign.center, // style: TextStyle(fontSize: 18.sp)) // ], // ), // Positioned( // top: 0.w, // right: 0.w, // child: Image( // width: 36.w, // height: 36.w, // image: state.selectVideoLogList.value.contains(recordData) // ? const AssetImage('images/icon_round_select.png') // : const AssetImage('images/icon_round_unSelect.png'))) // ], // )), // ); // } Widget bottomBottomBtnWidget() { return SizedBox( width: 1.sw, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ state.isNavLocal.value == false ? bottomBtnItemWidget( 'images/main/icon_lockDetail_monitoringDownloadVideo.png', '下载'.tr, Colors.white, _onDownLoadClickAndRequestPermission, ) : SizedBox.shrink(), state.isNavLocal.value == false ? SizedBox(width: 100.w) : SizedBox.shrink(), bottomBtnItemWidget( 'images/main/icon_lockDetail_monitoringDeletVideo.png', '删除'.tr, AppColors.mainColor, _onDelClick, ) ], ), ); } Future _onDownLoadClickAndRequestPermission() async { // 检查是否具有存储权限 final PermissionStatus status = await Permission.storage.status; if (status.isGranted) { // 如果权限已授予,执行下载逻辑 await _onDownLoadClick(); } else if (status.isDenied || status.isRestricted) { // 如果权限被拒绝或受限,请求权限 final PermissionStatus requestResult = await Permission.storage.request(); if (requestResult.isGranted) { // 权限请求成功后,执行下载逻辑 await _onDownLoadClick(); } else { // 用户拒绝了权限请求 print('用户拒绝了存储权限'); } } else if (status.isPermanentlyDenied) { // 如果权限被永久拒绝,提示用户前往设置页面手动开启 print('存储权限被永久拒绝,请前往设置页面开启'); openAppSettings(); } } Future _onDownLoadClick() async { if (state.selectVideoLogList.value.isNotEmpty) { state.selectVideoLogList.value.forEach((element) { if (element.videoUrl != null && element.videoUrl != '') { logic.downloadFile(element.videoUrl ?? '', element.recordType!); } else if (element.imagesUrl != null && element.imagesUrl != '') { logic.downloadFile(element.imagesUrl ?? '', element.recordType!); } }); // double _progress = 0.0; // 开始下载 // 显示进度条 // EasyLoading.showProgress(_progress, status: '加载数据中'.tr); // // // 模拟进度更新 // for (int i = 0; i <= state.selectVideoLogList.length - 1; i++) { // final item = state.selectVideoLogList.value[i]; // // // 判断 imagesUrl 是否为空 // if (item.imagesUrl != null && item.imagesUrl!.isNotEmpty) { // await logic.downloadAndSaveToGallery(item.imagesUrl!, 'image_$i.jpg'); // } // // // 判断 videoUrl 是否为空 // if (item.videoUrl != null && item.videoUrl!.isNotEmpty) { // await logic.downloadAndSaveToGallery(item.videoUrl!, 'video_$i.mp4'); // } // // // 更新进度 // _progress = (i + 1) / state.selectVideoLogList.length; // EasyLoading.showProgress(_progress, status: '加载数据中'.tr); // } // // // 加载完成后隐藏进度条 // EasyLoading.dismiss(); // EasyLoading.showSuccess('下载完成,请到相册查看'.tr); EasyLoading.showSuccess('下载完成'.tr); state.selectVideoLogList.clear(); Get.back(); setState(() {}); // Get.toNamed(Routers.videoLogDownLoadPage, // arguments: >{ // 'downloadVideoLogList': state.selectVideoLogList.value // }); } else { logic.showToast('请选择要下载的视频'); } } Future _onDelClick() async { if (state.isNavLocal.isFalse) { if (state.selectVideoLogList.value.isNotEmpty) { await logic.deleteLockCloudStorageList(); setState(() {}); } else { logic.showToast('请选择要删除的视频'.tr); } } else { if (state.selectVideoLogList.value.isNotEmpty) { List 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); } } } Widget bottomBtnItemWidget( String iconUrl, String name, Color backgroundColor, Future Function() onClick, ) { final double wh = 40.w; return GestureDetector( onTap: onClick, child: SizedBox( height: 140.h, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 30.w), Image.asset(iconUrl, width: wh, height: wh, fit: BoxFit.fitWidth), SizedBox(height: 10.w), Expanded( child: Text(name, style: TextStyle(fontSize: 22.sp), textAlign: TextAlign.center), ) ], ), ), ); } Widget videoItem(RecordListData recordData) { return GestureDetector( onTap: () { recordData.isSelect = !recordData.isSelect!; if (recordData.isSelect! == true) { state.selectVideoLogList.add(recordData); } else { state.selectVideoLogList.remove(recordData); } setState(() {}); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 20.w), margin: EdgeInsets.only( bottom: 20.h, left: 18.w, right: 18.w, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10.w), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.2), spreadRadius: 1, blurRadius: 5, offset: const Offset(0, 3), // changes position of shadow ), ], ), width: 1.sw, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Image( width: 36.w, height: 36.w, image: state.selectVideoLogList.value.contains(recordData) ? const AssetImage('images/icon_round_select.png') : const AssetImage('images/icon_round_unSelect.png'), ), SizedBox( width: 14.w, ), Container( padding: EdgeInsets.all(10.w), decoration: BoxDecoration( borderRadius: BorderRadius.circular(58.w), color: AppColors.mainColor, ), child: Icon( _buildIconByType(recordData), size: 48.sp, color: Colors.white, ), ), SizedBox( width: 14.w, ), Container( height: itemW, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( _buildTitleByType(recordData), style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.w600, ), ), SizedBox( height: 8.h, ), Text( DateTool() .dateToHNString(recordData.operateDate.toString()), textAlign: TextAlign.center, style: TextStyle( fontSize: 20.sp, fontWeight: FontWeight.w600, ), ), ], ), ), ], ), Container( width: 118.w, height: 118.w, margin: const EdgeInsets.all(0), color: Colors.white, child: ClipRRect( borderRadius: BorderRadius.circular(10.w), child: _buildImageOrVideoItem(recordData), ), ), ], ), ), ); } String _buildTitleByType(RecordListData item) { final recordType = item.recordType; switch (recordType) { case 130: return '防拆报警'.tr; case 160: return '人脸'.tr + '开锁'.tr; case 220: return '逗留警告'.tr; default: return ''; } } IconData _buildIconByType(RecordListData item) { final recordType = item.recordType; switch (recordType) { case 130: return Icons.fmd_bad_outlined; case 160: return Icons.tag_faces_outlined; case 220: return Icons.wifi_tethering_error_rounded_outlined; default: return Icons.priority_high_rounded; } } Color _buildTextColorByType(RecordListData item) { final recordType = item.recordType; switch (recordType) { case 120: case 150: case 130: case 190: case 200: case 210: case 220: return Colors.red; default: return Colors.black; } } _buildImageOrVideoItem(RecordListData recordData) { if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) { return _buildVideoItem(recordData); } else { return _buildImageItem(recordData); } } _buildVideoItem(RecordListData recordData) { return VideoThumbnailImage(videoUrl: recordData.videoUrl!); } _buildImageItem(RecordListData recordData) { return RotatedBox( quarterTurns: -1, child: _buildImageWidget(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, errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { // 图片加载失败时显示错误图片 return Image.asset( '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'); } }