diff --git a/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index cb5c3072..2eab574e 100755 --- a/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; @@ -35,11 +36,23 @@ import '../../../blue/blue_manage.dart'; import '../../../blue/io_protocol/io_openLock.dart'; import '../../../blue/io_protocol/io_referEventRecordTime.dart'; import '../../../blue/io_reply.dart'; +import '../../../blue/io_sender.dart'; import '../../../blue/io_tool/io_tool.dart'; import '../../../blue/io_tool/manager_event_bus.dart'; import '../../../blue/sender_manage.dart'; import '../../../network/api_repository.dart'; +import '../../../network/start_chart_api.dart'; import '../../../talk/other/audio_player_manager.dart'; +import '../../../talk/starChart/constant/message_type_constant.dart'; +import '../../../talk/starChart/constant/payload_type_constant.dart'; +import '../../../talk/starChart/constant/protocol_flag_constant.dart'; +import '../../../talk/starChart/entity/scp_message.dart'; +import '../../../talk/starChart/exception/start_chart_message_exception.dart'; +import '../../../talk/starChart/handle/impl/udp_ble_passthrough_handler.dart'; +import '../../../talk/starChart/handle/impl/udp_remote_un_lock_handler.dart'; +import '../../../talk/starChart/handle/scp_message_handle.dart'; +import '../../../talk/starChart/handle/scp_message_handler_factory.dart'; +import '../../../talk/udp/udp_reciverData.dart'; import '../../../tools/baseGetXController.dart'; import '../../../tools/commonDataManage.dart'; import '../../../tools/dateTool.dart'; @@ -207,8 +220,9 @@ class LockDetailLogic extends BaseGetXController { signKey: signKeyDataList, privateKey: getPrivateKeyList, ); - // 只有接听状态时才可以重发开门指令 - if (StartChartManage().talkStatus.status == TalkStatus.answeredSuccessfully) { + // 重发开门指令 + if (StartChartManage().talkStatus.status == TalkStatus.answeredSuccessfully || + StartChartManage().lockPeerId.isNotEmpty) { sendStarChartOpenLockMessage(reply); } @@ -689,57 +703,74 @@ class LockDetailLogic extends BaseGetXController { // 远程开锁 Future remoteOpenLock() async { + final catEyeConfig = state.keyInfos.value.lockSetting?.catEyeConfig ?? []; + // 支持猫眼功能时,才需要判断是否是省电模式 + if (state.keyInfos.value.lockFeature?.isSupportCatEye == 1 && catEyeConfig[0].catEyeMode == 0) { + showToast('猫眼设置为省电模式时无法进行远程开锁,请在猫眼设置中切换为其他模式'.tr); + return; + } final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo; - var lockId = currentKeyInfo.lockId ?? 0; var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0; - final lockPeerId = StartChartManage().lockPeerId; - final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData(); + var lockPeerId = StartChartManage().lockPeerId; - //检查蓝牙连接状态 - final connectedDevices = await FlutterBluePlus.connectedDevices; - final isDeviceConnected = connectedDevices.any((device) => - device.remoteId.str == BlueManage().connectDeviceName); - - if (!isDeviceConnected) { - AppLog.log('蓝牙已断开,尝试重新连接'); - // 蓝牙断开,需要重新连接并获取新的token - await _reconnectAndRefreshToken(); - } - - if (lockListInfoGroupEntity != null) { - lockListInfoGroupEntity!.groupList?.forEach((element) { - final lockList = element.lockList; - if (lockList != null && lockList.length != 0) { - for (var lockInfo in lockList) { - final peerId = lockInfo.network?.peerId; - if (peerId != null && peerId != '') { - if (peerId == lockPeerId) { - lockId = lockInfo.lockId ?? 0; - remoteUnlock = lockInfo.lockSetting?.remoteUnlock ?? 0; - } - } - } - } - }); + if (lockPeerId.isEmpty) { + final network = currentKeyInfo.network; + if (network != null && network.peerId != null && network.peerId!.isNotEmpty) { + lockPeerId = network.peerId!; + StartChartManage().lockPeerId = lockPeerId; + } } if (remoteUnlock == 1) { - // 发送蓝牙透传开锁 - await _sendUnlockViaBluetooth(); - // 发送远程开锁api - final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60); - if (entity.errorCode!.codeIsSuccessful) { - showToast('已开锁'.tr); - StartChartManage().lockListPeerId = []; + try { + if (lockPeerId.isEmpty) { + AppLog.log('远程服务未连接,无法进行远程开锁'); + return; + } + + final response = await StartChartApi.to.analyzeInformationOtherEnd(peerId: lockPeerId); + if (response.statusCode == 200) { + AppLog.log('成功分析对端信息'); + } else { + AppLog.log('分析对端信息失败,状态码: ${response.statusCode}'); + return; + } + + // 判断是否为WiFi锁 + final network = currentKeyInfo.network; + if (network != null && (network.peerId != null && network.peerId!.isNotEmpty)){ + // 发送蓝牙透传开锁指令 + await _sendUnlockViaBluetooth(); + } else { + // 发送远程开锁API + final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60); + if (entity.errorCode!.codeIsSuccessful) { + showToast('已开锁'.tr); + StartChartManage().lockListPeerId = []; + } + } + } catch (e) { + AppLog.log('远程开锁失败: $e'); + showToast('远程开锁失败'.tr); } + } else { + AppLog.log('该锁的远程开锁功能未启用'); + showToast('该锁的远程开锁功能未启用'.tr); } } - // 新增方法:通过蓝牙透传发送开锁命令 + // 通过蓝牙透传发送开锁命令 Future _sendUnlockViaBluetooth() async { try { + // 验证当前连接的设备是否为目标设备 + final String targetDeviceName = state.keyInfos.value.bluetooth!.bluetoothDeviceName!; + final String currentConnectedDevice = BlueManage().connectDeviceName; + + if (targetDeviceName != currentConnectedDevice) { + AppLog.log('目标设备与当前连接设备不匹配,目标: $targetDeviceName, 当前: $currentConnectedDevice'); + } // 获取必要的密钥信息 final List? privateKey = await Storage.getStringList(saveBluePrivateKey); final List privateKeyList = changeStringListToIntList(privateKey!); @@ -750,10 +781,23 @@ class LockDetailLogic extends BaseGetXController { final List? token = await Storage.getStringList(saveBlueToken); final List tokenList = changeStringListToIntList(token!); + // 获取连接的设备名称 + final String bluetoothDeviceName = BlueManage().connectDeviceName; + if (bluetoothDeviceName.isEmpty) { + throw Exception('未找到连接的蓝牙设备'); + } + + // 获取用户ID + final String? userID = await Storage.getUid(); + if (userID == null || userID.isEmpty) { + throw Exception('未找到用户ID'); + } + AppLog.log('用户ID: $userID'); + // 构建开锁命令 final OpenLockCommand openLockCommand = OpenLockCommand( - lockID: BlueManage().connectDeviceName, - userID: await Storage.getUid(), + lockID: bluetoothDeviceName, + userID: userID, openMode: state.openDoorModel, openTime: getUTCNetTime(), onlineToken: state.lockNetToken, @@ -762,151 +806,20 @@ class LockDetailLogic extends BaseGetXController { signKey: signKeyList, privateKey: privateKeyList, ); + AppLog.log('构建开锁命令成功'); // 包装命令数据 final List messageDetail = openLockCommand.packageData(); - // 通过蓝牙透传发送开锁命令 + // 发送蓝牙透传开锁命令 StartChartManage().sendRemoteUnLockMessage( - bluetoothDeviceName: BlueManage().connectDeviceName, + bluetoothDeviceName: bluetoothDeviceName, openLockCommand: messageDetail, ); - - AppLog.log('通过蓝牙透传发送远程开锁命令'); - - // 监听开锁结果,处理token不一致的情况 - _listenForOpenLockReply(tokenList); + AppLog.log('蓝牙透传开锁命令已发送到设备: $bluetoothDeviceName'); } catch (e) { AppLog.log('蓝牙透传开锁异常: $e'); - showToast('蓝牙透传开锁失败'.tr); - } - } - - // 监听开锁回复,处理token验证 - void _listenForOpenLockReply(List originalToken) { - StreamSubscription? subscription; - // 设置监听器处理开锁回复 - subscription = EventBusManager().eventBus!.on().listen((Reply reply) async { - if (reply is OpenDoorReply) { - final int status = reply.data[6]; - - // 如果是token不一致的情况(状态码0x06) - if (status == 0x06) { - AppLog.log('token不一致,使用新token重新开锁'); - - // 提取新的token - final List newToken = reply.data.sublist(2, 6); - - // 保存新token到存储 - final List saveStrList = changeIntListToStringList(newToken); - Storage.setStringList(saveBlueToken, saveStrList); - - // 使用新token重新发送开锁命令 - await _reSendUnlockWithNewToken(newToken); - } - - // 取消监听 - subscription?.cancel(); - } - }); - - // 设置超时机制,避免监听器一直存在 - Timer(const Duration(seconds: 10), () { - subscription?.cancel(); - }); - } - - // 使用新token重新发送开锁命令 - Future _reSendUnlockWithNewToken(List newToken) async { - try { - // 获取必要的密钥信息 - final List? privateKey = await Storage.getStringList(saveBluePrivateKey); - final List privateKeyList = changeStringListToIntList(privateKey!); - - final List? signKey = await Storage.getStringList(saveBlueSignKey); - final List signKeyList = changeStringListToIntList(signKey!); - - // 构建新的开锁命令 - final OpenLockCommand openLockCommand = OpenLockCommand( - lockID: BlueManage().connectDeviceName, - userID: await Storage.getUid(), - openMode: state.openDoorModel, - openTime: getUTCNetTime(), - onlineToken: state.lockNetToken, - token: newToken, - needAuthor: 1, - signKey: signKeyList, - privateKey: privateKeyList, - ); - - // 包装命令数据 - final List messageDetail = openLockCommand.packageData(); - - // 通过蓝牙透传发送开锁命令 - StartChartManage().sendRemoteUnLockMessage( - bluetoothDeviceName: BlueManage().connectDeviceName, - openLockCommand: messageDetail, - ); - - AppLog.log('使用新token重新发送开锁命令'); - } catch (e) { - AppLog.log('使用新token重新开锁异常: $e'); - showToast('重新开锁失败'.tr); - } - } - - // 新增方法:重新连接蓝牙并刷新token - Future _reconnectAndRefreshToken() async { - try { - // 重新连接蓝牙 - await BlueManage().blueSendData( - state.keyInfos.value.bluetooth!.bluetoothDeviceName!, - (BluetoothConnectionState deviceConnectionState) async { - if (deviceConnectionState == BluetoothConnectionState.connected) { - AppLog.log('蓝牙重新连接成功'); - // 获取新的token - await _refreshLockToken(); - } else if (deviceConnectionState == BluetoothConnectionState.disconnected) { - AppLog.log('蓝牙重新连接失败'); - showToast('蓝牙连接失败,请重试'.tr); - } - }, - ); - } catch (e) { - AppLog.log('蓝牙重连异常: $e'); - showToast('蓝牙连接异常,请重试'.tr); - } - } - - // 新增方法:刷新锁token - Future _refreshLockToken() async { - try { - final List? token = await Storage.getStringList(saveBlueToken); - final List tokenList = changeStringListToIntList(token!); - - final List? privateKey = await Storage.getStringList(saveBluePrivateKey); - final List privateKeyList = changeStringListToIntList(privateKey!); - - final List? signKey = await Storage.getStringList(saveBlueSignKey); - final List signKeyList = changeStringListToIntList(signKey!); - - // 发送获取新token的命令 - IoSenderManage.senderOpenLock( - lockID: BlueManage().connectDeviceName, - userID: await Storage.getUid(), - openMode: state.openDoorModel, - openTime: getUTCNetTime(), - onlineToken: state.lockNetToken, - token: tokenList, - needAuthor: 1, - signKey: signKeyList, - privateKey: privateKeyList, - ); - - // 等待一段时间让token更新完成 - await Future.delayed(Duration(milliseconds: 500)); - } catch (e) { - AppLog.log('刷新token异常: $e'); + rethrow; } } diff --git a/lib/main/lockDetail/lockDetail/lockDetail_page.dart b/lib/main/lockDetail/lockDetail/lockDetail_page.dart index e7d2f9cc..7f0e95c3 100755 --- a/lib/main/lockDetail/lockDetail/lockDetail_page.dart +++ b/lib/main/lockDetail/lockDetail/lockDetail_page.dart @@ -695,9 +695,9 @@ class _LockDetailPageState extends State with TickerProviderStat child: GestureDetector( onTap: () { ShowCupertinoAlertView().isToRemoteUnLockAlert(remoteUnlockAction: () { - if (state.keyInfos.value.hasGateway != 1) { - logic.showToast('附近没有可用网关'.tr); - } + // if (state.keyInfos.value.hasGateway != 1) { + // logic.showToast('附近没有可用网关'.tr); + // } logic.remoteOpenLock(); }); }, diff --git a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart index 599f65fc..8dc030f0 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart @@ -191,7 +191,7 @@ class ConfiguringWifiLogic extends BaseGetXController { state.lockSetInfoData.value?.lockBasicInfo?.networkInfo?.wifiName = wifiName; state.lockSetInfoData.value?.lockBasicInfo?.networkInfo?.rssi = - rssi as int?; + rssi; /// 配网成功后,赋值锁的peerId StartChartManage().lockPeerId = peerId; diff --git a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart index 33a38066..d3195e31 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart @@ -79,14 +79,6 @@ class _ConfiguringWifiPageState extends State SizedBox( height: 20.h, ), - Text( - '请确保网络是2.4GHz Wi-Fi'.tr, - style: TextStyle( - color: AppColors.blackColor, - fontSize: 20.sp, - fontWeight: FontWeight.w500, - ), - ), ], )); } diff --git a/lib/talk/starChart/star_chart_manage.dart b/lib/talk/starChart/star_chart_manage.dart index 6adc5663..b44a131c 100644 --- a/lib/talk/starChart/star_chart_manage.dart +++ b/lib/talk/starChart/star_chart_manage.dart @@ -1074,6 +1074,7 @@ class StartChartManage { void _handleUdpResultData(ScpMessage scpMessage) { final int payloadType = scpMessage.PayloadType ?? 0; final int messageType = scpMessage.MessageType ?? 0; + AppLog.log('payloadType:$payloadType,messageType:$messageType'); // 添加开锁回应的日志打印 if (payloadType == PayloadTypeConstant.remoteUnlock) { AppLog.log('收到蓝牙设备回应消息,${scpMessage.PayloadType}'); diff --git a/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart b/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart index 9a6cbcbf..4437ab13 100644 --- a/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart +++ b/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart @@ -58,6 +58,12 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { List? _cachedPps; bool _waitingForCompleteIFrame = false; + /// 状态变更防抖时间(毫秒) + static const int STATUS_DEBOUNCE_TIME = 500; + + /// 上次状态变更时间戳 + int _lastStatusChangeTime = 0; + int _frameProcessCount = 0; int _lastFrameProcessTime = 0; double _actualFps = 0.0; @@ -833,6 +839,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { /// 监听对讲状态 void _startListenTalkStatus() { state.startChartTalkStatus.statusStream.listen((talkStatus) { + // 防抖处理:检查距离上次状态变更的时间间隔 + final int currentTime = DateTime.now().millisecondsSinceEpoch; + if (currentTime - _lastStatusChangeTime < STATUS_DEBOUNCE_TIME) { + AppLog.log('状态变更过于频繁,忽略此次变更: $talkStatus'); + return; + } + // 更新上次状态变更时间 + _lastStatusChangeTime = currentTime; state.talkStatus.value = talkStatus; switch (talkStatus) { case TalkStatus.rejected: @@ -865,13 +879,9 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData); FlutterPcmSound.feed(fromList); if (!state.isPlaying.value) { - AppLog.log('play'); FlutterPcmSound.play(); state.isPlaying.value = true; } - } else if (state.isOpenVoice.isFalse) { - FlutterPcmSound.pause(); - state.isPlaying.value = false; } } diff --git a/lib/talk/starChart/views/native/talk_view_native_decode_page.dart b/lib/talk/starChart/views/native/talk_view_native_decode_page.dart index cd7a137d..122b34de 100644 --- a/lib/talk/starChart/views/native/talk_view_native_decode_page.dart +++ b/lib/talk/starChart/views/native/talk_view_native_decode_page.dart @@ -39,29 +39,32 @@ class _TalkViewNativeDecodePageState extends State wit final TalkViewNativeDecodeState state = Get.find().state; final startChartManage = StartChartManage(); + late AnimationController _animationController; // 改为本地变量 + @override void initState() { super.initState(); - state.animationController = AnimationController( - vsync: this, // 确保使用的TickerProvider是当前Widget + _animationController = AnimationController( // 使用本地变量 + vsync: this, duration: const Duration(seconds: 1), ); - state.animationController.repeat(); - // 添加帧回调以优化动画性能 + state.animationController = _animationController; // 同步到状态 + + _animationController.repeat(); + SchedulerBinding.instance.addPostFrameCallback((_) { - // 确保动画在合适的帧率下运行 - state.animationController.duration = const Duration(milliseconds: 500); + _animationController.duration = const Duration(milliseconds: 500); }); - //动画开始、结束、向前移动或向后移动时会调用StatusListener - state.animationController.addStatusListener((AnimationStatus status) { + + _animationController.addStatusListener((AnimationStatus status) { if (status == AnimationStatus.completed) { - state.animationController.reset(); - state.animationController.forward(); + _animationController.reset(); + _animationController.forward(); } else if (status == AnimationStatus.dismissed) { - state.animationController.reset(); - state.animationController.forward(); + _animationController.reset(); + _animationController.forward(); } }); } @@ -360,9 +363,12 @@ class _TalkViewNativeDecodePageState extends State wit state.isLongPressing.value = false; }, onClick: () async { + // 只有在被动呼叫等待接听状态下才允许接听操作 if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) { - // 接听 - logic.initiateAnswerCommand(); + // 确保不是监控模式下调用 + if (!state.isMonitoringMode()) { + logic.initiateAnswerCommand(); + } } }, ), @@ -393,6 +399,10 @@ class _TalkViewNativeDecodePageState extends State wit } String getAnswerBtnImg() { + // 如果是监控模式,始终显示对讲按钮 + if (state.isMonitoringMode.value) { + return 'images/main/icon_lockDetail_monitoringUnTalkback.png'; + } switch (state.talkStatus.value) { case TalkStatus.passiveCallWaitingAnswer: return 'images/main/icon_lockDetail_monitoringAnswerCalls.png'; @@ -405,6 +415,10 @@ class _TalkViewNativeDecodePageState extends State wit } String getAnswerBtnName() { + // 如果是监控模式,显示对讲相关文本 + if (state.isMonitoringMode.value) { + return '长按说话'.tr; + } switch (state.talkStatus.value) { case TalkStatus.passiveCallWaitingAnswer: return '接听'.tr; @@ -506,8 +520,11 @@ class _TalkViewNativeDecodePageState extends State wit @override void dispose() { - state.animationController.dispose(); CallTalk().finishAVData(); + + // 只处理本地的 animation controller + _animationController.dispose(); + super.dispose(); } } diff --git a/lib/talk/starChart/views/native/talk_view_native_decode_state.dart b/lib/talk/starChart/views/native/talk_view_native_decode_state.dart index 4396884c..350961f1 100644 --- a/lib/talk/starChart/views/native/talk_view_native_decode_state.dart +++ b/lib/talk/starChart/views/native/talk_view_native_decode_state.dart @@ -129,4 +129,7 @@ class TalkViewNativeDecodeState { // 是否拉伸至全屏 RxBool isFullScreen = false.obs; + + //添加监控模式标识 + final RxBool isMonitoringMode = false.obs; }