fix:增加视频日志中的视频缩略图、修复监控时锁板不在线状态不变更的问题

This commit is contained in:
liyi 2025-01-22 13:53:17 +08:00
parent 2ee6782714
commit 5b96705633
8 changed files with 111 additions and 75 deletions

View File

@ -118,7 +118,10 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(value, style: TextStyle(color: Colors.white, fontSize: 22.sp)),
Text(
value,
style: TextStyle(color: Colors.white, fontSize: 22.sp),
),
],
),
),
@ -241,13 +244,16 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Obx(() => XSDropDownWidget(
Obx(
() => XSDropDownWidget(
items: state.getDropDownItemList,
value: state.dropdownTitle.value,
valueChanged: (value) {
valueChanged: (value) async {
state.dropdownValue.value = int.parse(value);
logic.mockNetworkDataRequest(isRefresh: true);
})),
await logic.mockNetworkDataRequest(isRefresh: true);
},
),
),
],
),
);
@ -261,24 +267,26 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Obx(() => state.lockLogItemList.isNotEmpty
? Timeline.tileBuilder(
builder: _timelineBuilderWidget(),
theme: TimelineThemeData(
nodePosition: 0.04, //
connectorTheme: const ConnectorThemeData(
thickness: 1.0,
color: AppColors.greyLineColor,
indent: 0.5,
child: Obx(
() => state.lockLogItemList.isNotEmpty
? Timeline.tileBuilder(
builder: _timelineBuilderWidget(),
theme: TimelineThemeData(
nodePosition: 0.04, //
connectorTheme: const ConnectorThemeData(
thickness: 1.0,
color: AppColors.greyLineColor,
indent: 0.5,
),
indicatorTheme: const IndicatorThemeData(
size: 8.0,
color: AppColors.greyLineColor,
position: 0.45,
),
),
indicatorTheme: const IndicatorThemeData(
size: 8.0,
color: AppColors.greyLineColor,
position: 0.4,
),
),
)
: NoData()),
)
: NoData(),
),
);
}
@ -288,15 +296,12 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
itemCount: state.lockLogItemList.length,
contentsBuilder: (BuildContext context, int index) {
final DoorLockLogDataItem timelineData = state.lockLogItemList[index];
final DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(timelineData.operateDate!);
final String formattedTime =
'${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
return GestureDetector(
onTap: () {
Get.toNamed(Routers.doorLockLogDetailPage,
arguments: {'doorLockLogDataItem': timelineData});
Get.toNamed(
Routers.doorLockLogDetailPage,
arguments: {'doorLockLogDataItem': timelineData},
);
},
child: Padding(
padding: EdgeInsets.only(left: 20.w, top: 20.h),
@ -305,7 +310,6 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
// '$formattedTime ${timelineData.username!.isNotEmpty ? "${timelineData.username}操作" : ""}${timelineData.recordTypeName}',
timelineData.recordStr ?? '',
textAlign: TextAlign.left,
style: TextStyle(
@ -315,15 +319,17 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
),
),
SizedBox(
height: 10.h,
height: 12.h,
),
videoItem(
RecordListData(
recordId: state.lockLogItemList.value[index].recordId,
recordType: state.lockLogItemList.value[index].recordType,
operateDate: state.lockLogItemList.value[index].operateDate,
imagesUrl: state.lockLogItemList.value[index].imagesUrl,
videoUrl: state.lockLogItemList.value[index].videoUrl,
),
),
videoItem(RecordListData(
recordId: state.lockLogItemList.value[index].recordId,
recordType: state.lockLogItemList.value[index].recordType,
operateDate: state.lockLogItemList.value[index].operateDate,
imagesUrl: state.lockLogItemList.value[index].imagesUrl,
videoUrl: state.lockLogItemList.value[index].videoUrl,
)),
SizedBox(
height: 20.h,
),
@ -341,13 +347,15 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) {
final lockLogItemList = state.lockLogItemList.value;
final list = lockLogItemList
.map((e) => RecordListData(
videoUrl: e.videoUrl,
imagesUrl: e.imagesUrl,
operateDate: e.operateDate,
recordId: e.recordId,
recordType: e.recordType,
))
.map(
(e) => RecordListData(
videoUrl: e.videoUrl,
imagesUrl: e.imagesUrl,
operateDate: e.operateDate,
recordId: e.recordId,
recordType: e.recordType,
),
)
.toList();
final selectDateString =
DateTool().dateToYMDString(state.startDate.value.toString());
@ -369,12 +377,9 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
);
}
},
child: SizedBox(
width: 260.w,
height: 260.h,
child: Column(
children: <Widget>[
Container(
child: ((recordData.imagesUrl != null && recordData.imagesUrl != '') ||
(recordData.videoUrl != null && recordData.videoUrl != ''))
? Container(
width: 260.w,
height: 260.h,
margin: const EdgeInsets.all(0),
@ -383,18 +388,19 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
borderRadius: BorderRadius.circular(10.w),
child: _buildImageOrVideoItem(recordData),
),
),
],
),
),
)
: SizedBox.shrink(),
);
}
_buildImageOrVideoItem(RecordListData recordData) {
if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) {
return _buildVideoItem(recordData);
} else {
} else if (recordData.imagesUrl != null &&
recordData.imagesUrl!.isNotEmpty) {
return _buildImageItem(recordData);
} else {
return SizedBox.shrink();
}
}
@ -411,12 +417,9 @@ class _DoorLockLogPageState extends State<DoorLockLogPage> with RouteAware {
errorBuilder:
(BuildContext context, Object error, StackTrace? stackTrace) {
//
return RotatedBox(
quarterTurns: -1,
child: Image.asset(
'images/icon_unHaveData.png', //
fit: BoxFit.cover,
),
return Image.asset(
'images/icon_unHaveData.png', //
fit: BoxFit.cover,
);
},
),

View File

@ -1,4 +1,3 @@
import 'dart:io';
import 'package:flutter/material.dart';
@ -225,8 +224,13 @@ class __DerivedRecordWidgetState extends State<_DerivedRecordWidget> {
Future<String> downloadAndSaveFile(String url) async {
final http.Response response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
// yyyyMMdd
final String formattedDate =
DateFormat('yyyyMMdd').format(DateTime.now());
final Directory directory = await getApplicationDocumentsDirectory();
final File file = File('${directory.path}/record.xlsx');
final File file =
File('${directory.path}/openLockRecord_${formattedDate}.xlsx');
await file.writeAsBytes(response.bodyBytes);
return file.path;
} else {

View File

@ -34,7 +34,7 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
talkePingOverTimeTimerManager.cancel();
talkDataOverTimeTimerManager.cancel();
EasyLoading.showToast('已挂断'.tr);
// EasyLoading.showToast('已挂断'.tr);
Get.back();
}

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
@ -27,7 +28,9 @@ class TalkePingOverTimeTimerManager {
//
static void _handleTalkePingOverTime() {
if (talkStatus.status == TalkStatus.answeredSuccessfully) {
//
if (talkStatus.status == TalkStatus.answeredSuccessfully ||
talkStatus.status == TalkStatus.proactivelyCallWaitingAnswer) {
EasyLoading.showToast('通话异常中断'.tr, duration: 2000.milliseconds);
//
StartChartManage().stopTalkPingMessageTimer();
@ -42,6 +45,7 @@ class TalkePingOverTimeTimerManager {
//
void start() {
AppLog.log('启动talkping判断');
//
_timer?.cancel();
_timer = Timer(timeout, onTimeout);

View File

@ -57,6 +57,7 @@ class ScpMessageBaseHandle {
ToPeerId: scpMessage.FromPeerId!,
FromPeerId: scpMessage.ToPeerId!,
PayloadType: scpMessage.PayloadType!,
messageId: scpMessage.MessageId!,
);
}

View File

@ -421,6 +421,9 @@ class StartChartManage {
},
);
talkStatus.setProactivelyCallWaitingAnswer();
startTalkPingMessageTimer();
// ping超时判断定时器
talkePingOverTimeTimerManager.start();
}
///
@ -597,15 +600,20 @@ class StartChartManage {
}
//
void sendGenericRespSuccessMessage(
{required String ToPeerId,
required String FromPeerId,
required int PayloadType}) async {
void sendGenericRespSuccessMessage({
required String ToPeerId,
required String FromPeerId,
required int PayloadType,
required int messageId,
}) async {
if (messageId == null) {
messageId = MessageCommand.getNextMessageId(ToPeerId, increment: false);
}
final message = MessageCommand.genericRespSuccessMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
PayloadType: PayloadType,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: false),
MessageId: messageId,
);
await _sendMessage(message: message);
}

View File

@ -122,15 +122,15 @@ class _XSDropDownWidgetState extends State<XSDropDownWidget> {
child: Container(
margin:
EdgeInsets.only(left: 0.w, right: 0, top: 0, bottom: 0),
color: item.itemValue == currentValue
? AppColors.mainColor
: null, //
// color: item.itemValue == currentValue
// ? AppColors.mainColor
// : null, //
child: Text(
item.itemTitle,
style: TextStyle(
fontSize: 24.sp,
color: item.itemValue == currentValue
? Colors.white
? AppColors.mainColor
: Colors.black, //
),
),

View File

@ -1148,6 +1148,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.6"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
network_info_plus:
dependency: "direct main"
description:
@ -1388,6 +1396,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "21.1.2"
provider:
dependency: "direct main"
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
pub_semver:
dependency: transitive
description: