import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/appRouters.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/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_image.dart'; import 'package:star_lock/tools/dateTool.dart'; import 'package:video_player/video_player.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../tools/titleAppBar.dart'; import 'videoLogDetail_logic.dart'; class VideoLogDetailPage extends StatefulWidget { const VideoLogDetailPage({Key? key}) : super(key: key); @override State createState() => _VideoLogDetailPageState(); } class _VideoLogDetailPageState extends State { final VideoLogDetailLogic logic = Get.put(VideoLogDetailLogic()); final VideoLogDetailState state = Get.find().state; @override void initState() { super.initState(); AppLog.log( 'state.recordData.value.videoUrl!' + state.recordData.value.videoUrl!); state.videoController = createVideoController(state.recordData.value.videoUrl!); state.videoController.addListener(() { setState(() {}); }); state.videoController.setLooping(false); state.videoController.initialize(); } void _initializeVideoPlayer(String videoUrl) async { if (state.videoController != null) { await state.videoController.dispose(); // 释放旧资源 } state.videoController = createVideoController(state.recordData.value.videoUrl!); // 初始化完成后通知框架重新构建界面 await state.videoController.initialize(); state.videoController.addListener(() { setState(() {}); }); setState(() {}); } VideoPlayerController createVideoController(String url) { if (url.startsWith('http://') || url.startsWith('https://')) { return VideoPlayerController.networkUrl( Uri.parse(url), videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true), ); } else { final file = File( url.startsWith('file://') ? url.replaceFirst('file://', '') : url); return VideoPlayerController.file( file, videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true), ); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: TitleAppBar( barTitle: '视频播放'.tr, haveBack: true, backgroundColor: AppColors.mainColor, ), body: state.videoController.value.isInitialized ? Column( children: [ Container( color: Colors.black, height: 500.h, width: 1.sw, child: Stack( alignment: Alignment.bottomCenter, children: [ RotatedBox( quarterTurns: -1, child: AspectRatio( aspectRatio: state.videoController.value.size.width / state.videoController.value.size.height, child: VideoPlayer(state.videoController), ), ), ControlsOverlay( controller: state.videoController, recordData: state.recordData.value, ), if (state.videoController.value.isPlaying || state.videoController.value.isBuffering) Container() else VideoProgressIndicator( state.videoController, colors: VideoProgressColors( playedColor: AppColors.mainColor), allowScrubbing: true, ), ], ), ), // _buildTitleRow(), _buildOther(), ], ) : Center( child: CircularProgressIndicator(), ), ); } double itemW = (1.sw - 15.w * 4) / 3; double itemH = (1.sw - 15.w * 4) / 3 + 40.h; Widget videoItem(RecordListData recordData) { return GestureDetector( onTap: () { if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) { state.recordData.value = recordData; _initializeVideoPlayer(recordData.videoUrl!); setState(() {}); } else if (recordData.imagesUrl != null && recordData.imagesUrl!.isNotEmpty) { Navigator.push( context, MaterialPageRoute( builder: (context) => FullScreenImagePage( imageUrl: recordData.imagesUrl!, ), ), ); } }, 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: [ 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), ), ), ], ), ), ); } _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: Image.network( recordData.imagesUrl!, fit: BoxFit.cover, errorBuilder: (BuildContext context, Object error, StackTrace? stackTrace) { // 图片加载失败时显示错误图片 return RotatedBox( quarterTurns: -1, child: Image.asset( 'images/icon_unHaveData.png', // 错误图片路径 fit: BoxFit.cover, ), ); }, ), ); } String formatString(time) { String shortName = time.toString().substring(2, 7); return shortName; } @override void dispose() { super.dispose(); state.videoController.dispose(); } _buildOther() { return Expanded( child: ListView.builder( itemCount: state.videoLogList.length, itemBuilder: (BuildContext c, int index) { CloudStorageData item = state.videoLogList[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only(left: 20.w, top: 15.w, bottom: 15.w), child: Row( children: [ Text(item.date ?? '', style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.w600)), ], ), ), ...mainListView(index, item), ], ); }, ), ); } // 云存列表 List mainListView(int index, CloudStorageData itemData) { return itemData.recordList!.map((e) => videoItem(e)).toList(); } 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; } } _buildItem(itemData) { return videoItem(itemData); } _buildTitleRow() { return Container( decoration: BoxDecoration( color: Colors.white, ), padding: EdgeInsets.only(left: 15.w, top: 24.w, bottom: 24.w), child: Row( children: [ Text( _buildTitleByType(state.recordData.value) ?? '', style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.w600, ), ), ], ), ); } }