1,更新视频播放器插件版本
2,新增视频日志云存列表接口对接及视频列表逻辑处理 3,完成点击云存列表播放当前MP4格式的视频以及页面完善逻辑处理 4,新增编辑视频页面数据接口对接
This commit is contained in:
parent
7fdc1e6e6d
commit
af59247c46
@ -46,7 +46,7 @@
|
|||||||
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
|
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
|
||||||
|
|
||||||
|
|
||||||
<application android:label="@string/app_name" android:name="android.app.Application" android:icon="@mipmap/ic_launcher">
|
<application android:usesCleartextTraffic="true" android:label="@string/app_name" android:name="android.app.Application" android:icon="@mipmap/ic_launcher">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
|||||||
BIN
star_lock/images/icon_video_placeholder.jpg
Normal file
BIN
star_lock/images/icon_video_placeholder.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
@ -779,5 +779,13 @@
|
|||||||
"添加和使用面容开锁时:":"Add and use Face when unlocking:",
|
"添加和使用面容开锁时:":"Add and use Face when unlocking:",
|
||||||
"关锁":"close lock",
|
"关锁":"close lock",
|
||||||
"功能":"function",
|
"功能":"function",
|
||||||
"配件":"parts"
|
"配件":"parts",
|
||||||
|
"云存":"Cloud storage",
|
||||||
|
"本地":"This locality",
|
||||||
|
"3天滚动储存":"3 days rolling storage",
|
||||||
|
"去升级":"Upgrade Now",
|
||||||
|
"下载列表":"Download list",
|
||||||
|
"已下载":"Downloaded",
|
||||||
|
"全部视频":"All videos",
|
||||||
|
"已为本设备免费提供3大滚动视频储存服务":"Three scrolling video storage services have been provided for this device free of charge"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -778,5 +778,13 @@
|
|||||||
"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网":"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网",
|
"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网":"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网",
|
||||||
"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。":"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。",
|
"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。":"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。",
|
||||||
"门未开时间":"门未开时间",
|
"门未开时间":"门未开时间",
|
||||||
"添加和使用面容开锁时:":"添加和使用面容开锁时:"
|
"添加和使用面容开锁时:":"添加和使用面容开锁时:",
|
||||||
|
"云存":"云存",
|
||||||
|
"本地":"本地",
|
||||||
|
"3天滚动储存":"3天滚动储存",
|
||||||
|
"去升级":"去升级",
|
||||||
|
"下载列表":"下载列表",
|
||||||
|
"已下载":"已下载",
|
||||||
|
"全部视频":"全部视频",
|
||||||
|
"已为本设备免费提供3大滚动视频储存服务":"已为本设备免费提供3大滚动视频储存服务"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -781,5 +781,13 @@
|
|||||||
"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网":"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网",
|
"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网":"经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网",
|
||||||
"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。":"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。",
|
"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。":"打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。",
|
||||||
"门未开时间":"门未开时间",
|
"门未开时间":"门未开时间",
|
||||||
"添加和使用面容开锁时:":"添加和使用面容开锁时:"
|
"添加和使用面容开锁时:":"添加和使用面容开锁时:",
|
||||||
|
"云存":"云存",
|
||||||
|
"本地":"本地",
|
||||||
|
"3天滚动储存":"3天滚动储存",
|
||||||
|
"去升级":"去升级",
|
||||||
|
"下载列表":"下载列表",
|
||||||
|
"已下载":"已下载",
|
||||||
|
"全部视频":"全部视频",
|
||||||
|
"已为本设备免费提供3大滚动视频储存服务":"已为本设备免费提供3大滚动视频储存服务"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
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';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
|
import 'package:star_lock/tools/dateTool.dart';
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
import '../../../../app_settings/app_colors.dart';
|
||||||
import '../../../../tools/titleAppBar.dart';
|
import '../../../../tools/titleAppBar.dart';
|
||||||
@ -41,20 +42,23 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: Obx(() => ListView.builder(
|
||||||
itemCount: 5,
|
itemCount: state.videoLogList.length,
|
||||||
itemBuilder: (c, index) {
|
itemBuilder: (c, index) {
|
||||||
return Column(children: [
|
CloudStorageData item = state.videoLogList[index];
|
||||||
Container(
|
return Column(
|
||||||
margin: EdgeInsets.only(left:20.w, top: 15.w, bottom: 15.w),
|
children: [
|
||||||
child: Row(
|
Container(
|
||||||
children: [
|
margin: EdgeInsets.only(
|
||||||
Text("2023.10.23", style: TextStyle(fontSize: 20.sp)),
|
left: 20.w, top: 15.w, bottom: 15.w),
|
||||||
]
|
child: Row(children: [
|
||||||
)),
|
Text(item.date ?? "",
|
||||||
mainListView(index)
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
],);
|
])),
|
||||||
}),
|
mainListView(index, item)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
})),
|
||||||
),
|
),
|
||||||
bottomBottomBtnWidget()
|
bottomBottomBtnWidget()
|
||||||
],
|
],
|
||||||
@ -62,35 +66,31 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemW = (1.sw - 15.w*4)/3;
|
var itemW = (1.sw - 15.w * 4) / 3;
|
||||||
var itemH = (1.sw - 15.w*4)/3+40.h;
|
var itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
||||||
Widget mainListView(int index){
|
Widget mainListView(int index, CloudStorageData itemData) {
|
||||||
return Container(
|
return GridView.builder(
|
||||||
// margin: EdgeInsets.only(left: 10.w, right: 10.w, top: 40.h),
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
// color: Colors.blue,
|
itemCount: itemData.recordList!.length,
|
||||||
child: GridView.builder(
|
shrinkWrap: true,
|
||||||
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: index+1,
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
//横轴元素个数
|
//横轴元素个数
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
//纵轴间距
|
//纵轴间距
|
||||||
mainAxisSpacing: 10.w,
|
mainAxisSpacing: 10.w,
|
||||||
// 横轴间距
|
// 横轴间距
|
||||||
crossAxisSpacing: 15.w,
|
crossAxisSpacing: 15.w,
|
||||||
//子组件宽高长度比例
|
//子组件宽高长度比例
|
||||||
childAspectRatio: itemW/itemH
|
childAspectRatio: itemW / itemH),
|
||||||
),
|
itemBuilder: (context, index) {
|
||||||
itemBuilder: (context, index) {
|
RecordListData recordData = itemData.recordList![index];
|
||||||
return Obx(() => videoItem());
|
return videoItem(recordData, index);
|
||||||
},
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget videoItem(){
|
Widget videoItem(RecordListData recordData, int index) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: itemW,
|
width: itemW,
|
||||||
height: itemH,
|
height: itemH,
|
||||||
@ -98,12 +98,26 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Container(
|
||||||
borderRadius: BorderRadius.circular(10.w),
|
width: itemW,
|
||||||
child: Image(width: itemW, height: itemW, fit: BoxFit.fill, image: const AssetImage("images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
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),
|
SizedBox(height: 5.h),
|
||||||
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
Text(
|
||||||
|
DateTool()
|
||||||
|
.dateToYMDHNString(recordData.operateDate.toString()),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: 18.sp))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
@ -112,36 +126,41 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
top: 0.w,
|
top: 0.w,
|
||||||
right: 0.w,
|
right: 0.w,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: (){
|
onTap: () {},
|
||||||
|
child: Obx(() => Image(
|
||||||
},
|
width: 36.w,
|
||||||
child: Image(width: 40.w, height: 40.w, image: state.isSelectAll.value ? const AssetImage("images/icon_round_select.png") : const AssetImage("images/icon_round_unSelect.png"))
|
height: 36.w,
|
||||||
)
|
image: state.isSelectAll.value
|
||||||
),
|
? const AssetImage("images/icon_round_select.png")
|
||||||
|
: const AssetImage(
|
||||||
|
"images/icon_round_unSelect.png"))))),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget bottomBottomBtnWidget(){
|
Widget bottomBottomBtnWidget() {
|
||||||
return Container(
|
return Container(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
child: Row(
|
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
bottomBtnItemWidget(
|
||||||
children: [
|
"images/main/icon_lockDetail_monitoringDownloadVideo.png",
|
||||||
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringDownloadVideo.png", "下载", Colors.white,(){
|
"下载",
|
||||||
|
Colors.white,
|
||||||
}),
|
() {}),
|
||||||
SizedBox(width:100.w),
|
SizedBox(width: 100.w),
|
||||||
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringDeletVideo.png", "删除", AppColors.mainColor,(){
|
bottomBtnItemWidget(
|
||||||
|
"images/main/icon_lockDetail_monitoringDeletVideo.png",
|
||||||
})
|
"删除",
|
||||||
]),
|
AppColors.mainColor,
|
||||||
|
() {})
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget bottomBtnItemWidget(String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
Widget bottomBtnItemWidget(
|
||||||
|
String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
||||||
var wh = 40.w;
|
var wh = 40.w;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onClick,
|
onTap: onClick,
|
||||||
@ -153,10 +172,12 @@ class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
|||||||
SizedBox(height: 30.w),
|
SizedBox(height: 30.w),
|
||||||
Image.asset(iconUrl, width: wh, height: wh, fit: BoxFit.fitWidth),
|
Image.asset(iconUrl, width: wh, height: wh, fit: BoxFit.fitWidth),
|
||||||
SizedBox(height: 10.w),
|
SizedBox(height: 10.w),
|
||||||
Expanded(child: Text(name, style: TextStyle(fontSize: 22.sp), textAlign: TextAlign.center))
|
Expanded(
|
||||||
|
child: Text(name,
|
||||||
|
style: TextStyle(fontSize: 22.sp),
|
||||||
|
textAlign: TextAlign.center))
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class EditVideoLogState{
|
class EditVideoLogState {
|
||||||
|
|
||||||
var selectVideoLog = 0.obs;
|
var selectVideoLog = 0.obs;
|
||||||
|
var selectVideoLogList = [].obs;
|
||||||
var isSelectAll = false.obs;
|
var isSelectAll = false.obs;
|
||||||
|
var videoLogList = [].obs;
|
||||||
|
|
||||||
|
EditVideoLogState() {
|
||||||
|
Map map = Get.arguments;
|
||||||
|
if (map['videoDataList'] != null) {
|
||||||
|
videoLogList.value = map['videoDataList'];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,90 @@
|
|||||||
|
class VideoLogEntity {
|
||||||
|
int? errorCode;
|
||||||
|
String? description;
|
||||||
|
String? errorMsg;
|
||||||
|
List<CloudStorageData>? data;
|
||||||
|
|
||||||
|
VideoLogEntity({this.errorCode, this.description, this.errorMsg, this.data});
|
||||||
|
|
||||||
|
VideoLogEntity.fromJson(Map<String, dynamic> json) {
|
||||||
|
errorCode = json['errorCode'];
|
||||||
|
description = json['description'];
|
||||||
|
errorMsg = json['errorMsg'];
|
||||||
|
if (json['data'] != null) {
|
||||||
|
data = <CloudStorageData>[];
|
||||||
|
json['data'].forEach((v) {
|
||||||
|
data!.add(CloudStorageData.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['errorCode'] = errorCode;
|
||||||
|
data['description'] = description;
|
||||||
|
data['errorMsg'] = errorMsg;
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CloudStorageData {
|
||||||
|
String? date;
|
||||||
|
List<RecordListData>? recordList;
|
||||||
|
|
||||||
|
CloudStorageData({this.date, this.recordList});
|
||||||
|
|
||||||
|
CloudStorageData.fromJson(Map<String, dynamic> json) {
|
||||||
|
date = json['date'];
|
||||||
|
if (json['recordList'] != null) {
|
||||||
|
recordList = <RecordListData>[];
|
||||||
|
json['recordList'].forEach((v) {
|
||||||
|
recordList!.add(RecordListData.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['date'] = date;
|
||||||
|
if (recordList != null) {
|
||||||
|
data['recordList'] = recordList!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecordListData {
|
||||||
|
int? recordId;
|
||||||
|
int? operateDate;
|
||||||
|
String? imagesUrl;
|
||||||
|
String? videoUrl;
|
||||||
|
int? recordType;
|
||||||
|
|
||||||
|
RecordListData(
|
||||||
|
{this.recordId,
|
||||||
|
this.operateDate,
|
||||||
|
this.imagesUrl,
|
||||||
|
this.videoUrl,
|
||||||
|
this.recordType});
|
||||||
|
|
||||||
|
RecordListData.fromJson(Map<String, dynamic> json) {
|
||||||
|
recordId = json['recordId'];
|
||||||
|
operateDate = json['operateDate'];
|
||||||
|
imagesUrl = json['imagesUrl'];
|
||||||
|
videoUrl = json['videoUrl'];
|
||||||
|
recordType = json['recordType'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['recordId'] = recordId;
|
||||||
|
data['operateDate'] = operateDate;
|
||||||
|
data['imagesUrl'] = imagesUrl;
|
||||||
|
data['videoUrl'] = videoUrl;
|
||||||
|
data['recordType'] = recordType;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ class VideoLogLogic extends BaseGetXController {
|
|||||||
lockId: state.getLockId.value,
|
lockId: state.getLockId.value,
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.videoLogList.value = entity.data!.list!;
|
state.videoLogList.value = entity.data!;
|
||||||
state.videoLogList.refresh();
|
state.videoLogList.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,9 @@ 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';
|
||||||
import 'package:star_lock/appRouters.dart';
|
import 'package:star_lock/appRouters.dart';
|
||||||
|
import 'package:star_lock/flavors.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
|
import 'package:star_lock/tools/dateTool.dart';
|
||||||
import 'package:star_lock/tools/noData.dart';
|
import 'package:star_lock/tools/noData.dart';
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
import '../../../../app_settings/app_colors.dart';
|
||||||
@ -43,25 +46,26 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
Visibility(visible: state.isNavLocal.value, child: localTip()),
|
Visibility(visible: state.isNavLocal.value, child: localTip()),
|
||||||
// title加编辑按钮
|
// title加编辑按钮
|
||||||
editVideoTip(),
|
editVideoTip(),
|
||||||
Visibility(
|
Obx(() => Visibility(
|
||||||
visible: !state.isNavLocal.value,
|
visible: !state.isNavLocal.value,
|
||||||
child: Expanded(
|
child: Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: 5,
|
itemCount: state.videoLogList.length,
|
||||||
itemBuilder: (c, index) {
|
itemBuilder: (c, index) {
|
||||||
|
CloudStorageData item = state.videoLogList[index];
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
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: [
|
child: Row(children: [
|
||||||
Text("2023.10.2$index",
|
Text(item.date ?? "",
|
||||||
style: TextStyle(fontSize: 20.sp)),
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
])),
|
])),
|
||||||
mainListView(index)
|
mainListView(index, item)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}))),
|
})))),
|
||||||
// 本地顶部
|
// 本地顶部
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: state.isNavLocal.value,
|
visible: state.isNavLocal.value,
|
||||||
@ -79,7 +83,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
Text("2023.10.2$index",
|
Text("2023.10.2$index",
|
||||||
style: TextStyle(fontSize: 20.sp)),
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
])),
|
])),
|
||||||
mainListView(index)
|
mainListView(index, CloudStorageData()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -103,7 +107,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
state.isNavLocal.value = false;
|
state.isNavLocal.value = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Obx(() => Text("云存",
|
child: Obx(() => Text("云存".tr,
|
||||||
style: state.isNavLocal.value == true
|
style: state.isNavLocal.value == true
|
||||||
? TextStyle(
|
? TextStyle(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
@ -119,7 +123,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
state.isNavLocal.value = true;
|
state.isNavLocal.value = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Obx(() => Text("本地",
|
child: Obx(() => Text("本地".tr,
|
||||||
style: state.isNavLocal.value == true
|
style: state.isNavLocal.value == true
|
||||||
? TextStyle(
|
? TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@ -154,14 +158,14 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("3天滚动储存", style: TextStyle(fontSize: 24.sp)),
|
Text("3天滚动储存".tr, style: TextStyle(fontSize: 24.sp)),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
Text("星锁已为本设备免费提供3大滚动视频储存服务",
|
Text("${F.navTitle}${"已为本设备免费提供3大滚动视频储存服务".tr}",
|
||||||
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
SizedBox(width: 15.w),
|
SizedBox(width: 15.w),
|
||||||
Text("去升级", style: TextStyle(fontSize: 22.sp)),
|
Text("去升级".tr, style: TextStyle(fontSize: 22.sp)),
|
||||||
Image(
|
Image(
|
||||||
width: 40.w,
|
width: 40.w,
|
||||||
height: 24.w,
|
height: 24.w,
|
||||||
@ -193,9 +197,9 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// SizedBox(height: 20.h),
|
// SizedBox(height: 20.h),
|
||||||
Text("下载列表", style: TextStyle(fontSize: 24.sp)),
|
Text("下载列表".tr, style: TextStyle(fontSize: 24.sp)),
|
||||||
SizedBox(height: 15.h),
|
SizedBox(height: 15.h),
|
||||||
Text("暂无下载内容",
|
Text("暂无下载内容".tr,
|
||||||
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
@ -218,7 +222,7 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(state.isNavLocal.value == true ? "已下载" : "全部视频",
|
Text(state.isNavLocal.value == true ? "已下载".tr : "全部视频".tr,
|
||||||
style: TextStyle(fontSize: 26.sp, fontWeight: FontWeight.w500)),
|
style: TextStyle(fontSize: 26.sp, fontWeight: FontWeight.w500)),
|
||||||
Expanded(child: SizedBox(width: 10.w)),
|
Expanded(child: SizedBox(width: 10.w)),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -230,7 +234,8 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
iconSize: 30,
|
iconSize: 30,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.toNamed(Routers.editVideoLogPage);
|
Get.toNamed(Routers.editVideoLogPage,
|
||||||
|
arguments: {"videoDataList": state.videoLogList.value});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// TextButton(
|
// TextButton(
|
||||||
@ -248,10 +253,10 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
var itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
var itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
||||||
|
|
||||||
// 云存列表
|
// 云存列表
|
||||||
Widget mainListView(int index) {
|
Widget mainListView(int index, CloudStorageData itemData) {
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
itemCount: index + 1,
|
itemCount: itemData.recordList!.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
@ -264,32 +269,44 @@ class _VideoLogPageState extends State<VideoLogPage> {
|
|||||||
//子组件宽高长度比例
|
//子组件宽高长度比例
|
||||||
childAspectRatio: itemW / itemH),
|
childAspectRatio: itemW / itemH),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return videoItem(() {
|
RecordListData recordData = itemData.recordList![index];
|
||||||
Get.toNamed(Routers.videoLogDetailPage);
|
return videoItem(recordData);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget videoItem(Function() action) {
|
Widget videoItem(RecordListData recordData) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: action,
|
onTap: () {
|
||||||
|
Get.toNamed(Routers.videoLogDetailPage, arguments: {
|
||||||
|
"recordData": recordData,
|
||||||
|
"videoDataList": state.videoLogList.value
|
||||||
|
});
|
||||||
|
},
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: itemW,
|
width: itemW,
|
||||||
height: itemH,
|
height: itemH,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Container(
|
||||||
borderRadius: BorderRadius.circular(10.w),
|
width: itemW,
|
||||||
child: Image(
|
height: itemW,
|
||||||
width: itemW,
|
margin: const EdgeInsets.all(0),
|
||||||
height: itemW,
|
color: Colors.white,
|
||||||
fit: BoxFit.fill,
|
child: ClipRRect(
|
||||||
image: const AssetImage(
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
"images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
child: Image(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: Image.network(recordData.imagesUrl ??
|
||||||
|
"images/icon_video_placeholder.jpg")
|
||||||
|
.image),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5.h),
|
SizedBox(height: 5.h),
|
||||||
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
Text(
|
||||||
|
DateTool().dateToYMDHNString(recordData.operateDate.toString()),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: 18.sp))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
|
|
||||||
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:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
|
import 'package:star_lock/tools/dateTool.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
class ControlsOverlay extends StatelessWidget {
|
class ControlsOverlay extends StatelessWidget {
|
||||||
const ControlsOverlay({required this.controller});
|
const ControlsOverlay(
|
||||||
|
{Key? key, required this.controller, required this.recordData})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
static const List<Duration> _exampleCaptionOffsets = <Duration>[
|
static const List<Duration> _exampleCaptionOffsets = <Duration>[
|
||||||
Duration(seconds: -10),
|
Duration(seconds: -10),
|
||||||
@ -29,6 +32,7 @@ class ControlsOverlay extends StatelessWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
final VideoPlayerController controller;
|
final VideoPlayerController controller;
|
||||||
|
final RecordListData recordData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -40,18 +44,18 @@ class ControlsOverlay extends StatelessWidget {
|
|||||||
child: controller.value.isPlaying
|
child: controller.value.isPlaying
|
||||||
? const SizedBox.shrink()
|
? const SizedBox.shrink()
|
||||||
: Container(
|
: Container(
|
||||||
color: Colors.black26,
|
color: Colors.black26,
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child:
|
child:
|
||||||
// CircularProgressIndicator()
|
// CircularProgressIndicator()
|
||||||
Icon(
|
Icon(
|
||||||
Icons.play_arrow,
|
Icons.play_arrow,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
size: 60.0,
|
size: 60.0,
|
||||||
semanticLabel: 'Play',
|
semanticLabel: 'Play',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -123,32 +127,47 @@ class ControlsOverlay extends StatelessWidget {
|
|||||||
left: 0.h,
|
left: 0.h,
|
||||||
right: 0.h,
|
right: 0.h,
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.only(left:20.w, right:20.w),
|
margin: EdgeInsets.only(left: 20.w, right: 20.w),
|
||||||
// color: const Color(0xC83C3F41),
|
// color: const Color(0xC83C3F41),
|
||||||
child: Row(
|
child: Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("星锁 2023/10/23", style: TextStyle(color: Colors.white, fontSize: 20.sp)),
|
Text(
|
||||||
|
DateTool()
|
||||||
|
.dateToYMDHNString(recordData.operateDate.toString()),
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 20.sp)),
|
||||||
Expanded(child: SizedBox(width: 10.w)),
|
Expanded(child: SizedBox(width: 10.w)),
|
||||||
Container(
|
Container(
|
||||||
width: 50.w,
|
width: 50.w,
|
||||||
height: 50.w,
|
height: 50.w,
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
child: Image(width: 50.w, height: 50.w, image: const AssetImage("images/main/icon_lockDetail_monitoringShareVideo_white.png")),
|
child: Image(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
image: const AssetImage(
|
||||||
|
"images/main/icon_lockDetail_monitoringShareVideo_white.png")),
|
||||||
),
|
),
|
||||||
SizedBox(width: 20.w),
|
SizedBox(width: 20.w),
|
||||||
Container(
|
Container(
|
||||||
width: 50.w,
|
width: 50.w,
|
||||||
height: 50.w,
|
height: 50.w,
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
child: Image(width: 50.w, height: 50.w, image: const AssetImage("images/main/icon_lockDetail_monitoringDownloadVideo_white.png")),
|
child: Image(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
image: const AssetImage(
|
||||||
|
"images/main/icon_lockDetail_monitoringDownloadVideo_white.png")),
|
||||||
),
|
),
|
||||||
SizedBox(width: 20.w),
|
SizedBox(width: 20.w),
|
||||||
Container(
|
Container(
|
||||||
width: 50.w,
|
width: 50.w,
|
||||||
height: 50.w,
|
height: 50.w,
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
child: Image(width: 50.w, height: 50.w, image: const AssetImage("images/main/icon_lockDetail_monitoringDeletVideo_white.png")),
|
child: Image(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
image: const AssetImage(
|
||||||
|
"images/main/icon_lockDetail_monitoringDeletVideo_white.png")),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -164,37 +183,50 @@ class ControlsOverlay extends StatelessWidget {
|
|||||||
color: const Color.fromRGBO(0, 0, 0, 0.5),
|
color: const Color.fromRGBO(0, 0, 0, 0.5),
|
||||||
height: 60.h,
|
height: 60.h,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
children: [
|
||||||
//暂停按钮
|
//暂停按钮
|
||||||
InkWell(
|
InkWell(
|
||||||
child: controller.value.isPlaying ? const Icon(Icons.pause, size: 30, color: Color(0xffefefef)) : const Icon(Icons.play_arrow, size: 30, color: Color(0xffefefef)),
|
child: controller.value.isPlaying
|
||||||
|
? const Icon(Icons.pause,
|
||||||
|
size: 30, color: Color(0xffefefef))
|
||||||
|
: const Icon(Icons.play_arrow,
|
||||||
|
size: 30, color: Color(0xffefefef)),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// if(controller.value.isBuffering == false){
|
// if(controller.value.isBuffering == false){
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
controller.value.isPlaying ? controller.pause() : controller.play();
|
controller.value.isPlaying
|
||||||
|
? controller.pause()
|
||||||
|
: controller.play();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
//当前播放进度
|
//当前播放进度
|
||||||
Text(formatString(controller.value.position), style: TextStyle(fontSize: 22.sp, color: const Color(0xffefefef)),),
|
Text(
|
||||||
|
formatString(controller.value.position),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22.sp, color: const Color(0xffefefef)),
|
||||||
|
),
|
||||||
//进度条
|
//进度条
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: Slider(
|
||||||
child: Slider(activeColor: const Color(0xFFFFFFFF), max: controller.value.duration.inMilliseconds.truncateToDouble(),
|
activeColor: const Color(0xFFFFFFFF),
|
||||||
value: controller.value.position.inMilliseconds.truncateToDouble(),
|
max: controller.value.duration.inMilliseconds
|
||||||
|
.truncateToDouble(),
|
||||||
|
value: controller.value.position.inMilliseconds
|
||||||
|
.truncateToDouble(),
|
||||||
onChanged: (newRating) {
|
onChanged: (newRating) {
|
||||||
controller
|
controller
|
||||||
.seekTo(Duration(
|
.seekTo(Duration(milliseconds: newRating.truncate()));
|
||||||
milliseconds:
|
|
||||||
newRating
|
|
||||||
.truncate()));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
//总视频进度
|
//总视频进度
|
||||||
Text(formatString(controller.value.duration), style: TextStyle(fontSize: 22.sp, color: const Color(0xffefefef)),),
|
Text(
|
||||||
|
formatString(controller.value.duration),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22.sp, color: const Color(0xffefefef)),
|
||||||
|
),
|
||||||
//倍速下拉菜单
|
//倍速下拉菜单
|
||||||
// DropdownButtonHideUnderline(
|
// DropdownButtonHideUnderline(
|
||||||
// child: DropdownButton2(
|
// child: DropdownButton2(
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
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';
|
||||||
|
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/tools/dateTool.dart';
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
import '../../../../app_settings/app_colors.dart';
|
||||||
import '../../../../tools/titleAppBar.dart';
|
import '../../../../tools/titleAppBar.dart';
|
||||||
import 'controlsOverlay_page.dart';
|
|
||||||
import 'videoLogDetail_logic.dart';
|
import 'videoLogDetail_logic.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
@ -20,34 +21,20 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
final logic = Get.put(VideoLogDetailLogic());
|
final logic = Get.put(VideoLogDetailLogic());
|
||||||
final state = Get.find<VideoLogDetailLogic>().state;
|
final state = Get.find<VideoLogDetailLogic>().state;
|
||||||
|
|
||||||
late VideoPlayerController _controller;
|
|
||||||
|
|
||||||
// Future<ClosedCaptionFile> _loadCaptions() async {
|
|
||||||
// final String fileContents = await DefaultAssetBundle.of(context)
|
|
||||||
// .loadString('images/bumble_bee_captions.vtt');
|
|
||||||
// return WebVTTCaptionFile(
|
|
||||||
// fileContents); // For vtt files, use WebVTTCaptionFile
|
|
||||||
// }
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = VideoPlayerController.networkUrl(
|
|
||||||
Uri.parse('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'),
|
state.videoController = VideoPlayerController.networkUrl(
|
||||||
// closedCaptionFile: _loadCaptions(),
|
Uri.parse(state.recordData.value.videoUrl!),
|
||||||
// videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
|
videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
|
||||||
);
|
);
|
||||||
|
|
||||||
_controller.addListener(() {
|
state.videoController.addListener(() {
|
||||||
setState(() {
|
setState(() {});
|
||||||
print("controller.value.isBuffering:${_controller.value.isBuffering}");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
state.videoController.setLooping(false);
|
||||||
_controller.setLooping(false);
|
state.videoController.initialize();
|
||||||
// _controller.setVolume(1);
|
|
||||||
_controller.initialize();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -55,90 +42,119 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: TitleAppBar(
|
appBar: TitleAppBar(
|
||||||
barTitle: "本地视频播放",
|
barTitle: "视频播放",
|
||||||
haveBack: true,
|
haveBack: true,
|
||||||
backgroundColor: AppColors.mainColor,
|
backgroundColor: AppColors.mainColor,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
AspectRatio(
|
AspectRatio(
|
||||||
aspectRatio: 16/9,
|
aspectRatio: state.videoController.value.aspectRatio,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
VideoPlayer(_controller),
|
VideoPlayer(state.videoController),
|
||||||
// ClosedCaption(text: _controller.value.caption.text),
|
ControlsOverlay(
|
||||||
ControlsOverlay(controller: _controller),
|
controller: state.videoController,
|
||||||
(_controller.value.isPlaying || _controller.value.isBuffering) ? Container() : VideoProgressIndicator(_controller, colors:VideoProgressColors(playedColor:AppColors.mainColor), allowScrubbing: true),
|
recordData: state.recordData.value,
|
||||||
|
),
|
||||||
|
(state.videoController.value.isPlaying ||
|
||||||
|
state.videoController.value.isBuffering)
|
||||||
|
? Container()
|
||||||
|
: VideoProgressIndicator(state.videoController,
|
||||||
|
colors: VideoProgressColors(
|
||||||
|
playedColor: AppColors.mainColor),
|
||||||
|
allowScrubbing: true),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(left:20.w, top: 15.w),
|
margin: EdgeInsets.only(left: 20.w, top: 15.w),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text("2023.10.23", style: TextStyle(fontSize: 20.sp)),
|
Text(
|
||||||
|
DateTool().dateToYMDString(
|
||||||
|
state.recordData.value.operateDate.toString()),
|
||||||
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 15.h),
|
SizedBox(height: 15.h),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
videoItem(true),
|
videoItem(true, state.recordData.value),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: 4,
|
itemCount: state.videoLogList.length,
|
||||||
itemBuilder: (c, index) {
|
itemBuilder: (c, index) {
|
||||||
return Column(children: [
|
CloudStorageData item = state.videoLogList[index];
|
||||||
Container(
|
return Column(
|
||||||
margin: EdgeInsets.only(left:20.w, top: 15.w, bottom: 15.w),
|
children: [
|
||||||
child: Row(
|
Container(
|
||||||
children: [
|
margin: EdgeInsets.only(
|
||||||
Text("2023.10.23", style: TextStyle(fontSize: 20.sp)),
|
left: 20.w, top: 15.w, bottom: 15.w),
|
||||||
]
|
child: Row(children: [
|
||||||
)),
|
Text(item.date ?? "",
|
||||||
mainListView()
|
style: TextStyle(fontSize: 20.sp)),
|
||||||
],);
|
])),
|
||||||
}),
|
mainListView(index, item)
|
||||||
),
|
],
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
// Expanded(
|
||||||
|
// child: ListView.builder(
|
||||||
|
// itemCount: state.videoLogList.value.length,
|
||||||
|
// itemBuilder: (c, index) {
|
||||||
|
// return Column(
|
||||||
|
// children: [
|
||||||
|
// Container(
|
||||||
|
// margin: EdgeInsets.only(
|
||||||
|
// left: 20.w, top: 15.w, bottom: 15.w),
|
||||||
|
// child: Row(children: [
|
||||||
|
// Text("2023.10.23",
|
||||||
|
// style: TextStyle(fontSize: 20.sp)),
|
||||||
|
// ])),
|
||||||
|
// mainListView()
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var itemW = (1.sw - 15.w * 4) / 3;
|
||||||
var itemW = (1.sw - 15.w*4)/3;
|
var itemH = (1.sw - 15.w * 4) / 3 + 40.h;
|
||||||
var itemH = (1.sw - 15.w*4)/3+40.h;
|
Widget mainListView(int index, CloudStorageData itemData) {
|
||||||
Widget mainListView(){
|
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
itemCount: 4,
|
itemCount: itemData.recordList!.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
//横轴元素个数
|
//横轴元素个数
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
//纵轴间距
|
//纵轴间距
|
||||||
mainAxisSpacing: 10.w,
|
mainAxisSpacing: 10.w,
|
||||||
// 横轴间距
|
// 横轴间距
|
||||||
crossAxisSpacing: 15.w,
|
crossAxisSpacing: 15.w,
|
||||||
//子组件宽高长度比例
|
//子组件宽高长度比例
|
||||||
childAspectRatio: itemW/itemH
|
childAspectRatio: itemW / itemH),
|
||||||
),
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return videoItem(false);
|
return videoItem(false, itemData.recordList![index]);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget videoItem(bool isPlay){
|
Widget videoItem(bool isPlay, RecordListData itemData) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: itemW,
|
width: itemW,
|
||||||
height: itemH,
|
height: itemH,
|
||||||
@ -148,33 +164,50 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(10.w),
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
child: Stack(
|
child: Stack(children: [
|
||||||
children: [
|
Container(
|
||||||
Image(width: itemW, height: itemW, fit: BoxFit.fill, image: const AssetImage("images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
width: itemW,
|
||||||
Positioned(
|
height: itemW,
|
||||||
left: 8.w,
|
margin: const EdgeInsets.all(0),
|
||||||
bottom: 5.h,
|
color: Colors.white,
|
||||||
child: Text("00:06", style: TextStyle(color: Colors.white, fontSize: 20.sp))
|
child: ClipRRect(
|
||||||
),
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
Visibility(
|
child: Image(
|
||||||
visible: isPlay,
|
fit: BoxFit.cover,
|
||||||
child: Positioned(
|
image: Image.network(itemData.imagesUrl ??
|
||||||
left: 0,
|
"images/icon_video_placeholder.jpg")
|
||||||
right: 0,
|
.image),
|
||||||
top: 0,
|
),
|
||||||
bottom: 0,
|
),
|
||||||
child: Container(
|
Positioned(
|
||||||
// padding: EdgeInsets.only(right: 10.w, left: 10.w),
|
left: 8.w,
|
||||||
color: const Color.fromRGBO(0, 0, 0, 0.3),
|
bottom: 5.h,
|
||||||
child: Center(child: Text("播放中", style: TextStyle(color: Colors.white, fontSize: 22.sp))),
|
child: Text(
|
||||||
)
|
formatString(state.videoController.value.duration),
|
||||||
),
|
style:
|
||||||
)
|
TextStyle(color: Colors.grey, fontSize: 20.sp))),
|
||||||
]
|
Visibility(
|
||||||
),
|
visible: isPlay,
|
||||||
|
child: Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: Container(
|
||||||
|
// padding: EdgeInsets.only(right: 10.w, left: 10.w),
|
||||||
|
color: const Color.fromRGBO(0, 0, 0, 0.3),
|
||||||
|
child: Center(
|
||||||
|
child: Text("播放中",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white, fontSize: 22.sp))),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
SizedBox(height:5.h),
|
SizedBox(height: 5.h),
|
||||||
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
Text(
|
||||||
|
DateTool().dateToYMDHNString(itemData.operateDate.toString()),
|
||||||
|
style: TextStyle(fontSize: 18.sp))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -182,10 +215,14 @@ class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String formatString(time) {
|
||||||
|
var shortName = time.toString().substring(2, 7);
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
_controller.dispose();
|
state.videoController.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,20 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
class VideoLogDetailState {
|
||||||
|
var recordData = RecordListData().obs;
|
||||||
|
late VideoPlayerController videoController;
|
||||||
|
var videoLogList = [].obs;
|
||||||
|
|
||||||
class VideoLogDetailState{
|
VideoLogDetailState() {
|
||||||
|
Map map = Get.arguments;
|
||||||
|
if (map['recordData'] != null) {
|
||||||
|
recordData.value = map['recordData'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map['videoDataList'] != null) {
|
||||||
|
videoLogList.value = map['videoDataList'];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -12,6 +12,7 @@ import 'package:star_lock/main/lockDetail/messageWarn/msgNotification/coerceOpen
|
|||||||
import 'package:star_lock/main/lockDetail/messageWarn/msgNotification/msgNotification/msgNotification_entity.dart';
|
import 'package:star_lock/main/lockDetail/messageWarn/msgNotification/msgNotification/msgNotification_entity.dart';
|
||||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKeyList/passwordKeyListEntity.dart';
|
import 'package:star_lock/main/lockDetail/passwordKey/passwordKeyList/passwordKeyListEntity.dart';
|
||||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKeyEntity.dart';
|
import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKeyEntity.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/videoLog/videoLog/videoLog_entity.dart';
|
||||||
import 'package:star_lock/mine/mall/lockMall_entity.dart';
|
import 'package:star_lock/mine/mall/lockMall_entity.dart';
|
||||||
import 'package:star_lock/mine/minePersonInfo/minePersonInfoEditAccount/minePersonInfoEditAccount/mineUnbindPhoneOrEmail_entity.dart';
|
import 'package:star_lock/mine/minePersonInfo/minePersonInfoEditAccount/minePersonInfoEditAccount/mineUnbindPhoneOrEmail_entity.dart';
|
||||||
import 'package:star_lock/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_entity.dart';
|
import 'package:star_lock/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_entity.dart';
|
||||||
@ -1961,10 +1962,9 @@ class ApiRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取云存列表
|
// 获取云存列表
|
||||||
Future<CoerceFingerprintListEntity> getLockCloudStorageList(
|
Future<VideoLogEntity> getLockCloudStorageList({required int lockId}) async {
|
||||||
{required int lockId}) async {
|
|
||||||
final res = await apiProvider.getLockCloudStorageList(lockId);
|
final res = await apiProvider.getLockCloudStorageList(lockId);
|
||||||
return CoerceFingerprintListEntity.fromJson(res.body);
|
return VideoLogEntity.fromJson(res.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置微信公众号推送
|
// 设置微信公众号推送
|
||||||
|
|||||||
@ -135,7 +135,7 @@ dependencies:
|
|||||||
jpush_flutter: ^2.5.1
|
jpush_flutter: ^2.5.1
|
||||||
|
|
||||||
#视频播放器
|
#视频播放器
|
||||||
video_player: ^2.7.1
|
video_player: ^2.8.5
|
||||||
#控制横竖屏控件
|
#控制横竖屏控件
|
||||||
auto_orientation: ^2.3.1
|
auto_orientation: ^2.3.1
|
||||||
audioplayers: ^5.2.1
|
audioplayers: ^5.2.1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user