371 lines
11 KiB
Dart
Executable File

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<VideoLogDetailPage> createState() => _VideoLogDetailPageState();
}
class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
final VideoLogDetailLogic logic = Get.put(VideoLogDetailLogic());
final VideoLogDetailState state = Get.find<VideoLogDetailLogic>().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: <Widget>[
Container(
color: Colors.black,
height: 500.h,
width: 1.sw,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
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: <Widget>[
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: <Widget>[
Container(
margin: EdgeInsets.only(left: 20.w, top: 15.w, bottom: 15.w),
child: Row(
children: <Widget>[
Text(item.date ?? '',
style: TextStyle(
fontSize: 24.sp, fontWeight: FontWeight.w600)),
],
),
),
...mainListView(index, item),
],
);
},
),
);
}
// 云存列表
List<Widget> 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,
),
),
],
),
);
}
}