import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/appRouters.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_entity.dart'; import 'package:star_lock/main/lockDetail/doorLockLog/doorLockLog_logic.dart'; 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_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'; import 'package:star_lock/tools/dateTool.dart'; import 'package:star_lock/tools/menuItem/xsDropDownWidget.dart'; import 'package:star_lock/tools/noData.dart'; import 'package:star_lock/tools/showCupertinoAlertView.dart'; import 'package:star_lock/tools/showTipView.dart'; import 'package:timelines/timelines.dart'; import '../../../app_settings/app_colors.dart'; import '../../../tools/appRouteObserver.dart'; import '../../../tools/titleAppBar.dart'; class DoorLockLogPage extends StatefulWidget { const DoorLockLogPage({Key? key}) : super(key: key); @override State createState() => _DoorLockLogPageState(); } class _DoorLockLogPageState extends State with RouteAware { final DoorLockLogLogic logic = Get.put(DoorLockLogLogic()); final DoorLockLogState state = Get.find().state; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.mainBackgroundColor, appBar: TitleAppBar( barTitle: '操作记录'.tr, haveBack: true, backgroundColor: AppColors.mainColor, actionsList: [ Visibility( visible: CommonDataManage().currentKeyInfo.isLockOwner == 1 || CommonDataManage().currentKeyInfo.keyRight == 1, child: GestureDetector( child: Image.asset( 'images/icon_tips_Q.png', width: 34.w, height: 32.w, color: Colors.white, ), onTap: () { ShowTipView().showSureAlertDialog( '1.锁没有联网,密码、IC卡、指纹等开门记录无法实时上传,可以点击右上角按钮,然后读取记录。'.tr + '\n' + '2.如果您需要保留历史记录,可以点击右上角按钮,然后导出记录'.tr, tipTitle: '看不到操作记录,可能原因有'.tr, sureStr: '我知道了'.tr); }, )), Visibility( visible: CommonDataManage().currentKeyInfo.isLockOwner == 1 || CommonDataManage().currentKeyInfo.keyRight == 1, child: PopupMenuButton( onSelected: _onMenuItemSelected, color: Colors.black, itemBuilder: (BuildContext context) { return >[ _buildCustomPopupMenuItem('读取记录'.tr), if (CommonDataManage().currentKeyInfo.isLockOwner == 1) const PopupMenuDivider(), if (CommonDataManage().currentKeyInfo.isLockOwner == 1) _buildCustomPopupMenuItem('清空记录'.tr), const PopupMenuDivider(), _buildCustomPopupMenuItem('导出记录'.tr), ]; }, icon: Image.asset( 'images/icon_bar_more.png', height: 30.h, width: 10.w, ), offset: Offset(0, 70.h), // 设置弹出框位置偏移量 ), ), ], ), body: Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ topAdvancedCalendarWidget(), Divider( height: 1, color: AppColors.greyLineColor, indent: 30.w, endIndent: 30.w, ), eventDropDownWidget(), Expanded(child: timeLineView()) ], ), ); } // PopupMenuItem _buildCustomPopupMenuItem(String value) { return PopupMenuItem( value: value, height: 46.h, child: SizedBox( height: 46.h, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( value, style: TextStyle(color: Colors.white, fontSize: 22.sp), ), ], ), ), ); } void _onMenuItemSelected(String value) { if (value == '读取记录'.tr) { logic.getLockRecordLastUploadDataTime(); } else if (value == '清空记录'.tr) { ShowCupertinoAlertView().showClearOperationRecordAlert(clearClick: () { logic.clearOperationRecordRequest(); }); } else if (value == '导出记录'.tr) { showDialog( context: context, builder: (BuildContext context) { return ExportRecordDialog( onExport: (String filePath) { Get.toNamed(Routers.exportSuccessPage, arguments: {'filePath': filePath}); }, ); }, ); } } // switch (value) { // case "读取记录".tr: // { // logic.mockNetworkDataRequest(isRefresh: true); // } // break; // case '清空记录'.tr: // { // ShowCupertinoAlertView().showClearOperationRecordAlert( // clearClick: () { // logic.clearOperationRecordRequest(); // }); // } // break; // case '导出记录': // { // showDialog( // context: context, // builder: (BuildContext context) { // return ExportRecordDialog( // onExport: (String filePath) { // Get.toNamed(Routers.exportSuccessPage, // arguments: {'filePath': filePath}); // }, // ); // }, // ); // } // break; // } // } //顶部日历小部件 Widget topAdvancedCalendarWidget() { final ThemeData theme = Theme.of(context); return Theme( data: theme.copyWith( textTheme: theme.textTheme.copyWith( titleMedium: theme.textTheme.titleMedium!.copyWith( fontSize: 16, color: theme.colorScheme.secondary, ), bodyLarge: theme.textTheme.bodyLarge!.copyWith( fontSize: 14, color: Colors.black54, ), bodyMedium: theme.textTheme.bodyMedium!.copyWith( fontSize: 12, color: Colors.black87, ), ), primaryColor: AppColors.mainColor, highlightColor: Colors.yellow, disabledColor: Colors.grey, ), child: Stack( children: [ AdvancedCalendar( controller: state.calendarControllerCustom, events: state.events, weekLineHeight: 48.0, startWeekDay: 1, innerDot: true, keepLineSize: true, calendarTextStyle: const TextStyle( fontSize: 18, fontWeight: FontWeight.w400, height: 1.3125, letterSpacing: 0, ), ), Positioned( top: 8.0, right: 8.0, child: Obx(() => Text( '${state.currentSelectDate.value.year}${'年'.tr}${state.currentSelectDate.value.month}${'月'.tr}', style: theme.textTheme.titleMedium!.copyWith( fontSize: 16, color: theme.colorScheme.secondary, ), )), ), ], ), ); } //事件下拉框组件 Widget eventDropDownWidget() { return Container( margin: EdgeInsets.only(top: 20.h, left: 30.w, bottom: 10.h, right: 20.w), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Obx( () => XSDropDownWidget( items: state.getDropDownItemList, value: state.dropdownTitle.value, valueChanged: (value) async { state.dropdownValue.value = int.parse(value); await logic.mockNetworkDataRequest(isRefresh: true); }, ), ), ], ), ); } //时间轴组件 Widget timeLineView() { return Container( margin: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 20.h, top: 20.h), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16.w), ), child: Obx(() => EasyRefreshTool( onRefresh: () async { logic.mockNetworkDataRequest(isRefresh: true); }, onLoad: () async { logic.mockNetworkDataRequest(isRefresh: false); }, child: 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.4, ), ), ) : NoData())), ); } TimelineTileBuilder _timelineBuilderWidget() { return TimelineTileBuilder.fromStyle( contentsAlign: ContentsAlign.basic, itemCount: state.lockLogItemList.length, contentsBuilder: (BuildContext context, int index) { final DoorLockLogDataItem timelineData = state.lockLogItemList[index]; return GestureDetector( onTap: () { Get.toNamed( Routers.doorLockLogDetailPage, arguments: {'doorLockLogDataItem': timelineData}, ); }, child: Padding( padding: EdgeInsets.only(left: 20.w, top: 20.h), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( timelineData.recordStr ?? '', textAlign: TextAlign.left, style: TextStyle( color: Colors.black, fontSize: 24.sp, fontWeight: FontWeight.w600, ), ), SizedBox( 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, ), ), SizedBox( height: 20.h, ), ], ), ), ); }, ); } Widget videoItem(RecordListData recordData) { return GestureDetector( onTap: () { if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) { final lockLogItemList = state.lockLogItemList.value; final list = lockLogItemList .where((e) => (e.videoUrl != null && e.videoUrl!.isNotEmpty) || (e.imagesUrl != null && e.imagesUrl!.isNotEmpty)) .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()); final cloudStorageData = CloudStorageData(date: selectDateString, recordList: list); Get.toNamed(Routers.videoLogDetailPage, arguments: { 'recordData': recordData, 'videoDataList': [cloudStorageData] }); } else if (recordData.imagesUrl != null && recordData.imagesUrl!.isNotEmpty) { Navigator.push( context, MaterialPageRoute( builder: (context) => FullScreenImagePage( imageUrl: recordData.imagesUrl!, ), ), ); } }, child: ((recordData.imagesUrl != null && recordData.imagesUrl != '') || (recordData.videoUrl != null && recordData.videoUrl != '')) ? Container( width: 260.w, height: 260.h, margin: const EdgeInsets.all(0), color: Colors.white, child: ClipRRect( borderRadius: BorderRadius.circular(10.w), child: _buildImageOrVideoItem(recordData), ), ) : SizedBox.shrink(), ); } _buildImageOrVideoItem(RecordListData recordData) { if (recordData.videoUrl != null && recordData.videoUrl!.isNotEmpty) { return _buildVideoItem(recordData); } else if (recordData.imagesUrl != null && recordData.imagesUrl!.isNotEmpty) { return _buildImageItem(recordData); } else { return SizedBox.shrink(); } } _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 Image.asset( 'images/icon_unHaveData.png', // 错误图片路径 fit: BoxFit.cover, ); }, ), ); } @override void didChangeDependencies() { super.didChangeDependencies(); /// 路由订阅 AppRouteObserver().routeObserver.subscribe(this, ModalRoute.of(context)!); } @override void dispose() { /// 取消路由订阅 AppRouteObserver().routeObserver.unsubscribe(this); super.dispose(); } /// 从上级界面进入 当前界面即将出现 @override void didPush() { super.didPush(); state.ifCurrentScreen.value = true; } /// 返回上一个界面 当前界面即将消失 @override void didPop() { super.didPop(); logic.cancelBlueConnetctToastTimer(); if (EasyLoading.isShow) { EasyLoading.dismiss(animation: true); } state.ifCurrentScreen.value = false; } /// 从下级返回 当前界面即将出现 @override void didPopNext() { super.didPopNext(); state.ifCurrentScreen.value = true; } /// 进入下级界面 当前界面即将消失 @override void didPushNext() { super.didPushNext(); logic.cancelBlueConnetctToastTimer(); if (EasyLoading.isShow) { EasyLoading.dismiss(animation: true); } state.ifCurrentScreen.value = false; } }