fix:增加视频日志中的视频缩略图

This commit is contained in:
liyi 2025-01-21 14:09:09 +08:00
parent 4f6781a0b0
commit de6d7bca58
8 changed files with 109 additions and 167 deletions

View File

@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
#distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-7.4-all.zip

View File

@ -9,7 +9,7 @@ import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_state.dart';
import 'package:star_lock/main/lockDetail/doorLockLog/exportRecordDialog/exportRecordDialog_page.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.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
import 'package:star_lock/tools/EasyRefreshTool.dart';
import 'package:star_lock/tools/advancedCalendar/src/widget.dart';
import 'package:star_lock/tools/commonDataManage.dart';
@ -399,7 +399,7 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
}
_buildVideoItem(RecordListData recordData) {
return VideoThumbnail(videoUrl: recordData.videoUrl!);
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
}
_buildImageItem(RecordListData recordData) {

View File

@ -6,7 +6,7 @@ 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.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';
@ -241,61 +241,8 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
Future<void> _onDelClick() async {
if (state.selectVideoLogList.value.isNotEmpty) {
//
bool confirmDelete = await showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'确认删除'.tr,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
Text('确定要删除选中的视频吗?'.tr),
SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
// false
Navigator.of(context).pop(false);
},
child: Text('取消'.tr),
),
SizedBox(width: 8),
ElevatedButton(
onPressed: () {
// true
Navigator.of(context).pop(true);
},
child: Text('确认'.tr),
),
],
),
],
),
),
);
},
);
//
if (confirmDelete == true) {
await logic.deleteLockCloudStorageList();
}
await logic.deleteLockCloudStorageList();
setState(() {});
} else {
logic.showToast('请选择要删除的视频'.tr);
}
@ -412,7 +359,7 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
}
_buildVideoItem(RecordListData recordData) {
return VideoThumbnail(videoUrl: recordData.videoUrl!);
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
}
_buildImageItem(RecordListData recordData) {

View File

@ -22,38 +22,12 @@ class VideoLogLogic extends BaseGetXController {
(record.imagesUrl != null && record.imagesUrl!.isNotEmpty) ||
(record.videoUrl != null && record.videoUrl!.isNotEmpty))
.toList();
// // videoUrl
// for (var record in element.recordList!) {
// if (record.videoUrl != null && record.videoUrl!.isNotEmpty) {
// _setVideoThumbnail(record); //
// }
// }
});
state.videoLogList.refresh();
}
}
// Future<void> _setVideoThumbnail(RecordListData record) async {
// try {
// final thumbnailData = await getVideoThumbnail(record.videoUrl!);
// record.thumbnailData = thumbnailData; //
// } catch (e) {
// print('获取视频封面失败: $e');
// }
// }
//
// Future<Uint8List?> getVideoThumbnail(String videoUrl) async {
// final thumbnail = await VideoThumbnail.thumbnailData(
// video: videoUrl,
// imageFormat: ImageFormat.JPEG,
// maxWidth: 128, //
// quality: 25, // 0-100
// );
// return thumbnail;
// }
@override
onReady() {
super.onReady();

View File

@ -6,7 +6,7 @@ import 'package:star_lock/flavors.dart';
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_state.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
import 'package:star_lock/tools/dateTool.dart';
import 'package:star_lock/tools/noData.dart';
import 'package:video_player/video_player.dart';
@ -341,7 +341,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
}
_buildVideoItem(RecordListData recordData) {
return VideoThumbnail(videoUrl: recordData.videoUrl!);
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
}
_buildImageItem(RecordListData recordData) {

View File

@ -8,7 +8,7 @@ import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart
import 'package:star_lock/main/lockDetail/videoLog/videoLogDetail/controlsOverlay_page.dart';
import 'package:star_lock/main/lockDetail/videoLog/videoLogDetail/videoLogDetail_state.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/full_screenImage_page.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail.dart';
import 'package:star_lock/main/lockDetail/videoLog/widget/video_thumbnail_image.dart';
import 'package:star_lock/tools/dateTool.dart';
import 'package:video_player/video_player.dart';
@ -165,7 +165,7 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
}
_buildVideoItem(RecordListData recordData) {
return VideoThumbnail(videoUrl: recordData.videoUrl!);
return VideoThumbnailImage(videoUrl: recordData.videoUrl!);
}
_buildImageItem(RecordListData recordData) {

View File

@ -1,76 +0,0 @@
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class VideoThumbnail extends StatefulWidget {
final String videoUrl;
VideoThumbnail({required this.videoUrl});
@override
_VideoThumbnailState createState() => _VideoThumbnailState();
}
class _VideoThumbnailState extends State<VideoThumbnail> {
late VideoPlayerController _controller;
late Future<void> _initializeVideoPlayerFuture;
@override
void initState() {
super.initState();
// VideoPlayerController
_controller = VideoPlayerController.network(widget.videoUrl)
..initialize().then((_) {
// UI以便显示第一帧
setState(() {});
});
}
@override
void dispose() {
//
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
// onTap: () {
// setState(() {
// if (_controller.value.isPlaying) {
// _controller.pause();
// } else {
// _controller.play();
// }
// });
// },
child: Stack(
alignment: Alignment.center,
children: <Widget>[
//
_controller.value.isInitialized
? RotatedBox(
quarterTurns: -1,
child: AspectRatio(
aspectRatio: 1 / 1, //
child: FittedBox(
fit: BoxFit.cover, //
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: VideoPlayer(_controller),
),
),
),
)
: Center(
child: CircularProgressIndicator(), //
),
if (!_controller.value.isPlaying && _controller.value.isInitialized)
Icon(Icons.play_arrow_rounded,
size: 80, color: Colors.white.withOpacity(0.8)),
],
),
);
}
}

