完成视频日志、监控模块的UI
7
star_lock/images/bumble_bee_captions.vtt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
WEBVTT
|
||||||
|
|
||||||
|
00:00:00.200 --> 00:00:01.750
|
||||||
|
[ Birds chirping ]
|
||||||
|
|
||||||
|
00:00:02.300 --> 00:00:05.000
|
||||||
|
[ Buzzing ]
|
||||||
BIN
star_lock/images/icon_round_white_unSelet.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
star_lock/images/icon_test20231113.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
star_lock/images/main/icon_lockDetail_messageReminding.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringCloseVoice.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringDeletVideo.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringEditVoice.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringOpenVoice.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringScreenshot.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringTalkback.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringUnlock.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
star_lock/images/main/icon_lockDetail_monitoringvoiceFrist.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
star_lock/images/main/icon_lockDetail_videoLog.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@ -84,11 +84,17 @@ import 'main/lockDetail/lcokSet/wirelessKeyboard/addWirelessKeyboard/addWireless
|
|||||||
import 'main/lockDetail/lcokSet/wirelessKeyboard/addWirelessKeyboardScreenNotLightOn/addWirelessKeyboardScreenNotLightOn_page.dart';
|
import 'main/lockDetail/lcokSet/wirelessKeyboard/addWirelessKeyboardScreenNotLightOn/addWirelessKeyboardScreenNotLightOn_page.dart';
|
||||||
import 'main/lockDetail/lcokSet/wirelessKeyboard/seletWirelessKeyboard/seletWirelessKeyboard_page.dart';
|
import 'main/lockDetail/lcokSet/wirelessKeyboard/seletWirelessKeyboard/seletWirelessKeyboard_page.dart';
|
||||||
import 'main/lockDetail/lcokSet/wirelessKeyboard/wirelessKeyboardList/wirelessKeyboard_page.dart';
|
import 'main/lockDetail/lcokSet/wirelessKeyboard/wirelessKeyboardList/wirelessKeyboard_page.dart';
|
||||||
|
import 'main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart';
|
||||||
|
import 'main/lockDetail/monitoring/monitoringRealTimeScreen/monitoringRealTimeScreen_page.dart';
|
||||||
import 'main/lockDetail/otherTypeKey/addFingerprint/addFingerprint/addFingerprint_page.dart';
|
import 'main/lockDetail/otherTypeKey/addFingerprint/addFingerprint/addFingerprint_page.dart';
|
||||||
import 'main/lockDetail/otherTypeKey/addFingerprint/addFingerprintTip/addFingerprintTip_page.dart';
|
import 'main/lockDetail/otherTypeKey/addFingerprint/addFingerprintTip/addFingerprintTip_page.dart';
|
||||||
import 'main/lockDetail/otherTypeKey/addICCard/addICCard_page.dart';
|
import 'main/lockDetail/otherTypeKey/addICCard/addICCard_page.dart';
|
||||||
import 'main/lockDetail/otherTypeKey/otherTypeKeyChangeDate/otherTypeKeyChangeDate_page.dart';
|
import 'main/lockDetail/otherTypeKey/otherTypeKeyChangeDate/otherTypeKeyChangeDate_page.dart';
|
||||||
import 'main/lockDetail/otherTypeKey/otherTypeKeyChangeValidityDate/otherTypeKeyChangeValidityDate_page.dart';
|
import 'main/lockDetail/otherTypeKey/otherTypeKeyChangeValidityDate/otherTypeKeyChangeValidityDate_page.dart';
|
||||||
|
import 'main/lockDetail/videoLog/editVideoLog/editVideoLog_page.dart';
|
||||||
|
import 'main/lockDetail/videoLog/videoLog/videoLog_page.dart';
|
||||||
|
import 'main/lockDetail/videoLog/videoLogDetail/videoLogDetail_page.dart';
|
||||||
|
import 'main/lockDetail/videoLog/videoLogDownLoad/videoLogDownLoad_page.dart';
|
||||||
import 'main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_page.dart';
|
import 'main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_page.dart';
|
||||||
import 'main/lockMian/demoMode/demoModeLockSet/demoModeLockSet_page.dart';
|
import 'main/lockMian/demoMode/demoModeLockSet/demoModeLockSet_page.dart';
|
||||||
import 'mine/about/about_page.dart';
|
import 'mine/about/about_page.dart';
|
||||||
@ -371,6 +377,12 @@ abstract class Routers {
|
|||||||
static const coerceFingerprintPage = '/coerceFingerprintPage'; //胁迫指纹
|
static const coerceFingerprintPage = '/coerceFingerprintPage'; //胁迫指纹
|
||||||
static const lowBatteryReminderPage = '/lowBatteryReminderPage'; //低电量提醒
|
static const lowBatteryReminderPage = '/lowBatteryReminderPage'; //低电量提醒
|
||||||
static const coerceFingerprintListPage = '/coerceFingerprintListPage'; //指纹列表
|
static const coerceFingerprintListPage = '/coerceFingerprintListPage'; //指纹列表
|
||||||
|
static const lockMonitoringPage = '/LockMonitoringPage'; //监控
|
||||||
|
static const monitoringRealTimeScreenPage = '/MonitoringRealTimeScreenPage'; //实时画面
|
||||||
|
static const videoLogPage = '/VideoLogPage'; // 视频日志
|
||||||
|
static const editVideoLogPage = '/EditVideoLogPage'; // 编辑视频日志
|
||||||
|
static const videoLogDetailPage = '/VideoLogDetailPage'; // 视频日志详情
|
||||||
|
static const videoLogDownLoadPage = '/VideoLogDownLoadPage'; // 视频下载列表
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AppRouters {
|
abstract class AppRouters {
|
||||||
@ -911,6 +923,24 @@ abstract class AppRouters {
|
|||||||
page: () => const LowBatteryReminderPage()),
|
page: () => const LowBatteryReminderPage()),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: Routers.coerceFingerprintListPage,
|
name: Routers.coerceFingerprintListPage,
|
||||||
page: () => const CoerceFingerprintListPage())
|
page: () => const CoerceFingerprintListPage()),
|
||||||
|
GetPage(
|
||||||
|
name: Routers.lockMonitoringPage,
|
||||||
|
page: () => const LockMonitoringPage()),
|
||||||
|
GetPage(
|
||||||
|
name: Routers.monitoringRealTimeScreenPage,
|
||||||
|
page: () => const MonitoringRealTimeScreenPage()),
|
||||||
|
GetPage(
|
||||||
|
name: Routers.videoLogPage,
|
||||||
|
page: () => const VideoLogPage()),
|
||||||
|
GetPage(
|
||||||
|
name: Routers.editVideoLogPage,
|
||||||
|
page: () => const EditVideoLogPage()),
|
||||||
|
GetPage(
|
||||||
|
name: Routers.videoLogDetailPage,
|
||||||
|
page: () => const VideoLogDetailPage()),
|
||||||
|
GetPage(
|
||||||
|
name: Routers.videoLogDownLoadPage,
|
||||||
|
page: () => const VideoLogDownLoadPage()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,7 @@ class BlueManage{
|
|||||||
} else {
|
} else {
|
||||||
_scanDevices.add(device);
|
_scanDevices.add(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanResultCallBack(_scanDevices);
|
scanResultCallBack(_scanDevices);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -94,6 +95,7 @@ class BlueManage{
|
|||||||
} else {
|
} else {
|
||||||
_scanDevices.add(device);
|
_scanDevices.add(device);
|
||||||
}
|
}
|
||||||
|
// print("_scanDevices:$_scanDevices");
|
||||||
scanResultCallBack(_scanDevices);
|
scanResultCallBack(_scanDevices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class SenderConfiguringWifiCommand extends SenderProtocol {
|
|||||||
String? ssid;
|
String? ssid;
|
||||||
String? password;
|
String? password;
|
||||||
int? numberOfServers;
|
int? numberOfServers;
|
||||||
int? listOfServers;
|
List<int>? listOfServers;
|
||||||
List<int>? token;
|
List<int>? token;
|
||||||
int? needAuthor;
|
int? needAuthor;
|
||||||
List<int>? publicKey;
|
List<int>? publicKey;
|
||||||
@ -76,7 +76,7 @@ class SenderConfiguringWifiCommand extends SenderProtocol {
|
|||||||
subData.add(numberOfServers!);
|
subData.add(numberOfServers!);
|
||||||
|
|
||||||
// listOfServers
|
// listOfServers
|
||||||
subData.add(listOfServers!);
|
subData.addAll(listOfServers!);
|
||||||
|
|
||||||
// token
|
// token
|
||||||
// subData.addAll(token!);
|
// subData.addAll(token!);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:encrypt/encrypt.dart' as ddd;
|
|
||||||
|
|
||||||
List<String> changeIntListToStringList(List<int> list){
|
List<String> changeIntListToStringList(List<int> list){
|
||||||
List<String> strList = [];
|
List<String> strList = [];
|
||||||
|
|||||||
@ -252,6 +252,12 @@ class CommandReciverManager {
|
|||||||
reply = SenderReferEventRecordTimeReply.parseData(commandType, data);
|
reply = SenderReferEventRecordTimeReply.parseData(commandType, data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// case 50:
|
||||||
|
// {
|
||||||
|
// // wifi配网
|
||||||
|
// reply = SenderConfiguringWifiReply.parseData(commandType, data);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
case 51:
|
case 51:
|
||||||
{
|
{
|
||||||
// wifi配网结果
|
// wifi配网结果
|
||||||
|
|||||||
@ -516,7 +516,7 @@ class IoSenderManage {
|
|||||||
required String? ssid,
|
required String? ssid,
|
||||||
required String? password,
|
required String? password,
|
||||||
required int? numberOfServers,
|
required int? numberOfServers,
|
||||||
required int? listOfServers,
|
required List<int>? listOfServers,
|
||||||
required List<int>? token,
|
required List<int>? token,
|
||||||
required int? needAuthor,
|
required int? needAuthor,
|
||||||
required List<int>? publicKey,
|
required List<int>? publicKey,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
|
|||||||
import 'package:network_info_plus/network_info_plus.dart';
|
import 'package:network_info_plus/network_info_plus.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'package:star_lock/tools/toast.dart';
|
||||||
|
|
||||||
import '../../../../blue/blue_manage.dart';
|
import '../../../../blue/blue_manage.dart';
|
||||||
import '../../../../blue/io_protocol/io_configuringWifi.dart';
|
import '../../../../blue/io_protocol/io_configuringWifi.dart';
|
||||||
@ -24,6 +25,23 @@ class ConfiguringWifiLogic extends BaseGetXController{
|
|||||||
var entity = await ApiRepository.to.getWifiLockServiceIpAndPort();
|
var entity = await ApiRepository.to.getWifiLockServiceIpAndPort();
|
||||||
if(entity.errorCode! == 0){
|
if(entity.errorCode! == 0){
|
||||||
state.configuringWifiEntity.value = entity;
|
state.configuringWifiEntity.value = entity;
|
||||||
|
|
||||||
|
// var serversList = <int>[];
|
||||||
|
// for(int i = 0; i<state.configuringWifiEntity.value.data!.serviceList!.length; i++){
|
||||||
|
// var item = state.configuringWifiEntity.value.data!.serviceList![i];
|
||||||
|
// var itemList = item.serviceIp!.split(".");
|
||||||
|
// itemList.forEach((element) {
|
||||||
|
// serversList.add(int.parse(element));
|
||||||
|
// });
|
||||||
|
// // serversList.add(int.parse(item.port!));
|
||||||
|
//
|
||||||
|
// double typeDouble = int.parse(item.port!) / 256;
|
||||||
|
// int type1 = typeDouble.toInt();
|
||||||
|
// int type2 = int.parse(item.port!) % 256;
|
||||||
|
// serversList.add(type1);
|
||||||
|
// serversList.add(type2);
|
||||||
|
// }
|
||||||
|
// print("serversListserversList:$serversList");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,26 +49,15 @@ class ConfiguringWifiLogic extends BaseGetXController{
|
|||||||
late StreamSubscription<Reply> _replySubscription;
|
late StreamSubscription<Reply> _replySubscription;
|
||||||
void _initReplySubscription() {
|
void _initReplySubscription() {
|
||||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) async {
|
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) async {
|
||||||
// 配置wifi
|
// WIFI配网结果
|
||||||
if(reply is SenderConfiguringWifiReply) {
|
if(reply is SenderConfiguringWifiReply) {
|
||||||
_replySenderConfiguringWifi(reply);
|
_replySenderConfiguringWifi(reply);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开门数据解析
|
// WIFI配网结果
|
||||||
Future<void> _replySenderConfiguringWifi(Reply reply) async {
|
Future<void> _replySenderConfiguringWifi(Reply reply) async {
|
||||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
|
||||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
|
||||||
|
|
||||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
|
||||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
|
||||||
|
|
||||||
var tokenData = reply.data.sublist(2, 6);
|
|
||||||
var saveStrList = changeIntListToStringList(tokenData);
|
|
||||||
print("openDoorToken:$tokenData");
|
|
||||||
Storage.setStringList(saveBlueToken, saveStrList);
|
|
||||||
|
|
||||||
int status = reply.data[6];
|
int status = reply.data[6];
|
||||||
print("status:$status");
|
print("status:$status");
|
||||||
|
|
||||||
@ -58,20 +65,48 @@ class ConfiguringWifiLogic extends BaseGetXController{
|
|||||||
case 0x00:
|
case 0x00:
|
||||||
//成功
|
//成功
|
||||||
print("${reply.commandType}数据解析成功");
|
print("${reply.commandType}数据解析成功");
|
||||||
|
Toast.show(msg: "配网成功");
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
//无权限
|
//无权限
|
||||||
print("${reply.commandType}需要鉴权");
|
print("${reply.commandType}需要鉴权");
|
||||||
|
|
||||||
IoSenderManage.senderOpenLock(
|
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||||
keyID: "1",
|
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||||
|
|
||||||
|
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||||
|
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||||
|
|
||||||
|
var tokenData = reply.data.sublist(7, 10);
|
||||||
|
var saveStrList = changeIntListToStringList(tokenData);
|
||||||
|
print("openDoorToken:$tokenData");
|
||||||
|
Storage.setStringList(saveBlueToken, saveStrList);
|
||||||
|
|
||||||
|
var serversList = <int>[];
|
||||||
|
for(int i = 0; i<state.configuringWifiEntity.value.data!.serviceList!.length; i++){
|
||||||
|
var item = state.configuringWifiEntity.value.data!.serviceList![i];
|
||||||
|
var itemList = item.serviceIp!.split(".");
|
||||||
|
itemList.forEach((element) {
|
||||||
|
serversList.add(int.parse(element));
|
||||||
|
});
|
||||||
|
|
||||||
|
double typeDouble = int.parse(item.port!) / 256;
|
||||||
|
int type1 = typeDouble.toInt();
|
||||||
|
int type2 = int.parse(item.port!) % 256;
|
||||||
|
serversList.add(type1);
|
||||||
|
serversList.add(type2);
|
||||||
|
}
|
||||||
|
|
||||||
|
IoSenderManage.senderConfiguringWifiCommand(
|
||||||
|
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
|
||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
openMode: 1,
|
ssid: state.wifiNameController.text,
|
||||||
openTime: DateTime.now().millisecondsSinceEpoch,
|
password: state.wifiPWDController.text,
|
||||||
|
numberOfServers: state.configuringWifiEntity.value.data!.serviceNum,
|
||||||
|
listOfServers: serversList,
|
||||||
token: tokenData,
|
token: tokenData,
|
||||||
needAuthor: 1,
|
needAuthor: 1,
|
||||||
signKey: signKeyDataList,
|
publicKey: publicKeyDataList,
|
||||||
privateKey: getPrivateKeyList,
|
privateKey: getPrivateKeyList,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -109,13 +144,28 @@ class ConfiguringWifiLogic extends BaseGetXController{
|
|||||||
print("openDoorTokenPubToken:$getTokenList");
|
print("openDoorTokenPubToken:$getTokenList");
|
||||||
|
|
||||||
// print("millisecondsSinceEpoch/1000:${DateTime.now().millisecondsSinceEpoch~/1000}");
|
// print("millisecondsSinceEpoch/1000:${DateTime.now().millisecondsSinceEpoch~/1000}");
|
||||||
|
var serversList = <int>[];
|
||||||
|
for(int i = 0; i<state.configuringWifiEntity.value.data!.serviceList!.length; i++){
|
||||||
|
var item = state.configuringWifiEntity.value.data!.serviceList![i];
|
||||||
|
var itemList = item.serviceIp!.split(".");
|
||||||
|
itemList.forEach((element) {
|
||||||
|
serversList.add(int.parse(element));
|
||||||
|
});
|
||||||
|
|
||||||
|
double typeDouble = int.parse(item.port!) / 256;
|
||||||
|
int type1 = typeDouble.toInt();
|
||||||
|
int type2 = int.parse(item.port!) % 256;
|
||||||
|
serversList.add(type1);
|
||||||
|
serversList.add(type2);
|
||||||
|
}
|
||||||
|
|
||||||
IoSenderManage.senderConfiguringWifiCommand(
|
IoSenderManage.senderConfiguringWifiCommand(
|
||||||
keyID: "1",
|
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
|
||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
ssid: state.wifiNameController.text,
|
ssid: state.wifiNameController.text,
|
||||||
password: state.wifiPWDController.text,
|
password: state.wifiPWDController.text,
|
||||||
numberOfServers: state.configuringWifiEntity.value.data!.serviceNum,
|
numberOfServers: state.configuringWifiEntity.value.data!.serviceNum,
|
||||||
listOfServers: 0,
|
listOfServers: serversList,
|
||||||
token: getTokenList,
|
token: getTokenList,
|
||||||
needAuthor: 1,
|
needAuthor: 1,
|
||||||
publicKey: publicKeyDataList,
|
publicKey: publicKeyDataList,
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class _ConfiguringWifiPageState extends State<ConfiguringWifiPage> {
|
|||||||
configuringWifiTFWidget(TranslationLoader.lanKeys!.wifiPassward!.tr, TranslationLoader.lanKeys!.pleaseEnterWifiPwd!.tr, state.wifiPWDController),
|
configuringWifiTFWidget(TranslationLoader.lanKeys!.wifiPassward!.tr, TranslationLoader.lanKeys!.pleaseEnterWifiPwd!.tr, state.wifiPWDController),
|
||||||
SizedBox(height: 50.h,),
|
SizedBox(height: 50.h,),
|
||||||
SubmitBtn(btnName: TranslationLoader.lanKeys!.sure!.tr, onClick: () {
|
SubmitBtn(btnName: TranslationLoader.lanKeys!.sure!.tr, onClick: () {
|
||||||
|
logic.senderConfiguringWifiAction();
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
@ -51,14 +51,14 @@ class _ConfiguringWifiPageState extends State<ConfiguringWifiPage> {
|
|||||||
leftTitel: titleStr,
|
leftTitel: titleStr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveRightWidget: true,
|
isHaveRightWidget: true,
|
||||||
rightWidget: getTFWidget(rightTitle)),
|
rightWidget: getTFWidget(rightTitle, controller)),
|
||||||
Container(height: 10.h),
|
Container(height: 10.h),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 接受者信息输入框
|
// 接受者信息输入框
|
||||||
Widget getTFWidget(String tfStr) {
|
Widget getTFWidget(String tfStr, TextEditingController controller) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 50.h,
|
height: 50.h,
|
||||||
width: 300.w,
|
width: 300.w,
|
||||||
@ -68,7 +68,7 @@ class _ConfiguringWifiPageState extends State<ConfiguringWifiPage> {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
//输入框一行
|
//输入框一行
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
// controller: _controller,
|
controller: controller,
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
|||||||
@ -3,15 +3,20 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../lockSet/lockSetInfo_entity.dart';
|
||||||
import 'configuringWifiEntity.dart';
|
import 'configuringWifiEntity.dart';
|
||||||
|
|
||||||
class ConfiguringWifiState{
|
class ConfiguringWifiState{
|
||||||
var configuringWifiEntity = ConfiguringWifiEntity().obs;
|
var configuringWifiEntity = ConfiguringWifiEntity().obs;
|
||||||
|
var lockSetInfoData = LockSetInfoData().obs;
|
||||||
|
var lockBasicInfo = LockBasicInfo().obs;
|
||||||
|
|
||||||
TextEditingController wifiNameController = TextEditingController();
|
TextEditingController wifiNameController = TextEditingController();
|
||||||
TextEditingController wifiPWDController = TextEditingController();
|
TextEditingController wifiPWDController = TextEditingController();
|
||||||
ConfiguringWifiState() {
|
ConfiguringWifiState() {
|
||||||
// wifiNameController.text = emailOrPhone.value;
|
var map = Get.arguments;
|
||||||
|
lockSetInfoData.value = map["lockSetInfoData"];
|
||||||
|
lockBasicInfo.value = lockSetInfoData.value.lockBasicInfo!;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,4 +1,3 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -421,14 +420,20 @@ class _LockSetPageState extends State<LockSetPage> with RouteAware {
|
|||||||
() => Visibility(
|
() => Visibility(
|
||||||
visible:
|
visible:
|
||||||
state.lockFeature.value.wifi == 1 ? true : false,
|
state.lockFeature.value.wifi == 1 ? true : false,
|
||||||
child: CommonItem(
|
child:
|
||||||
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.wifiDistributionNetwork!.tr,
|
leftTitel: TranslationLoader.lanKeys!.wifiDistributionNetwork!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveLine: true,
|
isHaveLine: true,
|
||||||
isHaveDirection: true,
|
isHaveDirection: true,
|
||||||
action: () {
|
action: () {
|
||||||
Get.toNamed(Routers.configuringWifiPage);
|
Get.toNamed(Routers.configuringWifiPage,
|
||||||
})),
|
arguments: {
|
||||||
|
'lockSetInfoData':
|
||||||
|
state.lockSetInfoData.value
|
||||||
|
});
|
||||||
|
})
|
||||||
|
),
|
||||||
),
|
),
|
||||||
// Obx(() =>
|
// Obx(() =>
|
||||||
// 锁时间
|
// 锁时间
|
||||||
|
|||||||
@ -81,16 +81,16 @@ class _MsgNotificationPageState extends State<MsgNotificationPage> {
|
|||||||
Get.toNamed(Routers.nDaysUnopenedPage);
|
Get.toNamed(Routers.nDaysUnopenedPage);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(
|
// SizedBox(
|
||||||
height: 20.h,
|
// height: 20.h,
|
||||||
),
|
// ),
|
||||||
Obx(() => CommonItem(
|
// Obx(() => CommonItem(
|
||||||
leftTitel: '离家开门',
|
// leftTitel: '离家开门',
|
||||||
rightTitle: "",
|
// rightTitle: "",
|
||||||
isHaveLine: false,
|
// isHaveLine: false,
|
||||||
isHaveRightWidget: true,
|
// isHaveRightWidget: true,
|
||||||
rightWidget:
|
// rightWidget:
|
||||||
SizedBox(width: 60.w, height: 50.h, child: _switch(1)))),
|
// SizedBox(width: 60.w, height: 50.h, child: _switch(1)))),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 20.h,
|
height: 20.h,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -72,7 +72,10 @@ class _LockDetailPageState extends State<LockDetailPage>
|
|||||||
height: 1.sh - ScreenUtil().statusBarHeight * 2,
|
height: 1.sh - ScreenUtil().statusBarHeight * 2,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [topWidget(), Expanded(child: bottomWidget())],
|
children: [
|
||||||
|
topWidget(),
|
||||||
|
Expanded(child: bottomWidget())
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -114,7 +117,7 @@ class _LockDetailPageState extends State<LockDetailPage>
|
|||||||
Stack(
|
Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
SizedBox(
|
||||||
width: 1.sw - 120.w * 2,
|
width: 1.sw - 120.w * 2,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -124,22 +127,15 @@ class _LockDetailPageState extends State<LockDetailPage>
|
|||||||
))),
|
))),
|
||||||
Positioned(
|
Positioned(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text("100%", style: TextStyle(fontSize: 18.sp, color: AppColors.darkGrayTextColor)),
|
||||||
"100%",
|
SizedBox(width: 2.w),
|
||||||
style: TextStyle(
|
Image.asset('images/main/icon_main_cell.png', width: 30.w, height: 24.w),
|
||||||
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
|
SizedBox(width: 30.w),
|
||||||
),
|
],
|
||||||
SizedBox(width: 2.w),
|
)
|
||||||
Image.asset(
|
)
|
||||||
'images/main/icon_main_cell.png',
|
|
||||||
width: 30.w,
|
|
||||||
height: 24.w,
|
|
||||||
),
|
|
||||||
SizedBox(width: 30.w),
|
|
||||||
],
|
|
||||||
))
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 30.h),
|
SizedBox(height: 30.h),
|
||||||
@ -383,7 +379,10 @@ class _LockDetailPageState extends State<LockDetailPage>
|
|||||||
bottomItem('images/main/icon_catEyes.png', '监控', () {
|
bottomItem('images/main/icon_catEyes.png', '监控', () {
|
||||||
// Navigator.pushNamed(context, Routers.otherTypeKeyListPage,
|
// Navigator.pushNamed(context, Routers.otherTypeKeyListPage,
|
||||||
// arguments: 1);
|
// arguments: 1);
|
||||||
Toast.show(msg: "功能暂未开放");
|
// Toast.show(msg: "功能暂未开放");
|
||||||
|
Get.toNamed(Routers.lockMonitoringPage, arguments: {
|
||||||
|
"lockId": widget.lockListInfoItemEntity.lockId
|
||||||
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -402,11 +401,12 @@ class _LockDetailPageState extends State<LockDetailPage>
|
|||||||
arguments: {"keyInfo": widget.lockListInfoItemEntity});
|
arguments: {"keyInfo": widget.lockListInfoItemEntity});
|
||||||
}),
|
}),
|
||||||
// 视频日志
|
// 视频日志
|
||||||
bottomItem('images/main/icon_main_set.png', "视频日志", () {
|
bottomItem('images/main/icon_lockDetail_videoLog.png', "视频日志", () {
|
||||||
//视频日志
|
//视频日志
|
||||||
|
Get.toNamed(Routers.videoLogPage);
|
||||||
}),
|
}),
|
||||||
// 消息提醒
|
// 消息提醒
|
||||||
bottomItem('images/main/icon_main_set.png', "消息提醒", () {
|
bottomItem('images/main/icon_lockDetail_messageReminding.png', "消息提醒", () {
|
||||||
Get.toNamed(Routers.msgNotificationPage);
|
Get.toNamed(Routers.msgNotificationPage);
|
||||||
}),
|
}),
|
||||||
// 设置
|
// 设置
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
import '../../../../tools/baseGetXController.dart';
|
||||||
|
import 'lockMonitoring_state.dart';
|
||||||
|
|
||||||
|
class LockMonitoringLogic extends BaseGetXController {
|
||||||
|
final LockMonitoringState state = LockMonitoringState();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../../appRouters.dart';
|
||||||
|
import '../../../../app_settings/app_colors.dart';
|
||||||
|
import 'lockMonitoring_logic.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class LockMonitoringPage extends StatefulWidget {
|
||||||
|
const LockMonitoringPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LockMonitoringPage> createState() => _LockMonitoringPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
||||||
|
final logic = Get.put(LockMonitoringLogic());
|
||||||
|
final state = Get.find<LockMonitoringLogic>().state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: 1.sw,
|
||||||
|
height: 1.sh,
|
||||||
|
color: Colors.white,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Stack(
|
||||||
|
// alignment: Alignment.bottomCenter,
|
||||||
|
children: [
|
||||||
|
Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover),
|
||||||
|
Positioned(
|
||||||
|
top: ScreenUtil().statusBarHeight + 30.h,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 30.w),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(30.h)
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/icon_left_black.png"),),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 10.w,
|
||||||
|
child: Container(
|
||||||
|
width: 1.sw - 30.w*2,
|
||||||
|
// height: 300.h,
|
||||||
|
margin: EdgeInsets.all(30.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xC83C3F41),
|
||||||
|
borderRadius: BorderRadius.circular(20.h)
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
bottomTopBtnWidget(),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
bottomBottomBtnWidget(),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomTopBtnWidget(){
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// 打开关闭声音
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
state.isOpenVoice.value = !state.isOpenVoice.value;
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(5.w),
|
||||||
|
child: Obx(() => Image(
|
||||||
|
width: 40.w,
|
||||||
|
height: 40.w,
|
||||||
|
image: state.isOpenVoice.value
|
||||||
|
? const AssetImage("images/main/icon_lockDetail_monitoringCloseVoice.png")
|
||||||
|
: const AssetImage("images/main/icon_lockDetail_monitoringOpenVoice.png")
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 60.w),
|
||||||
|
// 截图
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// Get.toNamed(Routers.monitoringRealTimeScreenPage);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(5.w),
|
||||||
|
child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringScreenshot.png")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 60.w),
|
||||||
|
// 录制
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// Get.toNamed(Routers.monitoringRealTimeScreenPage);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(5.w),
|
||||||
|
child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringScreenRecording.png")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomBottomBtnWidget(){
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringTalkback.png", "点击对讲", Colors.white,(){
|
||||||
|
|
||||||
|
}),
|
||||||
|
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "长按开锁", AppColors.mainColor,(){
|
||||||
|
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomBtnItemWidget(String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
||||||
|
var wh = 80.w;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onClick,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 140.h,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: wh,
|
||||||
|
height: wh,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular((wh+ 10.w*2)/2)
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(20.w),
|
||||||
|
child: Image.asset(iconUrl, fit: BoxFit.fitWidth),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20.w),
|
||||||
|
Expanded(child: Text(name, style: TextStyle(fontSize: 20.sp, color: Colors.white), textAlign: TextAlign.center))
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class LockMonitoringState {
|
||||||
|
var isOpenVoice = false.obs;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'monitoringRealTimeScreen_state.dart';
|
||||||
|
|
||||||
|
class MonitoringRealTimeScreenLogic extends BaseGetXController{
|
||||||
|
MonitoringRealTimeScreenState state = MonitoringRealTimeScreenState();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../../app_settings/app_colors.dart';
|
||||||
|
import '../../../../tools/titleAppBar.dart';
|
||||||
|
import 'monitoringRealTimeScreen_logic.dart';
|
||||||
|
|
||||||
|
class MonitoringRealTimeScreenPage extends StatefulWidget {
|
||||||
|
const MonitoringRealTimeScreenPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MonitoringRealTimeScreenPage> createState() => _MonitoringRealTimeScreenPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MonitoringRealTimeScreenPageState extends State<MonitoringRealTimeScreenPage> {
|
||||||
|
final logic = Get.put(MonitoringRealTimeScreenLogic());
|
||||||
|
final state = Get.find<MonitoringRealTimeScreenLogic>().state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.mainBackgroundColor,
|
||||||
|
appBar: TitleAppBar(
|
||||||
|
barTitle: "实时播放",
|
||||||
|
haveBack: true,
|
||||||
|
backgroundColor: AppColors.mainColor,
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sw/5*4, fit: BoxFit.cover),
|
||||||
|
middleWidget(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 60.h,
|
||||||
|
child: bottomBtnWidget()
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget middleWidget(){
|
||||||
|
return Container(
|
||||||
|
color: Colors.grey,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
// 打开关闭声音
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
state.isOpenVoice.value = !state.isOpenVoice.value;
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(5.w),
|
||||||
|
child: Obx(() => Image(
|
||||||
|
width: 40.w,
|
||||||
|
height: 40.w,
|
||||||
|
image: state.isOpenVoice.value
|
||||||
|
? const AssetImage("images/main/icon_lockDetail_monitoringCloseVoice.png")
|
||||||
|
: const AssetImage("images/main/icon_lockDetail_monitoringOpenVoice.png")
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// SizedBox(width: 60.w),
|
||||||
|
// 截图
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(5.w),
|
||||||
|
child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringScreenshot.png")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// SizedBox(width: 60.w),
|
||||||
|
// 录制
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(5.w),
|
||||||
|
child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringScreenRecording.png")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomBtnWidget(){
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringTalkback.png", "点击对讲", Colors.white, (){
|
||||||
|
|
||||||
|
}),
|
||||||
|
SizedBox(width: (1.sw - 80.w)/3),
|
||||||
|
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "长按开锁", AppColors.mainColor, (){
|
||||||
|
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomBtnItemWidget(String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
||||||
|
var wh = 80.w;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onClick,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 140.h,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: wh,
|
||||||
|
height: wh,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular((wh+ 10.w*2)/2)
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(20.w),
|
||||||
|
child: Image.asset(iconUrl, fit: BoxFit.fitWidth),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20.w),
|
||||||
|
Expanded(child: Text(name, style: TextStyle(fontSize: 20.sp, color: Colors.black), textAlign: TextAlign.center))
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class MonitoringRealTimeScreenState{
|
||||||
|
var isOpenVoice = false.obs;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
mixin AfterLayoutMixin<T extends StatefulWidget> on State<T> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) => afterFirstLayout(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
void afterFirstLayout(BuildContext context);
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
import 'video_player_control.dart';
|
||||||
|
|
||||||
|
class ControllerWidget extends InheritedWidget {
|
||||||
|
final String title;
|
||||||
|
final GlobalKey<VideoPlayerControlState> controlKey;
|
||||||
|
final Widget child;
|
||||||
|
final VideoPlayerController controller;
|
||||||
|
final bool videoInit;
|
||||||
|
|
||||||
|
ControllerWidget(
|
||||||
|
{Key? key,
|
||||||
|
required this.controlKey,
|
||||||
|
required this.child,
|
||||||
|
required this.controller,
|
||||||
|
required this.videoInit,
|
||||||
|
required this.title
|
||||||
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
|
//定义一个便捷方法,方便子树中的widget获取共享数据
|
||||||
|
static ControllerWidget? of(BuildContext context) {
|
||||||
|
return context.dependOnInheritedWidgetOfExactType<ControllerWidget>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(InheritedWidget oldWidget) {
|
||||||
|
// TODO: implement updateShouldNotify
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,209 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:ui';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
// import 'package:screen/screen.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
import 'controller_widget.dart';
|
||||||
|
import 'video_player_control.dart';
|
||||||
|
import 'video_player_pan.dart';
|
||||||
|
|
||||||
|
enum VideoPlayerType { network, asset, file }
|
||||||
|
|
||||||
|
class VideoPlayerUI extends StatefulWidget {
|
||||||
|
VideoPlayerUI.network({
|
||||||
|
Key? key,
|
||||||
|
required String this.url, // 当前需要播放的地址
|
||||||
|
required this.width, // 播放器尺寸(大于等于视频播放区域)
|
||||||
|
required this.height,
|
||||||
|
this.title = '', // 视频需要显示的标题
|
||||||
|
}) : type = VideoPlayerType.network,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
VideoPlayerUI.asset({
|
||||||
|
Key? key,
|
||||||
|
required String dataSource, // 当前需要播放的地址
|
||||||
|
this.width = double.infinity, // 播放器尺寸(大于等于视频播放区域)
|
||||||
|
this.height = double.infinity,
|
||||||
|
this.title = '', // 视频需要显示的标题
|
||||||
|
}) : type = VideoPlayerType.asset,
|
||||||
|
url = dataSource,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
const VideoPlayerUI.file({
|
||||||
|
Key? key,
|
||||||
|
required File file, // 当前需要播放的地址
|
||||||
|
this.width = double.infinity, // 播放器尺寸(大于等于视频播放区域)
|
||||||
|
this.height = double.infinity,
|
||||||
|
this.title = '', // 视频需要显示的标题
|
||||||
|
}) : type = VideoPlayerType.file,
|
||||||
|
url = file,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
final url;
|
||||||
|
final VideoPlayerType type;
|
||||||
|
final double width;
|
||||||
|
final double height;
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_VideoPlayerUIState createState() => _VideoPlayerUIState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoPlayerUIState extends State<VideoPlayerUI> {
|
||||||
|
final GlobalKey<VideoPlayerControlState> _key =
|
||||||
|
GlobalKey<VideoPlayerControlState>();
|
||||||
|
|
||||||
|
///指示video资源是否加载完成,加载完成后会获得总时长和视频长宽比等信息
|
||||||
|
bool _videoInit = false;
|
||||||
|
bool _videoError = false;
|
||||||
|
|
||||||
|
late VideoPlayerController _controller; // video控件管理器
|
||||||
|
|
||||||
|
/// 记录是否全屏
|
||||||
|
bool get _isFullScreen =>
|
||||||
|
MediaQuery.of(context).orientation == Orientation.landscape;
|
||||||
|
|
||||||
|
Size get _window => MediaQueryData.fromWindow(window).size;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_urlChange(); // 初始进行一次url加载
|
||||||
|
// Screen.keepOn(true); // 设置屏幕常亮
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(VideoPlayerUI oldWidget) {
|
||||||
|
if (oldWidget.url != widget.url) {
|
||||||
|
_urlChange(); // url变化时重新执行一次url加载
|
||||||
|
}
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() async {
|
||||||
|
super.dispose();
|
||||||
|
if (_controller != null) {
|
||||||
|
_controller.removeListener(_videoListener);
|
||||||
|
_controller.dispose();
|
||||||
|
}
|
||||||
|
// Screen.keepOn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SafeArea(
|
||||||
|
top: !_isFullScreen,
|
||||||
|
bottom: !_isFullScreen,
|
||||||
|
left: !_isFullScreen,
|
||||||
|
right: !_isFullScreen,
|
||||||
|
child: Container(
|
||||||
|
width: _isFullScreen ? _window.width : widget.width,
|
||||||
|
height: _isFullScreen ? _window.height : widget.height,
|
||||||
|
child: _isHadUrl(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否有url
|
||||||
|
Widget _isHadUrl() {
|
||||||
|
if (widget.url != null) {
|
||||||
|
return ControllerWidget(
|
||||||
|
controlKey: _key,
|
||||||
|
controller: _controller,
|
||||||
|
videoInit: _videoInit,
|
||||||
|
title: widget.title,
|
||||||
|
child: VideoPlayerPan(
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
color: Colors.black,
|
||||||
|
child: _isVideoInit(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
'暂无视频信息',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载url成功时,根据视频比例渲染播放器
|
||||||
|
Widget _isVideoInit() {
|
||||||
|
if (_videoInit) {
|
||||||
|
return AspectRatio(
|
||||||
|
aspectRatio: _controller.value.aspectRatio,
|
||||||
|
child: VideoPlayer(_controller),
|
||||||
|
);
|
||||||
|
} else if (_controller != null && _videoError) {
|
||||||
|
return Text(
|
||||||
|
'加载出错',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return SizedBox(
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _urlChange() async {
|
||||||
|
if (widget.url == null || widget.url == '') return;
|
||||||
|
if (_controller != null) {
|
||||||
|
/// 如果控制器存在,清理掉重新创建
|
||||||
|
_controller.removeListener(_videoListener);
|
||||||
|
_controller.dispose();
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
/// 重置组件参数
|
||||||
|
_videoInit = false;
|
||||||
|
_videoError = false;
|
||||||
|
});
|
||||||
|
if (widget.type == VideoPlayerType.file) {
|
||||||
|
_controller = VideoPlayerController.file(widget.url);
|
||||||
|
} else if (widget.type == VideoPlayerType.asset) {
|
||||||
|
_controller = VideoPlayerController.asset(widget.url);
|
||||||
|
} else {
|
||||||
|
_controller = VideoPlayerController.network(widget.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 加载资源完成时,监听播放进度,并且标记_videoInit=true加载完成
|
||||||
|
_controller.addListener(_videoListener);
|
||||||
|
await _controller.initialize();
|
||||||
|
setState(() {
|
||||||
|
_videoInit = true;
|
||||||
|
_videoError = false;
|
||||||
|
_controller.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _videoListener() async {
|
||||||
|
if (_controller.value.hasError) {
|
||||||
|
setState(() {
|
||||||
|
_videoError = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Duration? res = await _controller.position;
|
||||||
|
if (res! >= _controller.value.duration) {
|
||||||
|
await _controller.seekTo(Duration(seconds: 0));
|
||||||
|
await _controller.pause();
|
||||||
|
}
|
||||||
|
if (_controller.value.isPlaying && _key.currentState != null) {
|
||||||
|
/// 减少build次数
|
||||||
|
_key.currentState!.setPosition(
|
||||||
|
position: res,
|
||||||
|
totalDuration: _controller.value.duration,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,273 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:auto_orientation/auto_orientation.dart';
|
||||||
|
import 'package:common_utils/common_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
import 'controller_widget.dart';
|
||||||
|
import 'video_player_slider.dart';
|
||||||
|
|
||||||
|
class VideoPlayerControl extends StatefulWidget {
|
||||||
|
VideoPlayerControl({
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
VideoPlayerControlState createState() => VideoPlayerControlState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class VideoPlayerControlState extends State<VideoPlayerControl> {
|
||||||
|
VideoPlayerController get controller => ControllerWidget.of(context)!.controller;
|
||||||
|
bool get videoInit => ControllerWidget.of(context)!.videoInit;
|
||||||
|
String get title=>ControllerWidget.of(context)!.title;
|
||||||
|
// 记录video播放进度
|
||||||
|
Duration _position = Duration(seconds: 0);
|
||||||
|
Duration _totalDuration = Duration(seconds: 0);
|
||||||
|
late Timer _timer; // 计时器,用于延迟隐藏控件ui
|
||||||
|
bool _hidePlayControl = true; // 控制是否隐藏控件ui
|
||||||
|
double _playControlOpacity = 0; // 通过透明度动画显示/隐藏控件ui
|
||||||
|
/// 记录是否全屏
|
||||||
|
bool get _isFullScreen =>
|
||||||
|
MediaQuery.of(context).orientation == Orientation.landscape;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
if (_timer != null) {
|
||||||
|
_timer.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onDoubleTap: _playOrPause,
|
||||||
|
onTap: _togglePlayControl,
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: WillPopScope(
|
||||||
|
child: Offstage(
|
||||||
|
offstage: _hidePlayControl,
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
// 加入透明度动画
|
||||||
|
opacity: _playControlOpacity,
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[_top(), _middle(), _bottom(context)],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onWillPop: _onWillPop,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拦截返回键
|
||||||
|
Future<bool> _onWillPop() async {
|
||||||
|
if (_isFullScreen) {
|
||||||
|
_toggleFullScreen();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 供父组件调用刷新页面,减少父组件的build
|
||||||
|
void setPosition({position, totalDuration}) {
|
||||||
|
setState(() {
|
||||||
|
_position = position;
|
||||||
|
_totalDuration = totalDuration;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _bottom(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
// 底部控件的容器
|
||||||
|
width: double.infinity,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
// 来点黑色到透明的渐变优雅一下
|
||||||
|
begin: Alignment.bottomCenter,
|
||||||
|
end: Alignment.topCenter,
|
||||||
|
colors: [Color.fromRGBO(0, 0, 0, .7), Color.fromRGBO(0, 0, 0, .1)],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
// 加载完成时才渲染,flex布局
|
||||||
|
children: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
// 播放按钮
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
iconSize: 26,
|
||||||
|
icon: Icon(
|
||||||
|
// 根据控制器动态变化播放图标还是暂停
|
||||||
|
controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: _playOrPause,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
// 相当于前端的flex: 1
|
||||||
|
child: VideoPlayerSlider(
|
||||||
|
startPlayControlTimer: _startPlayControlTimer,
|
||||||
|
timer: _timer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
// 播放时间
|
||||||
|
margin: EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
'${DateUtil.formatDateMs(
|
||||||
|
_position!.inMilliseconds,
|
||||||
|
format: 'mm:ss',
|
||||||
|
)}/${DateUtil.formatDateMs(
|
||||||
|
_totalDuration!.inMilliseconds,
|
||||||
|
format: 'mm:ss',
|
||||||
|
)}',
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
// 全屏/横屏按钮
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
iconSize: 26,
|
||||||
|
icon: Icon(
|
||||||
|
// 根据当前屏幕方向切换图标
|
||||||
|
_isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// 点击切换是否全屏
|
||||||
|
_toggleFullScreen();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _middle() {
|
||||||
|
return Expanded(
|
||||||
|
child: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _top() {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
// 来点黑色到透明的渐变优雅一下
|
||||||
|
begin: Alignment.bottomCenter,
|
||||||
|
end: Alignment.topCenter,
|
||||||
|
colors: [Color.fromRGBO(0, 0, 0, .7), Color.fromRGBO(0, 0, 0, .1)],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: <Widget>[
|
||||||
|
//在最上层或者不是横屏则隐藏按钮
|
||||||
|
ModalRoute.of(context)!.isFirst && !_isFullScreen
|
||||||
|
? Container()
|
||||||
|
: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.arrow_back,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: backPress),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
//在最上层或者不是横屏则隐藏按钮
|
||||||
|
ModalRoute.of(context)!.isFirst && !_isFullScreen
|
||||||
|
? Container()
|
||||||
|
: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.arrow_back,
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void backPress() {
|
||||||
|
print(_isFullScreen);
|
||||||
|
// 如果是全屏,点击返回键则关闭全屏,如果不是,则系统返回键
|
||||||
|
if (_isFullScreen) {
|
||||||
|
_toggleFullScreen();
|
||||||
|
} else if(ModalRoute.of(context)!.isFirst) {
|
||||||
|
SystemNavigator.pop();
|
||||||
|
}else{
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _playOrPause() {
|
||||||
|
/// 同样的,点击动态播放或者暂停
|
||||||
|
if (videoInit) {
|
||||||
|
controller.value.isPlaying ? controller.pause() : controller.play();
|
||||||
|
_startPlayControlTimer(); // 操作控件后,重置延迟隐藏控件的timer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _togglePlayControl() {
|
||||||
|
setState(() {
|
||||||
|
if (_hidePlayControl) {
|
||||||
|
/// 如果隐藏则显示
|
||||||
|
_hidePlayControl = false;
|
||||||
|
_playControlOpacity = 1;
|
||||||
|
_startPlayControlTimer(); // 开始计时器,计时后隐藏
|
||||||
|
} else {
|
||||||
|
/// 如果显示就隐藏
|
||||||
|
if (_timer != null) _timer.cancel(); // 有计时器先移除计时器
|
||||||
|
_playControlOpacity = 0;
|
||||||
|
Future.delayed(Duration(milliseconds: 500)).whenComplete(() {
|
||||||
|
_hidePlayControl = true; // 延迟500ms(透明度动画结束)后,隐藏
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startPlayControlTimer() {
|
||||||
|
/// 计时器,用法和前端js的大同小异
|
||||||
|
if (_timer != null) _timer.cancel();
|
||||||
|
_timer = Timer(Duration(seconds: 3), () {
|
||||||
|
/// 延迟3s后隐藏
|
||||||
|
setState(() {
|
||||||
|
_playControlOpacity = 0;
|
||||||
|
Future.delayed(Duration(milliseconds: 500)).whenComplete(() {
|
||||||
|
_hidePlayControl = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleFullScreen() {
|
||||||
|
setState(() {
|
||||||
|
if (_isFullScreen) {
|
||||||
|
/// 如果是全屏就切换竖屏
|
||||||
|
AutoOrientation.portraitAutoMode();
|
||||||
|
|
||||||
|
///显示状态栏,与底部虚拟操作按钮
|
||||||
|
SystemChrome.setEnabledSystemUIMode(
|
||||||
|
SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
|
||||||
|
} else {
|
||||||
|
AutoOrientation.landscapeAutoMode();
|
||||||
|
|
||||||
|
///关闭状态栏,与底部虚拟操作按钮
|
||||||
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
|
||||||
|
}
|
||||||
|
_startPlayControlTimer(); // 操作完控件开始计时隐藏
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,246 @@
|
|||||||
|
import 'package:common_utils/common_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
//import 'package:screen/screen.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
import '../after_layout.dart';
|
||||||
|
import 'controller_widget.dart';
|
||||||
|
import 'video_player_control.dart';
|
||||||
|
|
||||||
|
class VideoPlayerPan extends StatefulWidget {
|
||||||
|
VideoPlayerPan({
|
||||||
|
// this.controlKey,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
// final GlobalKey<VideoPlayerControlState> controlKey;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_VideoPlayerPanState createState() => _VideoPlayerPanState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoPlayerPanState extends State<VideoPlayerPan>
|
||||||
|
with AfterLayoutMixin<VideoPlayerPan> {
|
||||||
|
late Offset startPosition; // 起始位置
|
||||||
|
late double movePan; // 偏移量累计总和
|
||||||
|
late double layoutWidth; // 组件宽度
|
||||||
|
late double layoutHeight; // 组件高度
|
||||||
|
String volumePercentage = ''; // 组件位移描述
|
||||||
|
double playDialogOpacity = 0.0;
|
||||||
|
bool allowHorizontal = false; // 是否允许快进
|
||||||
|
Duration position = Duration(seconds: 0); // 当前时间
|
||||||
|
double brightness = 0.0; //亮度
|
||||||
|
bool brightnessOk = false; // 是否允许调节亮度
|
||||||
|
|
||||||
|
VideoPlayerController get controller => ControllerWidget.of(context)!.controller;
|
||||||
|
bool get videoInit => ControllerWidget.of(context)!.videoInit;
|
||||||
|
String get title=>ControllerWidget.of(context)!.title;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void afterFirstLayout(BuildContext context) {
|
||||||
|
_reset(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
brightnessOk = false;
|
||||||
|
allowHorizontal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onVerticalDragStart: _onVerticalDragStart,
|
||||||
|
onVerticalDragUpdate: _onVerticalDragUpdate,
|
||||||
|
onVerticalDragEnd: _onVerticalDragEnd,
|
||||||
|
onHorizontalDragStart: _onHorizontalDragStart,
|
||||||
|
onHorizontalDragUpdate: _onHorizontalDragUpdate,
|
||||||
|
onHorizontalDragEnd: _onHorizontalDragEnd,
|
||||||
|
child: Container(
|
||||||
|
child: Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
widget.child,
|
||||||
|
Center(
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
opacity: playDialogOpacity,
|
||||||
|
duration: Duration(milliseconds: 500),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 6.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black87,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(5.0))),
|
||||||
|
child: Text(
|
||||||
|
volumePercentage,
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
VideoPlayerControl(
|
||||||
|
key: ControllerWidget.of(context)!.controlKey,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onVerticalDragStart(details) async {
|
||||||
|
_reset(context);
|
||||||
|
startPosition = details.globalPosition;
|
||||||
|
if (startPosition.dx < (layoutWidth / 2)) {
|
||||||
|
/// 左边触摸
|
||||||
|
// brightness = await Screen.brightness;
|
||||||
|
brightnessOk = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onVerticalDragUpdate(details) {
|
||||||
|
if (!videoInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 累计计算偏移量(下滑减少百分比,上滑增加百分比)
|
||||||
|
movePan += (-details.delta.dy);
|
||||||
|
if (startPosition.dx < (layoutWidth / 2)) {
|
||||||
|
/// 左边触摸
|
||||||
|
if (brightnessOk = true) {
|
||||||
|
setState(() {
|
||||||
|
volumePercentage = '亮度:${(_setBrightnessValue() * 100).toInt()}%';
|
||||||
|
playDialogOpacity = 1.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/// 右边触摸
|
||||||
|
setState(() {
|
||||||
|
volumePercentage = '音量:${(_setVerticalValue(num: 2) * 100).toInt()}%';
|
||||||
|
playDialogOpacity = 1.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onVerticalDragEnd(_) async {
|
||||||
|
if (!videoInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (startPosition.dx < (layoutWidth / 2)) {
|
||||||
|
if (brightnessOk) {
|
||||||
|
// await Screen.setBrightness(_setBrightnessValue());
|
||||||
|
brightnessOk = false;
|
||||||
|
// 左边触摸
|
||||||
|
setState(() {
|
||||||
|
playDialogOpacity = 0.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 右边触摸
|
||||||
|
await controller.setVolume(_setVerticalValue());
|
||||||
|
setState(() {
|
||||||
|
playDialogOpacity = 0.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double _setBrightnessValue() {
|
||||||
|
// 亮度百分控制
|
||||||
|
double value =
|
||||||
|
double.parse((movePan / layoutHeight + brightness).toStringAsFixed(2));
|
||||||
|
if (value >= 1.00) {
|
||||||
|
value = 1.00;
|
||||||
|
} else if (value <= 0.00) {
|
||||||
|
value = 0.00;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _setVerticalValue({int num = 1}) {
|
||||||
|
// 声音亮度百分控制
|
||||||
|
double value = double.parse(
|
||||||
|
(movePan / layoutHeight + controller.value.volume)
|
||||||
|
.toStringAsFixed(num));
|
||||||
|
if (value >= 1.0) {
|
||||||
|
value = 1.0;
|
||||||
|
} else if (value <= 0.0) {
|
||||||
|
value = 0.0;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _reset(BuildContext context) {
|
||||||
|
startPosition = Offset(0, 0);
|
||||||
|
movePan = 0;
|
||||||
|
layoutHeight = context.size!.height;
|
||||||
|
layoutWidth = context.size!.width;
|
||||||
|
volumePercentage = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onHorizontalDragStart(DragStartDetails details) async {
|
||||||
|
_reset(context);
|
||||||
|
if (!videoInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取当前时间
|
||||||
|
position = controller.value.position;
|
||||||
|
// 暂停成功后才允许快进手势
|
||||||
|
allowHorizontal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onHorizontalDragUpdate(DragUpdateDetails details) {
|
||||||
|
if (!videoInit && !allowHorizontal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 累计计算偏移量
|
||||||
|
movePan += details.delta.dx;
|
||||||
|
double value = _setHorizontalValue();
|
||||||
|
// 用百分比计算出当前的秒数
|
||||||
|
String currentSecond = DateUtil.formatDateMs(
|
||||||
|
(value * controller.value.duration.inMilliseconds).toInt(),
|
||||||
|
format: 'mm:ss',
|
||||||
|
);
|
||||||
|
if (value >= 0) {
|
||||||
|
setState(() {
|
||||||
|
volumePercentage = '快进至:$currentSecond';
|
||||||
|
playDialogOpacity = 1.0;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
volumePercentage = '快退至:${(value * 100).toInt()}%';
|
||||||
|
playDialogOpacity = 1.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onHorizontalDragEnd(DragEndDetails details) async {
|
||||||
|
if (!videoInit && !allowHorizontal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double value = _setHorizontalValue();
|
||||||
|
int current =
|
||||||
|
(value * controller.value.duration.inMilliseconds).toInt();
|
||||||
|
await controller.seekTo(Duration(milliseconds: current));
|
||||||
|
allowHorizontal = false;
|
||||||
|
setState(() {
|
||||||
|
playDialogOpacity = 0.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
double _setHorizontalValue() {
|
||||||
|
// 进度条百分控制
|
||||||
|
double valueHorizontal =
|
||||||
|
double.parse((movePan / layoutWidth).toStringAsFixed(2));
|
||||||
|
// 当前进度条百分比
|
||||||
|
double currentValue = position.inMilliseconds /
|
||||||
|
controller.value.duration.inMilliseconds;
|
||||||
|
double value =
|
||||||
|
double.parse((currentValue + valueHorizontal).toStringAsFixed(2));
|
||||||
|
if (value >= 1.00) {
|
||||||
|
value = 1.00;
|
||||||
|
} else if (value <= 0.00) {
|
||||||
|
value = 0.00;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:common_utils/common_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
import 'controller_widget.dart';
|
||||||
|
|
||||||
|
class VideoPlayerSlider extends StatefulWidget {
|
||||||
|
final Function startPlayControlTimer;
|
||||||
|
final Timer timer;
|
||||||
|
|
||||||
|
VideoPlayerSlider({required this.startPlayControlTimer, required this.timer});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_VideoPlayerSliderState createState() => _VideoPlayerSliderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoPlayerSliderState extends State<VideoPlayerSlider> {
|
||||||
|
VideoPlayerController get controller =>
|
||||||
|
ControllerWidget.of(context)!.controller;
|
||||||
|
|
||||||
|
bool get videoInit => ControllerWidget.of(context)!.videoInit;
|
||||||
|
late double progressValue; //进度
|
||||||
|
late String labelProgress; //tip内容
|
||||||
|
bool handle = false; //判断是否在滑动的标识
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
progressValue = 0.0;
|
||||||
|
labelProgress = '00:00';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(VideoPlayerSlider oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (!handle && videoInit) {
|
||||||
|
int position = controller.value.position.inMilliseconds;
|
||||||
|
int duration = controller.value.duration.inMilliseconds;
|
||||||
|
if(position>=duration){
|
||||||
|
position=duration;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
progressValue = position / duration * 100;
|
||||||
|
labelProgress = DateUtil.formatDateMs(
|
||||||
|
progressValue.toInt(),
|
||||||
|
format: 'mm:ss',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliderTheme(
|
||||||
|
//自定义风格
|
||||||
|
data: SliderTheme.of(context).copyWith(
|
||||||
|
//进度条滑块左边颜色
|
||||||
|
inactiveTrackColor: Colors.white,
|
||||||
|
overlayShape: RoundSliderOverlayShape(
|
||||||
|
//可继承SliderComponentShape自定义形状
|
||||||
|
overlayRadius: 10, //滑块外圈大小
|
||||||
|
),
|
||||||
|
thumbShape: RoundSliderThumbShape(
|
||||||
|
//可继承SliderComponentShape自定义形状
|
||||||
|
disabledThumbRadius: 7, //禁用是滑块大小
|
||||||
|
enabledThumbRadius: 7, //滑块大小
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Slider(
|
||||||
|
value: progressValue,
|
||||||
|
label: labelProgress,
|
||||||
|
divisions: 100,
|
||||||
|
onChangeStart: _onChangeStart,
|
||||||
|
onChangeEnd: _onChangeEnd,
|
||||||
|
onChanged: _onChanged,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChangeEnd(_) {
|
||||||
|
if (!videoInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
widget.startPlayControlTimer();
|
||||||
|
// 关闭手动操作标识
|
||||||
|
handle = false;
|
||||||
|
// 跳转到滑动时间
|
||||||
|
int duration = controller.value.duration.inMilliseconds;
|
||||||
|
controller.seekTo(
|
||||||
|
Duration(milliseconds: (progressValue / 100 * duration).toInt()),
|
||||||
|
);
|
||||||
|
// if (!controller.value.isPlaying) {
|
||||||
|
// controller.play();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChangeStart(_) {
|
||||||
|
if (!videoInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (widget.timer != null) {
|
||||||
|
widget.timer.cancel();
|
||||||
|
}
|
||||||
|
// 开始手动操作标识
|
||||||
|
handle = true;
|
||||||
|
// if (controller.value.isPlaying) {
|
||||||
|
// controller.pause();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChanged(double value) {
|
||||||
|
if (!videoInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (widget.timer != null) {
|
||||||
|
widget.timer.cancel();
|
||||||
|
}
|
||||||
|
int duration = controller.value.duration.inMilliseconds;
|
||||||
|
setState(() {
|
||||||
|
progressValue = value;
|
||||||
|
labelProgress = DateUtil.formatDateMs(
|
||||||
|
(value / 100 * duration).toInt(),
|
||||||
|
format: 'mm:ss',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'editVideoLog_state.dart';
|
||||||
|
|
||||||
|
class EditVideoLogLogic extends BaseGetXController{
|
||||||
|
EditVideoLogState state = EditVideoLogState();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../../app_settings/app_colors.dart';
|
||||||
|
import '../../../../tools/titleAppBar.dart';
|
||||||
|
import 'editVideoLog_logic.dart';
|
||||||
|
|
||||||
|
class EditVideoLogPage extends StatefulWidget {
|
||||||
|
const EditVideoLogPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EditVideoLogPage> createState() => _EditVideoLogPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EditVideoLogPageState extends State<EditVideoLogPage> {
|
||||||
|
final logic = Get.put(EditVideoLogLogic());
|
||||||
|
final state = Get.find<EditVideoLogLogic>().state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: TitleAppBar(
|
||||||
|
barTitle: "已选${state.seletVideoLog.value}项",
|
||||||
|
haveBack: true,
|
||||||
|
backgroundColor: AppColors.mainColor,
|
||||||
|
actionsList: [
|
||||||
|
TextButton(
|
||||||
|
child: Text(
|
||||||
|
"全选",
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 24.sp),
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
state.isSeletAll.value = !state.isSeletAll.value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: 5,
|
||||||
|
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(index)
|
||||||
|
],);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
bottomBottomBtnWidget()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemW = (1.sw - 15.w*4)/3;
|
||||||
|
var itemH = (1.sw - 15.w*4)/3+40.h;
|
||||||
|
Widget mainListView(int index){
|
||||||
|
return Container(
|
||||||
|
// margin: EdgeInsets.only(left: 10.w, right: 10.w, top: 40.h),
|
||||||
|
// color: Colors.blue,
|
||||||
|
child: GridView.builder(
|
||||||
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
|
itemCount: index+1,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
//横轴元素个数
|
||||||
|
crossAxisCount: 3,
|
||||||
|
//纵轴间距
|
||||||
|
mainAxisSpacing: 10.w,
|
||||||
|
// 横轴间距
|
||||||
|
crossAxisSpacing: 15.w,
|
||||||
|
//子组件宽高长度比例
|
||||||
|
childAspectRatio: itemW/itemH
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Obx(() => videoItem());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget videoItem(){
|
||||||
|
return SizedBox(
|
||||||
|
width: itemW,
|
||||||
|
height: itemH,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
|
child: Image(width: itemW, height: itemW, fit: BoxFit.fill, image: const AssetImage("images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
||||||
|
),
|
||||||
|
SizedBox(height:5.h),
|
||||||
|
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: true,
|
||||||
|
child: Positioned(
|
||||||
|
top: 0.w,
|
||||||
|
right: 0.w,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: (){
|
||||||
|
|
||||||
|
},
|
||||||
|
child: Image(width: 40.w, height: 40.w, image: state.isSeletAll.value ? const AssetImage("images/icon_round_selet.png") : const AssetImage("images/icon_round_unSelet.png"))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomBottomBtnWidget(){
|
||||||
|
return Container(
|
||||||
|
width: 1.sw,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringDownloadVideo.png", "下载", Colors.white,(){
|
||||||
|
|
||||||
|
}),
|
||||||
|
SizedBox(width:100.w),
|
||||||
|
bottomBtnItemWidget("images/main/icon_lockDetail_monitoringDeletVideo.png", "删除", AppColors.mainColor,(){
|
||||||
|
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget bottomBtnItemWidget(String iconUrl, String name, Color backgroundColor, Function() onClick) {
|
||||||
|
var wh = 40.w;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onClick,
|
||||||
|
child: Container(
|
||||||
|
height: 140.h,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 30.w),
|
||||||
|
Image.asset(iconUrl, width: wh, height: wh, fit: BoxFit.fitWidth),
|
||||||
|
SizedBox(height: 10.w),
|
||||||
|
Expanded(child: Text(name, style: TextStyle(fontSize: 22.sp), textAlign: TextAlign.center))
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class EditVideoLogState{
|
||||||
|
|
||||||
|
var seletVideoLog = 0.obs;
|
||||||
|
var isSeletAll = false.obs;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'videoLog_state.dart';
|
||||||
|
|
||||||
|
class VideoLogLogic extends BaseGetXController{
|
||||||
|
VideoLogState state = VideoLogState();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,262 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:star_lock/appRouters.dart';
|
||||||
|
import 'package:star_lock/tools/noData.dart';
|
||||||
|
|
||||||
|
import '../../../../app_settings/app_colors.dart';
|
||||||
|
import '../../../../tools/titleAppBar.dart';
|
||||||
|
import 'videoLog_logic.dart';
|
||||||
|
|
||||||
|
class VideoLogPage extends StatefulWidget {
|
||||||
|
const VideoLogPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<VideoLogPage> createState() => _VideoLogPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoLogPageState extends State<VideoLogPage> {
|
||||||
|
final logic = Get.put(VideoLogLogic());
|
||||||
|
final state = Get.find<VideoLogLogic>().state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: TitleAppBar(
|
||||||
|
haveTitleWidget: true,
|
||||||
|
titleWidget: navBtn(),
|
||||||
|
haveBack: true,
|
||||||
|
backgroundColor: AppColors.mainColor,
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
// 云存顶部
|
||||||
|
Visibility(
|
||||||
|
visible: !state.isNavLocal.value,
|
||||||
|
child: vipTip()
|
||||||
|
),
|
||||||
|
// 本地顶部
|
||||||
|
Visibility(
|
||||||
|
visible: state.isNavLocal.value,
|
||||||
|
child: localTip()
|
||||||
|
),
|
||||||
|
// title加编辑按钮
|
||||||
|
editVideoTip(),
|
||||||
|
Visibility(
|
||||||
|
visible: !state.isNavLocal.value,
|
||||||
|
child: Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: 5,
|
||||||
|
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.2$index", style: TextStyle(fontSize: 20.sp)),
|
||||||
|
]
|
||||||
|
)),
|
||||||
|
mainListView(index)
|
||||||
|
],);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// 本地顶部
|
||||||
|
Visibility(
|
||||||
|
visible: state.isNavLocal.value,
|
||||||
|
child: Expanded(
|
||||||
|
child: state.localList.isNotEmpty ? ListView.builder(
|
||||||
|
itemCount: 5,
|
||||||
|
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.2$index", style: TextStyle(fontSize: 20.sp)),
|
||||||
|
]
|
||||||
|
)),
|
||||||
|
mainListView(index)
|
||||||
|
],);
|
||||||
|
}): const NoData()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nav按钮
|
||||||
|
Widget navBtn(){
|
||||||
|
return SizedBox(
|
||||||
|
width: 300.w,
|
||||||
|
// color: Colors.white,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: (){
|
||||||
|
setState(() {
|
||||||
|
state.isNavLocal.value = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Obx(() => Text("云存", style: state.isNavLocal.value == true ? TextStyle(color: Colors.grey, fontSize: 26.sp) : TextStyle(color: Colors.white, fontSize: 28.sp)))
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: (){
|
||||||
|
setState(() {
|
||||||
|
state.isNavLocal.value = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Obx(() => Text("本地", style: state.isNavLocal.value == true ? TextStyle(color: Colors.white, fontSize: 28.sp) : TextStyle(color: Colors.grey, fontSize: 26.sp)))
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 云存顶部视频
|
||||||
|
Widget vipTip(){
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: (){
|
||||||
|
Get.toNamed(Routers.valueAddedServicesHighFunctionPage);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 150.h,
|
||||||
|
margin: EdgeInsets.all(15.w),
|
||||||
|
padding: EdgeInsets.only(left:20.w, top:20.w, bottom:20.w, right: 10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF6F7F8),
|
||||||
|
borderRadius: BorderRadius.circular(20.h)
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("3天滚动储存", style: TextStyle(fontSize: 26.sp)),
|
||||||
|
SizedBox(height: 10.h),
|
||||||
|
Text("星锁已为本设备免费提供3大滚动视频储存服务", style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
SizedBox(width: 15.w),
|
||||||
|
Text("去升级", style: TextStyle(fontSize: 24.sp)),
|
||||||
|
Image(width: 40.w, height: 24.w, image: const AssetImage("images/icon_right_black.png"))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地顶部
|
||||||
|
Widget localTip(){
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: (){
|
||||||
|
Get.toNamed(Routers.videoLogDownLoadPage);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
// height: 130.h,
|
||||||
|
margin: EdgeInsets.all(15.w),
|
||||||
|
padding: EdgeInsets.only(left:20.w, top:30.w, bottom:30.w, right: 10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF6F7F8),
|
||||||
|
borderRadius: BorderRadius.circular(20.h)
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// SizedBox(height: 20.h),
|
||||||
|
Text("下载列表", style: TextStyle(fontSize: 26.sp)),
|
||||||
|
SizedBox(height: 15.h),
|
||||||
|
Text("暂无下载内容", style: TextStyle(fontSize: 22.sp, color: Colors.grey)),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
SizedBox(width: 15.w),
|
||||||
|
// Text("去升级", style: TextStyle(fontSize: 24.sp)),
|
||||||
|
Image(width: 40.w, height: 24.w, image: const AssetImage("images/icon_right_black.png"))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题加编辑按钮
|
||||||
|
Widget editVideoTip(){
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.only(left:20.w),
|
||||||
|
child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(state.isNavLocal.value == true ? "已下载":"全部视频", style: TextStyle(fontSize: 28.sp)),
|
||||||
|
Expanded(child: SizedBox(width: 10.w)),
|
||||||
|
IconButton(
|
||||||
|
icon: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringEditVoice.png")),
|
||||||
|
iconSize: 30,
|
||||||
|
color: Colors.black54, onPressed: () {
|
||||||
|
Get.toNamed(Routers.editVideoLogPage);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// TextButton(
|
||||||
|
// onPressed: (){
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringEditVoice.png"),)
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemW = (1.sw - 15.w*4)/3;
|
||||||
|
var itemH = (1.sw - 15.w*4)/3+40.h;
|
||||||
|
|
||||||
|
// 云存列表
|
||||||
|
Widget mainListView(int index){
|
||||||
|
return GridView.builder(
|
||||||
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
|
itemCount: index+1,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
//横轴元素个数
|
||||||
|
crossAxisCount: 3,
|
||||||
|
//纵轴间距
|
||||||
|
mainAxisSpacing: 15.w,
|
||||||
|
// 横轴间距
|
||||||
|
crossAxisSpacing: 15.w,
|
||||||
|
//子组件宽高长度比例
|
||||||
|
childAspectRatio: itemW/itemH
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return videoItem((){
|
||||||
|
Get.toNamed(Routers.videoLogDetailPage);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget videoItem(Function() action){
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: action,
|
||||||
|
child: SizedBox(
|
||||||
|
width: itemW,
|
||||||
|
height: itemH,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
|
child: Image(width: itemW, height: itemW, fit: BoxFit.fill, image: const AssetImage("images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
||||||
|
),
|
||||||
|
SizedBox(height:5.h),
|
||||||
|
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class VideoLogState{
|
||||||
|
|
||||||
|
var isNavLocal = false.obs;
|
||||||
|
var localList = [];
|
||||||
|
}
|
||||||
@ -0,0 +1,264 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
class ControlsOverlay extends StatelessWidget {
|
||||||
|
const ControlsOverlay({required this.controller});
|
||||||
|
|
||||||
|
static const List<Duration> _exampleCaptionOffsets = <Duration>[
|
||||||
|
Duration(seconds: -10),
|
||||||
|
Duration(seconds: -3),
|
||||||
|
Duration(seconds: -1, milliseconds: -500),
|
||||||
|
Duration(milliseconds: -250),
|
||||||
|
Duration.zero,
|
||||||
|
Duration(milliseconds: 250),
|
||||||
|
Duration(seconds: 1, milliseconds: 500),
|
||||||
|
Duration(seconds: 3),
|
||||||
|
Duration(seconds: 10),
|
||||||
|
];
|
||||||
|
static const List<double> _examplePlaybackRates = <double>[
|
||||||
|
0.25,
|
||||||
|
0.5,
|
||||||
|
1.0,
|
||||||
|
1.5,
|
||||||
|
2.0,
|
||||||
|
3.0,
|
||||||
|
5.0,
|
||||||
|
10.0,
|
||||||
|
];
|
||||||
|
|
||||||
|
final VideoPlayerController controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 50),
|
||||||
|
reverseDuration: const Duration(milliseconds: 200),
|
||||||
|
child: controller.value.isPlaying
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: Container(
|
||||||
|
color: Colors.black26,
|
||||||
|
child: const Center(
|
||||||
|
child:
|
||||||
|
// CircularProgressIndicator()
|
||||||
|
Icon(
|
||||||
|
Icons.play_arrow,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 60.0,
|
||||||
|
semanticLabel: 'Play',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
controller.value.isPlaying ? controller.pause() : controller.play();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// Align(
|
||||||
|
// alignment: Alignment.topLeft,
|
||||||
|
// child: PopupMenuButton<Duration>(
|
||||||
|
// initialValue: controller.value.captionOffset,
|
||||||
|
// tooltip: 'Caption Offset',
|
||||||
|
// onSelected: (Duration delay) {
|
||||||
|
// controller.setCaptionOffset(delay);
|
||||||
|
// },
|
||||||
|
// itemBuilder: (BuildContext context) {
|
||||||
|
// return <PopupMenuItem<Duration>>[
|
||||||
|
// for (final Duration offsetDuration in _exampleCaptionOffsets)
|
||||||
|
// PopupMenuItem<Duration>(
|
||||||
|
// value: offsetDuration,
|
||||||
|
// child: Text('${offsetDuration.inMilliseconds}ms'),
|
||||||
|
// )
|
||||||
|
// ];
|
||||||
|
// },
|
||||||
|
// child: Padding(
|
||||||
|
// padding: const EdgeInsets.symmetric(
|
||||||
|
// // Using less vertical padding as the text is also longer
|
||||||
|
// // horizontally, so it feels like it would need more spacing
|
||||||
|
// // horizontally (matching the aspect ratio of the video).
|
||||||
|
// vertical: 12,
|
||||||
|
// horizontal: 16,
|
||||||
|
// ),
|
||||||
|
// child: Text('${controller.value.captionOffset.inMilliseconds}ms'),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Align(
|
||||||
|
// alignment: Alignment.topRight,
|
||||||
|
// child: PopupMenuButton<double>(
|
||||||
|
// initialValue: controller.value.playbackSpeed,
|
||||||
|
// tooltip: 'Playback speed',
|
||||||
|
// onSelected: (double speed) {
|
||||||
|
// controller.setPlaybackSpeed(speed);
|
||||||
|
// },
|
||||||
|
// itemBuilder: (BuildContext context) {
|
||||||
|
// return <PopupMenuItem<double>>[
|
||||||
|
// for (final double speed in _examplePlaybackRates)
|
||||||
|
// PopupMenuItem<double>(
|
||||||
|
// value: speed,
|
||||||
|
// child: Text('${speed}x'),
|
||||||
|
// )
|
||||||
|
// ];
|
||||||
|
// },
|
||||||
|
// child: Padding(
|
||||||
|
// padding: const EdgeInsets.symmetric(
|
||||||
|
// // Using less vertical padding as the text is also longer
|
||||||
|
// // horizontally, so it feels like it would need more spacing
|
||||||
|
// // horizontally (matching the aspect ratio of the video).
|
||||||
|
// vertical: 12,
|
||||||
|
// horizontal: 16,
|
||||||
|
// ),
|
||||||
|
// child: Text('${controller.value.playbackSpeed}x'),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
Positioned(
|
||||||
|
top: 0.h,
|
||||||
|
left: 0.h,
|
||||||
|
right: 0.h,
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(left:20.w, right:20.w),
|
||||||
|
// color: const Color(0xC83C3F41),
|
||||||
|
child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text("星锁 2023/10/23", style: TextStyle(color: Colors.white, fontSize: 20.sp)),
|
||||||
|
Expanded(child: SizedBox(width: 10.w)),
|
||||||
|
Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
child: Image(width: 50.w, height: 50.w, image: const AssetImage("images/main/icon_lockDetail_monitoringShareVideo_white.png")),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20.w),
|
||||||
|
Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
child: Image(width: 50.w, height: 50.w, image: const AssetImage("images/main/icon_lockDetail_monitoringDownloadVideo_white.png")),
|
||||||
|
),
|
||||||
|
SizedBox(width: 20.w),
|
||||||
|
Container(
|
||||||
|
width: 50.w,
|
||||||
|
height: 50.w,
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
child: Image(width: 50.w, height: 50.w, image: const AssetImage("images/main/icon_lockDetail_monitoringDeletVideo_white.png")),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(right: 10.w, left: 10.w),
|
||||||
|
color: const Color.fromRGBO(0, 0, 0, 0.5),
|
||||||
|
height: 60.h,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
//暂停按钮
|
||||||
|
InkWell(
|
||||||
|
child: controller.value.isPlaying ? const Icon(Icons.pause, size: 30, color: Color(0xffefefef)) : const Icon(Icons.play_arrow, size: 30, color: Color(0xffefefef)),
|
||||||
|
onTap: () {
|
||||||
|
// if(controller.value.isBuffering == false){
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
controller.value.isPlaying ? controller.pause() : controller.play();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
//当前播放进度
|
||||||
|
Text(formatString(controller.value.position), style: TextStyle(fontSize: 22.sp, color: const Color(0xffefefef)),),
|
||||||
|
//进度条
|
||||||
|
Expanded(
|
||||||
|
|
||||||
|
child: Slider(activeColor: const Color(0xFFFFFFFF), max: controller.value.duration.inMilliseconds.truncateToDouble(),
|
||||||
|
value: controller.value.position.inMilliseconds.truncateToDouble(),
|
||||||
|
onChanged: (newRating) {
|
||||||
|
controller
|
||||||
|
.seekTo(Duration(
|
||||||
|
milliseconds:
|
||||||
|
newRating
|
||||||
|
.truncate()));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
//总视频进度
|
||||||
|
Text(formatString(controller.value.duration), style: TextStyle(fontSize: 22.sp, color: const Color(0xffefefef)),),
|
||||||
|
//倍速下拉菜单
|
||||||
|
// DropdownButtonHideUnderline(
|
||||||
|
// child: DropdownButton2(
|
||||||
|
// hint: Text(
|
||||||
|
// _selectedValue,
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 18,
|
||||||
|
// color:
|
||||||
|
// Color(0xffefefef),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// items: items
|
||||||
|
// .map((item) =>
|
||||||
|
// DropdownMenuItem<
|
||||||
|
// String>(
|
||||||
|
// value: item,
|
||||||
|
// child: Text(
|
||||||
|
// '${item}x',
|
||||||
|
// style:
|
||||||
|
// const TextStyle(
|
||||||
|
// fontSize:
|
||||||
|
// 16,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ))
|
||||||
|
// .toList(),
|
||||||
|
// // value: _selectedValue,
|
||||||
|
// // icon: Visibility(
|
||||||
|
// // visible: false,
|
||||||
|
// // child: Icon(Icons
|
||||||
|
// // .arrow_downward)),
|
||||||
|
// onChanged: (value) async {
|
||||||
|
// double val =
|
||||||
|
// double.parse(value
|
||||||
|
// as String);
|
||||||
|
// _videoPlayerController
|
||||||
|
// .setPlaybackSpeed(val);
|
||||||
|
// setState(() {
|
||||||
|
// if (val == 1.0) {
|
||||||
|
// _selectedValue =
|
||||||
|
// '倍速';
|
||||||
|
// } else {
|
||||||
|
// _selectedValue =
|
||||||
|
// '${value as String}x';
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// // dropdownWidth: 100,
|
||||||
|
// // buttonWidth: 60,
|
||||||
|
// // iconSize: 36,
|
||||||
|
// // iconEnabledColor:Colors.white,
|
||||||
|
// // buttonPadding:const EdgeInsets.only(left: 10),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatString(time) {
|
||||||
|
var shortName = time.toString().substring(2, 7);
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
|
||||||
|
import 'videoLogDetail_state.dart';
|
||||||
|
|
||||||
|
class VideoLogDetailLogic extends BaseGetXController{
|
||||||
|
VideoLogDetailState state = VideoLogDetailState();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../../app_settings/app_colors.dart';
|
||||||
|
import '../../../../tools/titleAppBar.dart';
|
||||||
|
import 'controlsOverlay_page.dart';
|
||||||
|
import 'videoLogDetail_logic.dart';
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
|
class VideoLogDetailPage extends StatefulWidget {
|
||||||
|
const VideoLogDetailPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<VideoLogDetailPage> createState() => _VideoLogDetailPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoLogDetailPageState extends State<VideoLogDetailPage> {
|
||||||
|
final logic = Get.put(VideoLogDetailLogic());
|
||||||
|
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
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = VideoPlayerController.networkUrl(
|
||||||
|
Uri.parse('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'),
|
||||||
|
// closedCaptionFile: _loadCaptions(),
|
||||||
|
// videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
|
||||||
|
);
|
||||||
|
|
||||||
|
_controller.addListener(() {
|
||||||
|
setState(() {
|
||||||
|
print("controller.value.isBuffering:${_controller.value.isBuffering}");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
_controller.setLooping(false);
|
||||||
|
// _controller.setVolume(1);
|
||||||
|
_controller.initialize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: TitleAppBar(
|
||||||
|
barTitle: "本地视频播放",
|
||||||
|
haveBack: true,
|
||||||
|
backgroundColor: AppColors.mainColor,
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
AspectRatio(
|
||||||
|
aspectRatio: 16/9,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
children: <Widget>[
|
||||||
|
VideoPlayer(_controller),
|
||||||
|
// ClosedCaption(text: _controller.value.caption.text),
|
||||||
|
ControlsOverlay(controller: _controller),
|
||||||
|
(_controller.value.isPlaying || _controller.value.isBuffering) ? Container() : VideoProgressIndicator(_controller, colors:VideoProgressColors(playedColor:AppColors.mainColor), allowScrubbing: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(left:20.w, top: 15.w),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text("2023.10.23", style: TextStyle(fontSize: 20.sp)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 15.h),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
videoItem(true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: 4,
|
||||||
|
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 itemH = (1.sw - 15.w*4)/3+40.h;
|
||||||
|
Widget mainListView(){
|
||||||
|
return GridView.builder(
|
||||||
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
|
itemCount: 4,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
//横轴元素个数
|
||||||
|
crossAxisCount: 3,
|
||||||
|
//纵轴间距
|
||||||
|
mainAxisSpacing: 10.w,
|
||||||
|
// 横轴间距
|
||||||
|
crossAxisSpacing: 15.w,
|
||||||
|
//子组件宽高长度比例
|
||||||
|
childAspectRatio: itemW/itemH
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return videoItem(false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget videoItem(bool isPlay){
|
||||||
|
return SizedBox(
|
||||||
|
width: itemW,
|
||||||
|
height: itemH,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Image(width: itemW, height: itemW, fit: BoxFit.fill, image: const AssetImage("images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
||||||
|
Positioned(
|
||||||
|
left: 8.w,
|
||||||
|
bottom: 5.h,
|
||||||
|
child: Text("00:06", style: TextStyle(color: Colors.white, 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),
|
||||||
|
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_controller.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class VideoLogDetailState{
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'videoLogDownLoad_state.dart';
|
||||||
|
|
||||||
|
class VideoLogDownLoadLogic extends BaseGetXController{
|
||||||
|
VideoLogDownLoadState state = VideoLogDownLoadState();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../../../app_settings/app_colors.dart';
|
||||||
|
import '../../../../tools/noData.dart';
|
||||||
|
import '../../../../tools/titleAppBar.dart';
|
||||||
|
import 'videoLogDownLoad_logic.dart';
|
||||||
|
|
||||||
|
class VideoLogDownLoadPage extends StatefulWidget {
|
||||||
|
const VideoLogDownLoadPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<VideoLogDownLoadPage> createState() => _VideoLogDownLoadPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoLogDownLoadPageState extends State<VideoLogDownLoadPage> {
|
||||||
|
final logic = Get.put(VideoLogDownLoadLogic());
|
||||||
|
final state = Get.find<VideoLogDownLoadLogic>().state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: TitleAppBar(
|
||||||
|
barTitle: "下载列表",
|
||||||
|
haveBack: true,
|
||||||
|
backgroundColor: AppColors.mainColor,
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: state.localList.isNotEmpty ? ListView.builder(
|
||||||
|
itemCount: 5,
|
||||||
|
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(index)
|
||||||
|
],);
|
||||||
|
}): const NoData(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemW = (1.sw - 15.w*4)/3;
|
||||||
|
var itemH = (1.sw - 15.w*4)/3+40.h;
|
||||||
|
Widget mainListView(int index){
|
||||||
|
return Container(
|
||||||
|
// margin: EdgeInsets.only(left: 10.w, right: 10.w, top: 40.h),
|
||||||
|
// color: Colors.blue,
|
||||||
|
child: GridView.builder(
|
||||||
|
padding: EdgeInsets.only(left: 15.w, right: 15.w),
|
||||||
|
itemCount: index+1,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
//横轴元素个数
|
||||||
|
crossAxisCount: 3,
|
||||||
|
//纵轴间距
|
||||||
|
mainAxisSpacing: 10.w,
|
||||||
|
// 横轴间距
|
||||||
|
crossAxisSpacing: 15.w,
|
||||||
|
//子组件宽高长度比例
|
||||||
|
childAspectRatio: itemW/itemH
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return videoItem();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget videoItem(){
|
||||||
|
return SizedBox(
|
||||||
|
width: itemW,
|
||||||
|
height: itemH,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
|
child: Image(width: itemW, height: itemW, fit: BoxFit.fill, image: const AssetImage("images/main/icon_lockDetail_monitoringvoiceFrist.png")),
|
||||||
|
),
|
||||||
|
SizedBox(height:5.h),
|
||||||
|
Text("2023.10.23 10:00", style: TextStyle(fontSize: 20.sp))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class VideoLogDownLoadState{
|
||||||
|
var localList = [];
|
||||||
|
}
|
||||||
@ -323,6 +323,15 @@ class _DemoModeLockDetailPageState extends State<DemoModeLockDetailPage> {
|
|||||||
Get.toNamed(Routers.lockOperatingRecordPage,
|
Get.toNamed(Routers.lockOperatingRecordPage,
|
||||||
arguments: {"keyInfo": LockListInfoItemEntity()});
|
arguments: {"keyInfo": LockListInfoItemEntity()});
|
||||||
}),
|
}),
|
||||||
|
// 视频日志
|
||||||
|
bottomItem('images/main/icon_lockDetail_videoLog.png', "视频日志", () {
|
||||||
|
//视频日志
|
||||||
|
Get.toNamed(Routers.videoLogPage);
|
||||||
|
}),
|
||||||
|
// 消息提醒
|
||||||
|
bottomItem('images/main/icon_lockDetail_messageReminding.png', "消息提醒", () {
|
||||||
|
Get.toNamed(Routers.msgNotificationPage);
|
||||||
|
}),
|
||||||
// 设置
|
// 设置
|
||||||
bottomItem(
|
bottomItem(
|
||||||
'images/main/icon_main_set.png', TranslationLoader.lanKeys!.set!.tr,
|
'images/main/icon_main_set.png', TranslationLoader.lanKeys!.set!.tr,
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import '../../../../tools/submitBtn.dart';
|
|||||||
import '../../../../tools/titleAppBar.dart';
|
import '../../../../tools/titleAppBar.dart';
|
||||||
import '../../../../tools/toast.dart';
|
import '../../../../tools/toast.dart';
|
||||||
import '../../../../translations/trans_lib.dart';
|
import '../../../../translations/trans_lib.dart';
|
||||||
|
import '../../../lockDetail/lcokSet/lockSet/lockSetInfo_entity.dart';
|
||||||
|
|
||||||
class DemoModeLockSetPage extends StatefulWidget {
|
class DemoModeLockSetPage extends StatefulWidget {
|
||||||
const DemoModeLockSetPage({Key? key}) : super(key: key);
|
const DemoModeLockSetPage({Key? key}) : super(key: key);
|
||||||
@ -78,6 +79,24 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
// Get.toNamed(Routers.wirelessKeyboardPage);
|
// Get.toNamed(Routers.wirelessKeyboardPage);
|
||||||
// Toast.show(msg: "功能暂未开放");
|
// Toast.show(msg: "功能暂未开放");
|
||||||
}),
|
}),
|
||||||
|
// 照明
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '照明',
|
||||||
|
rightTitle: "",
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
gotoAddLock();
|
||||||
|
}),
|
||||||
|
// 开门器
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '开门器',
|
||||||
|
rightTitle: "",
|
||||||
|
isHaveLine: false,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
gotoAddLock();
|
||||||
|
}),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
// 自动闭锁
|
// 自动闭锁
|
||||||
CommonItem(
|
CommonItem(
|
||||||
@ -148,54 +167,30 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
}),
|
}),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
//---田总新增展示
|
//---田总新增展示
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: '面容开锁',
|
leftTitel: '面容开锁',
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveLine: true,
|
isHaveLine: true,
|
||||||
isHaveRightWidget: true,
|
|
||||||
rightWidget:
|
|
||||||
SizedBox(width: 60.w, child: _otherUnHaveDoneSwitch())),
|
|
||||||
// ),
|
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
|
||||||
leftTitel: '感应距离',
|
|
||||||
rightTitle: "",
|
|
||||||
isHaveLine: true,
|
|
||||||
isHaveDirection: true,
|
isHaveDirection: true,
|
||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
// ),
|
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: '自动亮屏',
|
leftTitel: '消息提醒',
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveLine: true,
|
isHaveLine: true,
|
||||||
isHaveRightWidget: true,
|
isHaveDirection: true,
|
||||||
rightWidget:
|
action: () {
|
||||||
SizedBox(width: 60.w, child: _otherUnHaveDoneSwitch())),
|
gotoAddLock();
|
||||||
// ),
|
}),
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: '逗留警告',
|
leftTitel: '猫眼设置',
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveLine: true,
|
isHaveLine: true,
|
||||||
isHaveRightWidget: true,
|
isHaveDirection: true,
|
||||||
rightWidget:
|
action: () {
|
||||||
SizedBox(width: 60.w, child: _otherUnHaveDoneSwitch())),
|
gotoAddLock();
|
||||||
// ),
|
}),
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
|
||||||
leftTitel: '异常警告',
|
|
||||||
rightTitle: "",
|
|
||||||
isHaveLine: true,
|
|
||||||
isHaveRightWidget: true,
|
|
||||||
rightWidget:
|
|
||||||
SizedBox(width: 60.w, child: _otherUnHaveDoneSwitch())),
|
|
||||||
// ),
|
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: '开门方向设置',
|
leftTitel: '开门方向设置',
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
@ -203,10 +198,7 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
isHaveLine: true,
|
isHaveLine: true,
|
||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
// ),
|
|
||||||
// Obx(() =>
|
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: '电机功率设置',
|
leftTitel: '电机功率设置',
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
@ -214,11 +206,18 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
isHaveDirection: true,
|
isHaveDirection: true,
|
||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}
|
}),
|
||||||
),
|
// 支持蓝牙广播(关闭则不能使用蓝牙主动开锁)
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '蓝牙广播',
|
||||||
|
rightTitle: "",
|
||||||
|
isHaveLine: false,
|
||||||
|
isHaveRightWidget: true,
|
||||||
|
rightWidget: _lockRemindSwitch()),
|
||||||
// ),
|
// ),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
//-----新增至此
|
//-----新增至此
|
||||||
|
// 标记房态
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel:
|
leftTitel:
|
||||||
TranslationLoader.lanKeys!.markedHouseState!.tr,
|
TranslationLoader.lanKeys!.markedHouseState!.tr,
|
||||||
@ -228,22 +227,23 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}),
|
}),
|
||||||
|
// 考勤
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.checkingIn!.tr,
|
leftTitel: TranslationLoader.lanKeys!.checkingIn!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveLine: true,
|
isHaveLine: true,
|
||||||
isHaveRightWidget: true,
|
isHaveRightWidget: true,
|
||||||
rightWidget:
|
rightWidget: _openCheckInSwitch()
|
||||||
SizedBox(width: 60.w, child: _openCheckInSwitch())
|
|
||||||
),
|
),
|
||||||
|
// 开锁提醒
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.unlockReminder!.tr,
|
leftTitel: TranslationLoader.lanKeys!.unlockReminder!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
isHaveLine: false,
|
isHaveLine: false,
|
||||||
isHaveRightWidget: true,
|
isHaveRightWidget: true,
|
||||||
rightWidget:
|
rightWidget: _lockRemindSwitch()),
|
||||||
SizedBox(width: 60.w, child: _lockRemindSwitch())),
|
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
|
// wifi配网
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader
|
leftTitel: TranslationLoader
|
||||||
.lanKeys!.wifiDistributionNetwork!.tr,
|
.lanKeys!.wifiDistributionNetwork!.tr,
|
||||||
@ -253,6 +253,7 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}),
|
}),
|
||||||
|
// 锁时间
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.lockTime!.tr,
|
leftTitel: TranslationLoader.lanKeys!.lockTime!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
@ -261,6 +262,7 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}),
|
}),
|
||||||
|
// 诊断
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.diagnose!.tr,
|
leftTitel: TranslationLoader.lanKeys!.diagnose!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
@ -269,6 +271,7 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}),
|
}),
|
||||||
|
// 上传数据
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.uploadData!.tr,
|
leftTitel: TranslationLoader.lanKeys!.uploadData!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
@ -277,15 +280,16 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
action: () {
|
action: () {
|
||||||
gotoAddLock();
|
gotoAddLock();
|
||||||
}),
|
}),
|
||||||
CommonItem(
|
// CommonItem(
|
||||||
leftTitel:
|
// leftTitel:
|
||||||
TranslationLoader.lanKeys!.importOtherLockData!.tr,
|
// TranslationLoader.lanKeys!.importOtherLockData!.tr,
|
||||||
rightTitle: "",
|
// rightTitle: "",
|
||||||
isHaveLine: true,
|
// isHaveLine: true,
|
||||||
isHaveDirection: true,
|
// isHaveDirection: true,
|
||||||
action: () {
|
// action: () {
|
||||||
gotoAddLock();
|
// gotoAddLock();
|
||||||
}),
|
// }),
|
||||||
|
// 锁升级
|
||||||
CommonItem(
|
CommonItem(
|
||||||
leftTitel: TranslationLoader.lanKeys!.lockEscalation!.tr,
|
leftTitel: TranslationLoader.lanKeys!.lockEscalation!.tr,
|
||||||
rightTitle: "",
|
rightTitle: "",
|
||||||
@ -335,18 +339,6 @@ class _DemoModeLockSetPageState extends State<DemoModeLockSetPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CupertinoSwitch _otherUnHaveDoneSwitch() {
|
|
||||||
return CupertinoSwitch(
|
|
||||||
activeColor: CupertinoColors.activeBlue,
|
|
||||||
trackColor: CupertinoColors.systemGrey5,
|
|
||||||
thumbColor: CupertinoColors.white,
|
|
||||||
value: false,
|
|
||||||
onChanged: (value) {
|
|
||||||
gotoAddLock();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gotoAddLock(){
|
void gotoAddLock(){
|
||||||
// Get.toNamed(Routers.seletLockTypePage);
|
// Get.toNamed(Routers.seletLockTypePage);
|
||||||
Toast.show(msg: "演示模式");
|
Toast.show(msg: "演示模式");
|
||||||
|
|||||||
@ -110,6 +110,7 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 厂商名称
|
// 厂商名称
|
||||||
var vendor = reply.data.sublist(3, 23);
|
var vendor = reply.data.sublist(3, 23);
|
||||||
|
print("vendor:$vendor reply.data:${reply.data}");
|
||||||
var vendorStr = utf8String(vendor);
|
var vendorStr = utf8String(vendor);
|
||||||
state.lockInfo["vendor"] = vendorStr;
|
state.lockInfo["vendor"] = vendorStr;
|
||||||
// print("vendor:$vendor vendorStr:$vendorStr vendorStr.length${vendorStr.length}");
|
// print("vendor:$vendor vendorStr:$vendorStr vendorStr.length${vendorStr.length}");
|
||||||
|
|||||||
@ -128,7 +128,7 @@ class _StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
// }),
|
// }),
|
||||||
mineItem('images/mine/icon_mine_main_addLock.png',
|
mineItem('images/mine/icon_mine_main_addLock.png',
|
||||||
TranslationLoader.lanKeys!.addDevice!.tr, () {
|
TranslationLoader.lanKeys!.addDevice!.tr, () {
|
||||||
Navigator.pushNamed(context, Routers.seletLockTypePage);
|
Get.toNamed(Routers.seletLockTypePage);
|
||||||
}),
|
}),
|
||||||
// mineItem('images/mine/icon_mine_main_gateway.png',
|
// mineItem('images/mine/icon_mine_main_gateway.png',
|
||||||
// TranslationLoader.lanKeys!.gateway!.tr, () {
|
// TranslationLoader.lanKeys!.gateway!.tr, () {
|
||||||
@ -136,7 +136,7 @@ class _StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
// }),
|
// }),
|
||||||
mineItem('images/mine/icon_mine_main_message.png',
|
mineItem('images/mine/icon_mine_main_message.png',
|
||||||
TranslationLoader.lanKeys!.message!.tr, () {
|
TranslationLoader.lanKeys!.message!.tr, () {
|
||||||
Navigator.pushNamed(context, Routers.messageListPage);
|
Get.toNamed(Routers.messageListPage);
|
||||||
// Toast.show(msg: "功能暂未开放");
|
// Toast.show(msg: "功能暂未开放");
|
||||||
}),
|
}),
|
||||||
//删除“客服”行
|
//删除“客服”行
|
||||||
@ -146,15 +146,15 @@ class _StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
// }),
|
// }),
|
||||||
mineItem('images/mine/icon_mine_main_set.png',
|
mineItem('images/mine/icon_mine_main_set.png',
|
||||||
TranslationLoader.lanKeys!.set!.tr, () {
|
TranslationLoader.lanKeys!.set!.tr, () {
|
||||||
Navigator.pushNamed(context, Routers.mineSetPage);
|
Get.toNamed(Routers.mineSetPage);
|
||||||
}),
|
}),
|
||||||
mineItem('images/mine/icon_mine_main_vip.png',
|
mineItem('images/mine/icon_mine_main_vip.png',
|
||||||
TranslationLoader.lanKeys!.valueAddedServices!.tr, () {
|
TranslationLoader.lanKeys!.valueAddedServices!.tr, () {
|
||||||
Navigator.pushNamed(context, Routers.valueAddedServicesPage);
|
Get.toNamed(Routers.valueAddedServicesPage);
|
||||||
}),
|
}),
|
||||||
mineItem('images/mine/icon_mine_main_about.png',
|
mineItem('images/mine/icon_mine_main_about.png',
|
||||||
TranslationLoader.lanKeys!.about!.tr, () {
|
TranslationLoader.lanKeys!.about!.tr, () {
|
||||||
Navigator.pushNamed(context, Routers.abountPage);
|
Get.toNamed(Routers.abountPage);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -43,17 +43,14 @@ class _ValueAddedServicesPageListState
|
|||||||
// arguments: 2);
|
// arguments: 2);
|
||||||
// }),
|
// }),
|
||||||
_valueAddedServicesItem(
|
_valueAddedServicesItem(
|
||||||
Image.asset(
|
Image.asset('images/mine/icon_mine_valueAddedServices_realName.png'),
|
||||||
'images/mine/icon_mine_valueAddedServices_realName.png'),
|
|
||||||
TranslationLoader.lanKeys!.realNameAuthentication!.tr, () {
|
TranslationLoader.lanKeys!.realNameAuthentication!.tr, () {
|
||||||
Navigator.pushNamed(
|
Get.toNamed(Routers.valueAddedServicesRealNamePage);
|
||||||
context, Routers.valueAddedServicesRealNamePage);
|
|
||||||
}),
|
}),
|
||||||
_valueAddedServicesItem(
|
_valueAddedServicesItem(
|
||||||
Image.asset('images/mine/icon_mine_valueAddedServices_vip.png'),
|
Image.asset('images/mine/icon_mine_valueAddedServices_vip.png'),
|
||||||
TranslationLoader.lanKeys!.advancedFunction!.tr, () {
|
TranslationLoader.lanKeys!.advancedFunction!.tr, () {
|
||||||
Navigator.pushNamed(
|
Get.toNamed(Routers.valueAddedServicesHighFunctionPage);
|
||||||
context, Routers.valueAddedServicesHighFunctionPage);
|
|
||||||
}),
|
}),
|
||||||
// _valueAddedServicesItem(
|
// _valueAddedServicesItem(
|
||||||
// Image.asset('images/mine/icon_mine_valueAddedServices_push.png'),
|
// Image.asset('images/mine/icon_mine_valueAddedServices_push.png'),
|
||||||
|
|||||||
@ -55,6 +55,8 @@ class BaseProvider extends GetConnect with Api {
|
|||||||
body: rs as T,
|
body: rs as T,
|
||||||
statusText: res.statusText,
|
statusText: res.statusText,
|
||||||
);
|
);
|
||||||
|
}else{
|
||||||
|
|
||||||
}
|
}
|
||||||
// print('得到的数据======>bodyString:${res.bodyString} body:${res.body} bodyBytes:${res.bodyBytes} status:${res.status} statusText:${res.statusText} statusCode:${res.statusCode}');
|
// print('得到的数据======>bodyString:${res.bodyString} body:${res.body} bodyBytes:${res.bodyBytes} status:${res.status} statusText:${res.statusText} statusCode:${res.statusCode}');
|
||||||
getDataResult(res.body);
|
getDataResult(res.body);
|
||||||
|
|||||||
@ -9,7 +9,8 @@ class NoData extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
height: 1.sh - ScreenUtil().statusBarHeight,
|
// height: 1.sh - ScreenUtil().statusBarHeight,
|
||||||
|
height: 1.sw,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|||||||
@ -113,6 +113,11 @@ dependencies:
|
|||||||
webview_flutter: ^4.2.3
|
webview_flutter: ^4.2.3
|
||||||
aliyun_push: ^0.1.6
|
aliyun_push: ^0.1.6
|
||||||
|
|
||||||
|
#视频播放器
|
||||||
|
video_player: ^2.7.2
|
||||||
|
#控制横竖屏控件
|
||||||
|
auto_orientation: ^2.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||