View File

@ -0,0 +1,97 @@
import 'dart:io'; // dart:io 使 File
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:path_provider/path_provider.dart'; // path_provider
import 'package:video_thumbnail/video_thumbnail.dart'; // video_thumbnail
class VideoThumbnailImage extends StatefulWidget {
final String videoUrl;
VideoThumbnailImage({required this.videoUrl});
@override
_VideoThumbnailState createState() => _VideoThumbnailState();
}
class _VideoThumbnailState extends State<VideoThumbnailImage> {
final Map<String, String> _thumbnailCache = {}; //
late Future<String?> _thumbnailFuture; // Future
@override
void initState() {
super.initState();
_thumbnailFuture = _generateThumbnail(); // initState Future
}
//
Future<String?> _generateThumbnail() async {
try {
//
if (_thumbnailCache.containsKey(widget.videoUrl)) {
return _thumbnailCache[widget.videoUrl];
}
//
final tempDir = await getTemporaryDirectory();
final thumbnailPath = await VideoThumbnail.thumbnailFile(
video: widget.videoUrl,
// URL
thumbnailPath: tempDir.path,
//
imageFormat: ImageFormat.JPEG,
//
maxHeight: 200,
//
quality: 100, // (0-100)
);
//
_thumbnailCache[widget.videoUrl] = thumbnailPath!;
return thumbnailPath;
} catch (e) {
print('Failed to generate thumbnail: $e');
return null;
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder<String?>(
future: _thumbnailFuture, // Future
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
//
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError || !snapshot.hasData) {
//
return Image.asset(
'images/icon_unHaveData.png', //
fit: BoxFit.cover,
);
} else {
//
final thumbnailPath = snapshot.data!;
return Stack(
alignment: Alignment.center,
children: <Widget>[
RotatedBox(
quarterTurns: -1,
child: Image.file(
File(thumbnailPath), //
width: 200,
height: 200,
fit: BoxFit.cover,
),
),
Icon(
Icons.play_arrow_rounded,
size: 80,
color: Colors.white.withOpacity(0.8),
),
],
);
}
},
);
}
}