fix:完善对讲流程、增加蓝牙透传消息指令
This commit is contained in:
parent
c16c9be4c6
commit
92fcf4a4fa
@ -12,7 +12,7 @@ import 'package:star_lock/mine/about/debug/debug_tool.dart';
|
|||||||
import 'package:star_lock/network/api_provider.dart';
|
import 'package:star_lock/network/api_provider.dart';
|
||||||
import 'package:star_lock/network/api_repository.dart';
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
import 'package:star_lock/network/start_chart_api.dart';
|
import 'package:star_lock/network/start_chart_api.dart';
|
||||||
import 'package:star_lock/talk/startChart/appLifecycle_observer.dart';
|
import 'package:star_lock/talk/startChart/status/appLifecycle_observer.dart';
|
||||||
import 'package:star_lock/tools/bugly/bugly_tool.dart';
|
import 'package:star_lock/tools/bugly/bugly_tool.dart';
|
||||||
import 'package:star_lock/tools/device_info_service.dart';
|
import 'package:star_lock/tools/device_info_service.dart';
|
||||||
import 'package:star_lock/tools/platform_info_services.dart';
|
import 'package:star_lock/tools/platform_info_services.dart';
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class CatEyeSetLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置自动亮屏
|
//设置亮屏持续时间
|
||||||
Future<void> updateLightScreenTimeConfig() async {
|
Future<void> updateLightScreenTimeConfig() async {
|
||||||
final VersionUndateEntity entity = await ApiRepository.to.updateLightScreenTimeConfig(
|
final VersionUndateEntity entity = await ApiRepository.to.updateLightScreenTimeConfig(
|
||||||
lockId: state.lockSetInfoData.value.lockId!,
|
lockId: state.lockSetInfoData.value.lockId!,
|
||||||
@ -112,4 +112,6 @@ class CatEyeSetLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:star_lock/blue/blue_manage.dart';
|
||||||
|
import 'package:star_lock/blue/io_tool/io_tool.dart';
|
||||||
|
import 'package:star_lock/blue/sender_manage.dart';
|
||||||
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
|
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
|
||||||
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeWorkMode/catEyeWorkMode_state.dart';
|
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeWorkMode/catEyeWorkMode_state.dart';
|
||||||
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
|
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
|
||||||
import 'package:star_lock/network/api_repository.dart';
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'package:star_lock/tools/storage.dart';
|
||||||
import 'package:star_lock/versionUndate/versionUndate_entity.dart';
|
import 'package:star_lock/versionUndate/versionUndate_entity.dart';
|
||||||
|
|
||||||
class CatEyeWorkModeLogic extends BaseGetXController {
|
class CatEyeWorkModeLogic extends BaseGetXController {
|
||||||
@ -11,7 +16,8 @@ class CatEyeWorkModeLogic extends BaseGetXController {
|
|||||||
|
|
||||||
//设置猫眼工作模式
|
//设置猫眼工作模式
|
||||||
Future<void> updateCatEyeModeConfig() async {
|
Future<void> updateCatEyeModeConfig() async {
|
||||||
final VersionUndateEntity entity = await ApiRepository.to.updateCatEyeModeConfig(
|
final VersionUndateEntity entity =
|
||||||
|
await ApiRepository.to.updateCatEyeModeConfig(
|
||||||
lockId: state.lockSetInfoData.value.lockId!,
|
lockId: state.lockSetInfoData.value.lockId!,
|
||||||
catEyeConfig: [
|
catEyeConfig: [
|
||||||
<String, Object>{
|
<String, Object>{
|
||||||
@ -53,9 +59,47 @@ class CatEyeWorkModeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 处理蓝牙数据
|
||||||
|
void _handlerBleData() {
|
||||||
|
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||||
|
(BluetoothConnectionState connectionState) async {
|
||||||
|
if (connectionState == BluetoothConnectionState.connected) {
|
||||||
|
final List<String>? privateKey =
|
||||||
|
await Storage.getStringList(saveBluePrivateKey);
|
||||||
|
final List<int> getPrivateKeyList =
|
||||||
|
changeStringListToIntList(privateKey!);
|
||||||
|
|
||||||
|
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
||||||
|
final List<int> getTokenList = changeStringListToIntList(token!);
|
||||||
|
|
||||||
|
final List<String>? publicKey =
|
||||||
|
await Storage.getStringList(saveBluePublicKey);
|
||||||
|
final List<int> getPublicKeyList =
|
||||||
|
changeStringListToIntList(publicKey!);
|
||||||
|
|
||||||
|
List<int> featureData = [];
|
||||||
|
|
||||||
|
IoSenderManage.setSupportFunctionsWithParametersCommand(
|
||||||
|
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
|
||||||
|
userID: await Storage.getUid(),
|
||||||
|
featureBit: 33,
|
||||||
|
featureParaLength: 1,
|
||||||
|
featureData: featureData,
|
||||||
|
token: getTokenList,
|
||||||
|
needAuthor: 1,
|
||||||
|
publicKey: getPublicKeyList,
|
||||||
|
privateKey: getPrivateKeyList);
|
||||||
|
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||||
|
dismissEasyLoading();
|
||||||
|
cancelBlueConnetctToastTimer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 获取锁设置信息
|
// 获取锁设置信息
|
||||||
Future<void> getLockSettingInfoData() async {
|
Future<void> getLockSettingInfoData() async {
|
||||||
final LockSetInfoEntity entity = await ApiRepository.to.getLockSettingInfoData(
|
final LockSetInfoEntity entity =
|
||||||
|
await ApiRepository.to.getLockSettingInfoData(
|
||||||
lockId: state.lockSetInfoData.value.lockId.toString(),
|
lockId: state.lockSetInfoData.value.lockId.toString(),
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
|
|||||||
@ -105,10 +105,11 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
serversList.add(type2);
|
serversList.add(type2);
|
||||||
}
|
}
|
||||||
|
|
||||||
final StarChartRegisterNodeEntity? registerNodeEntity =
|
// 判断是否登录账户
|
||||||
await Storage.getStarChartRegisterNodeInfo();
|
final loginData = await Storage.getLoginData();
|
||||||
|
|
||||||
// 获取app用户的peerId
|
// 获取app用户的peerId
|
||||||
String appPeerId = registerNodeEntity?.peer?.id ?? '';
|
String appPeerId = loginData?.starchart?.starchartId ?? '';
|
||||||
|
|
||||||
final List<String> uidList = <String>[Storage.getUid().toString()];
|
final List<String> uidList = <String>[Storage.getUid().toString()];
|
||||||
IoSenderManage.senderConfiguringWifiCommand(
|
IoSenderManage.senderConfiguringWifiCommand(
|
||||||
@ -201,10 +202,11 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
final String? uidStr = await Storage.getUid();
|
final String? uidStr = await Storage.getUid();
|
||||||
final List<String> uidList = <String>[uidStr.toString()];
|
final List<String> uidList = <String>[uidStr.toString()];
|
||||||
|
|
||||||
final StarChartRegisterNodeEntity? registerNodeEntity =
|
// 判断是否登录账户
|
||||||
await Storage.getStarChartRegisterNodeInfo();
|
final loginData = await Storage.getLoginData();
|
||||||
|
|
||||||
// 获取app用户的peerId
|
// 获取app用户的peerId
|
||||||
String appPeerId = registerNodeEntity?.peer?.id ?? '';
|
String appPeerId = loginData?.starchart?.starchartId ?? '';
|
||||||
IoSenderManage.senderConfiguringWifiCommand(
|
IoSenderManage.senderConfiguringWifiCommand(
|
||||||
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
|
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
|
||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -6,6 +6,7 @@ import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart';
|
|||||||
import 'package:star_lock/talk/startChart/constant/protocol_flag_constant.dart';
|
import 'package:star_lock/talk/startChart/constant/protocol_flag_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/constant/udp_constant.dart';
|
import 'package:star_lock/talk/startChart/constant/udp_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
|
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
|
||||||
|
import 'package:star_lock/talk/startChart/proto/ble_message.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
||||||
@ -386,7 +387,7 @@ class MessageCommand {
|
|||||||
final payload = rbcuInfo.writeToBuffer();
|
final payload = rbcuInfo.writeToBuffer();
|
||||||
ScpMessage message = ScpMessage(
|
ScpMessage message = ScpMessage(
|
||||||
ProtocolFlag: ProtocolFlagConstant.scp01,
|
ProtocolFlag: ProtocolFlagConstant.scp01,
|
||||||
MessageType: MessageTypeConstant.Resp,
|
MessageType: MessageTypeConstant.Req,
|
||||||
MessageId: MessageId,
|
MessageId: MessageId,
|
||||||
SpTotal: 1,
|
SpTotal: 1,
|
||||||
SpIndex: 1,
|
SpIndex: 1,
|
||||||
@ -401,6 +402,40 @@ class MessageCommand {
|
|||||||
return _hexToBytes(serializedBytesString);
|
return _hexToBytes(serializedBytesString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 蓝牙消息
|
||||||
|
static List<int> bleMessage({
|
||||||
|
required String FromPeerId,
|
||||||
|
required String ToPeerId,
|
||||||
|
required String bluetoothDeviceName,
|
||||||
|
required List<int> bleStructData,
|
||||||
|
int? MessageId,
|
||||||
|
int? timeout = 30,
|
||||||
|
int? IdleTimeout = 0,
|
||||||
|
}) {
|
||||||
|
final bleReq = BleReq(
|
||||||
|
bluetoothDeviceName: bluetoothDeviceName,
|
||||||
|
structData: bleStructData,
|
||||||
|
timeout: timeout,
|
||||||
|
idleTimeout: 0,
|
||||||
|
);
|
||||||
|
final payload = bleReq.writeToBuffer();
|
||||||
|
ScpMessage message = ScpMessage(
|
||||||
|
ProtocolFlag: ProtocolFlagConstant.scp01,
|
||||||
|
MessageType: MessageTypeConstant.Req,
|
||||||
|
MessageId: MessageId,
|
||||||
|
SpTotal: 1,
|
||||||
|
SpIndex: 1,
|
||||||
|
FromPeerId: FromPeerId,
|
||||||
|
ToPeerId: ToPeerId,
|
||||||
|
Payload: payload,
|
||||||
|
PayloadCRC: calculationCrc(Uint8List.fromList(payload)),
|
||||||
|
PayloadLength: payload.length,
|
||||||
|
PayloadType: PayloadTypeConstant.blePassthrough,
|
||||||
|
);
|
||||||
|
String serializedBytesString = message.serialize();
|
||||||
|
return _hexToBytes(serializedBytesString);
|
||||||
|
}
|
||||||
|
|
||||||
// 辅助方法:将16进制字符串转换为字节列表
|
// 辅助方法:将16进制字符串转换为字节列表
|
||||||
static List<int> _hexToBytes(String hex) {
|
static List<int> _hexToBytes(String hex) {
|
||||||
final bytes = <int>[];
|
final bytes = <int>[];
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:star_lock/app_settings/app_settings.dart';
|
import 'package:star_lock/app_settings/app_settings.dart';
|
||||||
import 'package:star_lock/talk/startChart/exception/start_chart_message_exception.dart';
|
import 'package:star_lock/talk/startChart/exception/start_chart_message_exception.dart';
|
||||||
|
import 'package:star_lock/talk/startChart/handle/impl/udp_heart_beat_handler.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
|
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/scp_message_handler_factory.dart';
|
import 'package:star_lock/talk/startChart/handle/scp_message_handler_factory.dart';
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:star_lock/appRouters.dart';
|
import 'package:star_lock/appRouters.dart';
|
||||||
|
import 'package:star_lock/app_settings/app_settings.dart';
|
||||||
|
import 'package:star_lock/talk/startChart/constant/message_type_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
|
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/scp_message_base_handle.dart';
|
import 'package:star_lock/talk/startChart/handle/scp_message_base_handle.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
|
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
|
||||||
@ -16,13 +19,16 @@ class UdpBlePassThroughHandler extends ScpMessageBaseHandle
|
|||||||
implements ScpMessageHandler {
|
implements ScpMessageHandler {
|
||||||
@override
|
@override
|
||||||
void handleReq(ScpMessage scpMessage) {
|
void handleReq(ScpMessage scpMessage) {
|
||||||
final BleResp bleResp = scpMessage.Payload;
|
|
||||||
//TODO 收到蓝牙透传请求指令
|
//TODO 收到蓝牙透传请求指令
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleResp(ScpMessage scpMessage) {
|
void handleResp(ScpMessage scpMessage) {
|
||||||
// TODO: 收到蓝牙透传指令回复
|
final BleResp bleResp = scpMessage.Payload;
|
||||||
|
// 如果回复成功
|
||||||
|
// if (bleResp.status == BleResp_StatusE.SUCCESS) {
|
||||||
|
AppLog.log('收到蓝牙消息回复:${bleResp.structData}');
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -41,8 +47,17 @@ class UdpBlePassThroughHandler extends ScpMessageBaseHandle
|
|||||||
int? spTotal,
|
int? spTotal,
|
||||||
int? spIndex,
|
int? spIndex,
|
||||||
int? messageId}) {
|
int? messageId}) {
|
||||||
final BleResp bleResp = BleResp();
|
if (messageType == MessageTypeConstant.Resp) {
|
||||||
bleResp.mergeFromBuffer(byte);
|
final BleResp bleResp = BleResp();
|
||||||
return bleResp;
|
bleResp.mergeFromBuffer(byte);
|
||||||
|
return bleResp;
|
||||||
|
} else if (messageType == MessageTypeConstant.Req) {
|
||||||
|
final BleReq talkExpect = BleReq();
|
||||||
|
talkExpect.mergeFromBuffer(byte);
|
||||||
|
return talkExpect;
|
||||||
|
} else {
|
||||||
|
String payload = utf8.decode(byte);
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,16 +46,20 @@ class UdpRbcuInfoHandler extends ScpMessageBaseHandle
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void handleReq(ScpMessage scpMessage) {
|
void handleReq(ScpMessage scpMessage) {
|
||||||
final RbcuInfo rbcuInfo = scpMessage.Payload();
|
final RbcuInfo rbcuInfo = scpMessage.Payload;
|
||||||
if (rbcuInfo.isResp) {
|
if (rbcuInfo.isResp) {
|
||||||
// 如果是回复的消息
|
// 如果是回复的消息
|
||||||
_handleResultRbcuInfo(rbcuInfo);
|
_handleResultRbcuInfo(rbcuInfo);
|
||||||
|
} else {
|
||||||
|
// 回复
|
||||||
|
startChartManage.replyRbcuInfoMessage(ToPeerId: scpMessage.FromPeerId!);
|
||||||
}
|
}
|
||||||
|
replySuccessMessage(scpMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleResp(ScpMessage scpMessage) {
|
void handleResp(ScpMessage scpMessage) {
|
||||||
final GenericResp genericResp = scpMessage.Payload();
|
final GenericResp genericResp = scpMessage.Payload;
|
||||||
if (checkGenericRespSuccess(genericResp)) {
|
if (checkGenericRespSuccess(genericResp)) {
|
||||||
// 收到回复之后停止重发
|
// 收到回复之后停止重发
|
||||||
startChartManage.stopSendingRbcuInfoMessages();
|
startChartManage.stopSendingRbcuInfoMessages();
|
||||||
@ -65,5 +69,6 @@ class UdpRbcuInfoHandler extends ScpMessageBaseHandle
|
|||||||
/// 处理回复的rbcuInfo消息
|
/// 处理回复的rbcuInfo消息
|
||||||
void _handleResultRbcuInfo(RbcuInfo rbcuInfo) {
|
void _handleResultRbcuInfo(RbcuInfo rbcuInfo) {
|
||||||
P2pManage().communicationObjectRbcuInfo = rbcuInfo;
|
P2pManage().communicationObjectRbcuInfo = rbcuInfo;
|
||||||
|
startChartManage.stopSendingRbcuInfoMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,25 +12,21 @@ import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
|
|||||||
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
|
||||||
|
import 'package:star_lock/talk/startChart/views/talkView/talk_view_logic.dart';
|
||||||
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
|
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
|
||||||
|
|
||||||
import '../../start_chart_manage.dart';
|
import '../../start_chart_manage.dart';
|
||||||
|
|
||||||
class UdpTalkExpectHandler extends ScpMessageBaseHandle
|
class UdpTalkExpectHandler extends ScpMessageBaseHandle
|
||||||
implements ScpMessageHandler {
|
implements ScpMessageHandler {
|
||||||
final TalkViewState talkViewState = TalkViewState();
|
final TalkViewState talkViewState = Get.put(TalkViewLogic()).state;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleReq(ScpMessage scpMessage) {
|
void handleReq(ScpMessage scpMessage) {
|
||||||
// 收到预期音视频数据请求
|
// 收到预期音视频数据请求
|
||||||
final TalkExpectReq talkExpect = scpMessage.Payload;
|
final TalkExpectReq talkExpect = scpMessage.Payload;
|
||||||
print('收到预期音视频数据请求:$talkExpect');
|
|
||||||
|
|
||||||
// 回复请求
|
// 回复请求
|
||||||
replySuccessMessage(scpMessage);
|
replySuccessMessage(scpMessage);
|
||||||
|
|
||||||
// 启动发送通话数据
|
|
||||||
// startChartManage.startTalkDataTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -38,10 +34,13 @@ class UdpTalkExpectHandler extends ScpMessageBaseHandle
|
|||||||
// 收到预期音视频数据回复
|
// 收到预期音视频数据回复
|
||||||
final TalkExpectResp talkExpectResp = scpMessage.Payload;
|
final TalkExpectResp talkExpectResp = scpMessage.Payload;
|
||||||
if (talkExpectResp != null) {
|
if (talkExpectResp != null) {
|
||||||
print('收到预期音视频数据回复');
|
// print('收到预期音视频数据回复,scpMessage:$scpMessage');
|
||||||
// 停止发送预期数据的定时器
|
// 停止发送预期数据的定时器
|
||||||
startChartManage.stopTalkExpectMessageTimer();
|
startChartManage.stopTalkExpectMessageTimer();
|
||||||
talkViewState.rotateAngle.value = talkExpectResp.rotate ?? 0;
|
talkViewState.rotateAngle.value = talkExpectResp.rotate ?? 0;
|
||||||
|
// 收到预期数据的应答后,代表建立了连接,启动通话保持的监听
|
||||||
|
// 启动通话保持监听定时器(用来判断如果x秒内没有收到通话保持则执行的操作);
|
||||||
|
talkePingOverTimeTimerManager.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,17 +15,17 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
|
|||||||
implements ScpMessageHandler {
|
implements ScpMessageHandler {
|
||||||
@override
|
@override
|
||||||
void handleReq(ScpMessage scpMessage) {
|
void handleReq(ScpMessage scpMessage) {
|
||||||
if (talkStatus.status != TalkStatus.answeredSuccessfully) {
|
// if (talkStatus.status != TalkStatus.answeredSuccessfully) {
|
||||||
// 如果不是接听中,不处理通话中挂断请求
|
// // 如果不是接听中,不处理通话中挂断请求
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
print('收到通话中挂断请求');
|
||||||
// 回复请求
|
// 回复请求
|
||||||
replySuccessMessage(scpMessage);
|
replySuccessMessage(scpMessage);
|
||||||
talkStatus.setHangingUpDuring();
|
talkStatus.setHangingUpDuring();
|
||||||
stopRingtone();
|
stopRingtone();
|
||||||
StartChartManage().stopTalkExpectMessageTimer();
|
StartChartManage().stopTalkExpectMessageTimer();
|
||||||
StartChartManage().stopTalkPingMessageTimer();
|
StartChartManage().stopTalkPingMessageTimer();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -15,15 +15,13 @@ class UdpTalkPingHandler extends ScpMessageBaseHandle
|
|||||||
void handleReq(ScpMessage scpMessage) {
|
void handleReq(ScpMessage scpMessage) {
|
||||||
// 收到通话保持请求,回复成功消息
|
// 收到通话保持请求,回复成功消息
|
||||||
replySuccessMessage(scpMessage);
|
replySuccessMessage(scpMessage);
|
||||||
|
talkePingOverTimeTimerManager.renew();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleResp(ScpMessage scpMessage) {
|
void handleResp(ScpMessage scpMessage) {
|
||||||
// 收到通话保持回复
|
|
||||||
// print('收到通话保持回复');
|
|
||||||
final GenericResp genericResp = scpMessage.Payload;
|
final GenericResp genericResp = scpMessage.Payload;
|
||||||
if (checkGenericRespSuccess(genericResp)) {
|
if (checkGenericRespSuccess(genericResp)) {
|
||||||
// 收到消息,续签定时器
|
|
||||||
talkePingOverTimeTimerManager.renew();
|
talkePingOverTimeTimerManager.renew();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,8 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
|
|||||||
implements ScpMessageHandler {
|
implements ScpMessageHandler {
|
||||||
@override
|
@override
|
||||||
void handleReq(ScpMessage scpMessage) async {
|
void handleReq(ScpMessage scpMessage) async {
|
||||||
|
// 回复成功
|
||||||
|
replySuccessMessage(scpMessage);
|
||||||
// 判断是否登录账户
|
// 判断是否登录账户
|
||||||
final loginData = await Storage.getLoginData();
|
final loginData = await Storage.getLoginData();
|
||||||
if (loginData == null ||
|
if (loginData == null ||
|
||||||
@ -28,11 +30,8 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
|
|||||||
// 如果已经是等待接听了,就不在处理剩下的请求
|
// 如果已经是等待接听了,就不在处理剩下的请求
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 回复成功
|
|
||||||
replySuccessMessage(scpMessage);
|
|
||||||
// 收到对讲请求
|
// 收到对讲请求
|
||||||
final TalkReq talkReq = scpMessage.Payload;
|
final TalkReq talkReq = scpMessage.Payload;
|
||||||
|
|
||||||
startChartManage.FromPeerId = scpMessage.ToPeerId!;
|
startChartManage.FromPeerId = scpMessage.ToPeerId!;
|
||||||
startChartManage.ToPeerId = scpMessage.FromPeerId!;
|
startChartManage.ToPeerId = scpMessage.FromPeerId!;
|
||||||
// 处理收到接听请求后的事件
|
// 处理收到接听请求后的事件
|
||||||
@ -64,8 +63,6 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
|
|||||||
_showTalkRequestNotification(talkObjectName: talkObjectName);
|
_showTalkRequestNotification(talkObjectName: talkObjectName);
|
||||||
// 设置为等待接听状态
|
// 设置为等待接听状态
|
||||||
talkStatus.setWaitingAnswer();
|
talkStatus.setWaitingAnswer();
|
||||||
// 启动通话保持
|
|
||||||
_handleStartTalkPing();
|
|
||||||
// 启动对讲请求超时定时器
|
// 启动对讲请求超时定时器
|
||||||
talkeRequestOverTimeTimerManager.start();
|
talkeRequestOverTimeTimerManager.start();
|
||||||
// 收到呼叫请求,跳转到接听页面
|
// 收到呼叫请求,跳转到接听页面
|
||||||
@ -123,12 +120,4 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
|
|||||||
// 修改预期数据并启动发送预期数据定时器,在收到回复时停止
|
// 修改预期数据并启动发送预期数据定时器,在收到回复时停止
|
||||||
startChartManage.sendOnlyImageVideoTalkExpectData();
|
startChartManage.sendOnlyImageVideoTalkExpectData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动通话保持,判断x秒内是否收到通话保持
|
|
||||||
void _handleStartTalkPing() {
|
|
||||||
// 启动通话保持
|
|
||||||
startChartManage.startTalkPingMessageTimer();
|
|
||||||
// 启动通话保持监听定时器(用来判断如果x秒内没有收到通话保持则执行的操作)
|
|
||||||
talkePingOverTimeTimerManager.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import 'package:get/get.dart';
|
|||||||
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
|
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
|
||||||
|
|
||||||
|
|
||||||
class TalkDataOverTimeTimerManager {
|
class TalkDataOverTimeTimerManager {
|
||||||
// 单例实例
|
// 单例实例
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
|
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
|
||||||
|
|
||||||
class TalkePingOverTimeTimerManager {
|
class TalkePingOverTimeTimerManager {
|
||||||
// 单例实例
|
// 单例实例
|
||||||
@ -41,6 +41,8 @@ class TalkePingOverTimeTimerManager {
|
|||||||
|
|
||||||
// 启动定时器
|
// 启动定时器
|
||||||
void start() {
|
void start() {
|
||||||
|
// 取消之前的定时器
|
||||||
|
_timer?.cancel();
|
||||||
_timer = Timer(timeout, onTimeout);
|
_timer = Timer(timeout, onTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
|
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
|
||||||
|
|
||||||
class TalkeRequestOverTimeTimerManager {
|
class TalkeRequestOverTimeTimerManager {
|
||||||
// 单例实例
|
// 单例实例
|
||||||
@ -31,6 +31,7 @@ class TalkeRequestOverTimeTimerManager {
|
|||||||
EasyLoading.showToast('通话未接通,以挂断', duration: 2000.milliseconds);
|
EasyLoading.showToast('通话未接通,以挂断', duration: 2000.milliseconds);
|
||||||
// 超时未接听,发送挂断请求
|
// 超时未接听,发送挂断请求
|
||||||
StartChartManage().sendTalkRejectMessage();
|
StartChartManage().sendTalkRejectMessage();
|
||||||
|
talkStatus.setInitializationCompleted();
|
||||||
Get.back();
|
Get.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,8 @@ import 'package:star_lock/talk/startChart/handle/other/talke_request_over_time_t
|
|||||||
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
|
|
||||||
|
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
|
||||||
|
|
||||||
class ScpMessageBaseHandle {
|
class ScpMessageBaseHandle {
|
||||||
/// 使用单例 TimerManager
|
/// 使用单例 TimerManager
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart';
|
import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart';
|
import 'package:star_lock/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart';
|
||||||
|
import 'package:star_lock/talk/startChart/handle/impl/udp_rbcuInfo_handler.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/impl/udp_talk_request_handler.dart';
|
import 'package:star_lock/talk/startChart/handle/impl/udp_talk_request_handler.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/impl/udp_echo_test_handler.dart';
|
import 'package:star_lock/talk/startChart/handle/impl/udp_echo_test_handler.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/impl/udp_gateway_reset_handler.dart';
|
import 'package:star_lock/talk/startChart/handle/impl/udp_gateway_reset_handler.dart';
|
||||||
@ -55,7 +56,7 @@ class ScpMessageHandlerFactory {
|
|||||||
case PayloadTypeConstant.talkHangup:
|
case PayloadTypeConstant.talkHangup:
|
||||||
return UdpTalkHangUpHandler();
|
return UdpTalkHangUpHandler();
|
||||||
case PayloadTypeConstant.RbcuInfo:
|
case PayloadTypeConstant.RbcuInfo:
|
||||||
return UdpTalkHangUpHandler();
|
return UdpRbcuInfoHandler();
|
||||||
default:
|
default:
|
||||||
return UnKnowPayloadTypeHandler();
|
return UnKnowPayloadTypeHandler();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,25 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
||||||
|
|
||||||
class P2pManage {
|
class P2pManage {
|
||||||
|
// 常量定义
|
||||||
|
static const String testMessage = 'Hello'; // 测试消息
|
||||||
|
static const int localPort = 0; // 绑定本地端口(0 表示由系统分配)
|
||||||
|
static const Duration connectionTimeout = Duration(seconds: 5); // 连接超时时间
|
||||||
|
static const List<String> localNetworkPrefixes = [
|
||||||
|
'192.168.',
|
||||||
|
'10.',
|
||||||
|
'172.'
|
||||||
|
]; // 局域网 IP 前缀
|
||||||
|
|
||||||
RbcuInfo? communicationObjectRbcuInfo;
|
RbcuInfo? communicationObjectRbcuInfo;
|
||||||
|
|
||||||
|
void init() {
|
||||||
void init(){
|
// 初始化逻辑
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 解析 address 属性,提取对方的 IP 和端口
|
// 解析 address 属性,提取对方的 IP 和端口
|
||||||
List<Map<String, String>> parseRemoteAddresses() {
|
List<Map<String, String>> parseRemoteAddresses() {
|
||||||
final addresses = communicationObjectRbcuInfo?.address ?? [];
|
final addresses = communicationObjectRbcuInfo?.address ?? [];
|
||||||
@ -18,4 +29,80 @@ class P2pManage {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否为局域网 IP
|
||||||
|
bool _isLocalNetworkIp(String ip) {
|
||||||
|
for (final prefix in localNetworkPrefixes) {
|
||||||
|
if (ip.startsWith(prefix)) {
|
||||||
|
// 处理 172.16.x.x 到 172.31.x.x
|
||||||
|
if (prefix == '172.') {
|
||||||
|
final secondOctet = int.tryParse(ip.split('.')[1]) ?? 0;
|
||||||
|
if (secondOctet >= 16 && secondOctet <= 31) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 UDP 连接
|
||||||
|
Future<void> createUdpConnection() async {
|
||||||
|
final addresses = parseRemoteAddresses();
|
||||||
|
|
||||||
|
// 优先使用局域网 IP
|
||||||
|
addresses.sort((a, b) {
|
||||||
|
final isALocal = _isLocalNetworkIp(a['ip']!);
|
||||||
|
final isBLocal = _isLocalNetworkIp(b['ip']!);
|
||||||
|
if (isALocal && !isBLocal) return -1; // a 是局域网 IP,优先级更高
|
||||||
|
if (!isALocal && isBLocal) return 1; // b 是局域网 IP,优先级更高
|
||||||
|
return 0; // 优先级相同
|
||||||
|
});
|
||||||
|
|
||||||
|
// 尝试连接
|
||||||
|
for (final addr in addresses) {
|
||||||
|
final ip = addr['ip']!;
|
||||||
|
final port = int.parse(addr['port']!);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final socket = await RawDatagramSocket.bind(
|
||||||
|
InternetAddress.anyIPv4, localPort); // 绑定本地端口
|
||||||
|
|
||||||
|
// 发送测试数据
|
||||||
|
final testData = testMessage.codeUnits;
|
||||||
|
socket.send(testData, InternetAddress(ip), port);
|
||||||
|
|
||||||
|
// 设置超时时间
|
||||||
|
final completer = Completer<void>();
|
||||||
|
|
||||||
|
// 监听响应
|
||||||
|
socket.listen((event) {
|
||||||
|
if (event == RawSocketEvent.read) {
|
||||||
|
final datagram = socket.receive();
|
||||||
|
if (datagram != null) {
|
||||||
|
final response = String.fromCharCodes(datagram.data);
|
||||||
|
print('收到来自 $ip:$port 的响应: $response');
|
||||||
|
completer.complete(); // 收到响应,完成 Future
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 等待响应或超时
|
||||||
|
try {
|
||||||
|
await completer.future.timeout(connectionTimeout);
|
||||||
|
print('成功连接到 $ip:$port');
|
||||||
|
return; // 连接成功,退出循环
|
||||||
|
} on TimeoutException {
|
||||||
|
print('连接到 $ip:$port 超时');
|
||||||
|
} finally {
|
||||||
|
socket.close(); // 关闭 socket
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('连接到 $ip:$port 失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('无法连接到任何地址');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,18 +17,27 @@ import 'ble_message.pbenum.dart';
|
|||||||
|
|
||||||
export 'ble_message.pbenum.dart';
|
export 'ble_message.pbenum.dart';
|
||||||
|
|
||||||
|
/// 用于蓝牙透传的数据结构
|
||||||
class BleReq extends $pb.GeneratedMessage {
|
class BleReq extends $pb.GeneratedMessage {
|
||||||
factory BleReq({
|
factory BleReq({
|
||||||
|
$core.int? timeout,
|
||||||
$core.String? bluetoothDeviceName,
|
$core.String? bluetoothDeviceName,
|
||||||
$core.List<$core.int>? structData,
|
$core.List<$core.int>? structData,
|
||||||
|
$core.int? idleTimeout,
|
||||||
}) {
|
}) {
|
||||||
final $result = create();
|
final $result = create();
|
||||||
|
if (timeout != null) {
|
||||||
|
$result.timeout = timeout;
|
||||||
|
}
|
||||||
if (bluetoothDeviceName != null) {
|
if (bluetoothDeviceName != null) {
|
||||||
$result.bluetoothDeviceName = bluetoothDeviceName;
|
$result.bluetoothDeviceName = bluetoothDeviceName;
|
||||||
}
|
}
|
||||||
if (structData != null) {
|
if (structData != null) {
|
||||||
$result.structData = structData;
|
$result.structData = structData;
|
||||||
}
|
}
|
||||||
|
if (idleTimeout != null) {
|
||||||
|
$result.idleTimeout = idleTimeout;
|
||||||
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
BleReq._() : super();
|
BleReq._() : super();
|
||||||
@ -36,8 +45,10 @@ class BleReq extends $pb.GeneratedMessage {
|
|||||||
factory BleReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
factory BleReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
|
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BleReq', package: const $pb.PackageName(_omitMessageNames ? '' : 'main'), createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BleReq', package: const $pb.PackageName(_omitMessageNames ? '' : 'main'), createEmptyInstance: create)
|
||||||
|
..a<$core.int>(1, _omitFieldNames ? '' : 'Timeout', $pb.PbFieldType.OU3, protoName: 'Timeout')
|
||||||
..aOS(2, _omitFieldNames ? '' : 'bluetoothDeviceName', protoName: 'bluetoothDeviceName')
|
..aOS(2, _omitFieldNames ? '' : 'bluetoothDeviceName', protoName: 'bluetoothDeviceName')
|
||||||
..a<$core.List<$core.int>>(3, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
|
..a<$core.List<$core.int>>(3, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
|
||||||
|
..a<$core.int>(6, _omitFieldNames ? '' : 'IdleTimeout', $pb.PbFieldType.OU3, protoName: 'IdleTimeout')
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -62,25 +73,45 @@ class BleReq extends $pb.GeneratedMessage {
|
|||||||
static BleReq getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BleReq>(create);
|
static BleReq getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BleReq>(create);
|
||||||
static BleReq? _defaultInstance;
|
static BleReq? _defaultInstance;
|
||||||
|
|
||||||
|
/// 扫描+发送+接受的总超时时间,单位为秒
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.int get timeout => $_getIZ(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set timeout($core.int v) { $_setUnsignedInt32(0, v); }
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasTimeout() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearTimeout() => clearField(1);
|
||||||
|
|
||||||
/// 用唯一的设备名来进行匹配而不是mac地址
|
/// 用唯一的设备名来进行匹配而不是mac地址
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
$core.String get bluetoothDeviceName => $_getSZ(0);
|
$core.String get bluetoothDeviceName => $_getSZ(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
set bluetoothDeviceName($core.String v) { $_setString(0, v); }
|
set bluetoothDeviceName($core.String v) { $_setString(1, v); }
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
$core.bool hasBluetoothDeviceName() => $_has(0);
|
$core.bool hasBluetoothDeviceName() => $_has(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
void clearBluetoothDeviceName() => clearField(2);
|
void clearBluetoothDeviceName() => clearField(2);
|
||||||
|
|
||||||
/// 下面是蓝牙结构内容,未加密状态
|
/// 下面是蓝牙结构内容,未加密状态
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$core.List<$core.int> get structData => $_getN(1);
|
$core.List<$core.int> get structData => $_getN(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
set structData($core.List<$core.int> v) { $_setBytes(1, v); }
|
set structData($core.List<$core.int> v) { $_setBytes(2, v); }
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
$core.bool hasStructData() => $_has(1);
|
$core.bool hasStructData() => $_has(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
void clearStructData() => clearField(3);
|
void clearStructData() => clearField(3);
|
||||||
|
|
||||||
|
/// 空闲断开时间(秒),0为立即断开
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
$core.int get idleTimeout => $_getIZ(3);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
set idleTimeout($core.int v) { $_setUnsignedInt32(3, v); }
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
$core.bool hasIdleTimeout() => $_has(3);
|
||||||
|
@$pb.TagNumber(6)
|
||||||
|
void clearIdleTimeout() => clearField(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BleResp extends $pb.GeneratedMessage {
|
class BleResp extends $pb.GeneratedMessage {
|
||||||
@ -103,7 +134,7 @@ class BleResp extends $pb.GeneratedMessage {
|
|||||||
|
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BleResp', package: const $pb.PackageName(_omitMessageNames ? '' : 'main'), createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BleResp', package: const $pb.PackageName(_omitMessageNames ? '' : 'main'), createEmptyInstance: create)
|
||||||
..e<BleResp_StatusE>(1, _omitFieldNames ? '' : 'Status', $pb.PbFieldType.OE, protoName: 'Status', defaultOrMaker: BleResp_StatusE.SUCCESS, valueOf: BleResp_StatusE.valueOf, enumValues: BleResp_StatusE.values)
|
..e<BleResp_StatusE>(1, _omitFieldNames ? '' : 'Status', $pb.PbFieldType.OE, protoName: 'Status', defaultOrMaker: BleResp_StatusE.SUCCESS, valueOf: BleResp_StatusE.valueOf, enumValues: BleResp_StatusE.values)
|
||||||
..a<$core.List<$core.int>>(4, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
|
..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -138,15 +169,15 @@ class BleResp extends $pb.GeneratedMessage {
|
|||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
void clearStatus() => clearField(1);
|
void clearStatus() => clearField(1);
|
||||||
|
|
||||||
/// 下面是蓝牙结构内容,未加密状态
|
/// 下面是蓝牙结构内容
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(2)
|
||||||
$core.List<$core.int> get structData => $_getN(1);
|
$core.List<$core.int> get structData => $_getN(1);
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(2)
|
||||||
set structData($core.List<$core.int> v) { $_setBytes(1, v); }
|
set structData($core.List<$core.int> v) { $_setBytes(1, v); }
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(2)
|
||||||
$core.bool hasStructData() => $_has(1);
|
$core.bool hasStructData() => $_has(1);
|
||||||
@$pb.TagNumber(4)
|
@$pb.TagNumber(2)
|
||||||
void clearStructData() => clearField(4);
|
void clearStructData() => clearField(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,16 +18,16 @@ class BleResp_StatusE extends $pb.ProtobufEnum {
|
|||||||
static const BleResp_StatusE SUCCESS = BleResp_StatusE._(0, _omitEnumNames ? '' : 'SUCCESS');
|
static const BleResp_StatusE SUCCESS = BleResp_StatusE._(0, _omitEnumNames ? '' : 'SUCCESS');
|
||||||
static const BleResp_StatusE FAIL = BleResp_StatusE._(1, _omitEnumNames ? '' : 'FAIL');
|
static const BleResp_StatusE FAIL = BleResp_StatusE._(1, _omitEnumNames ? '' : 'FAIL');
|
||||||
static const BleResp_StatusE NOT_FOUND = BleResp_StatusE._(2, _omitEnumNames ? '' : 'NOT_FOUND');
|
static const BleResp_StatusE NOT_FOUND = BleResp_StatusE._(2, _omitEnumNames ? '' : 'NOT_FOUND');
|
||||||
static const BleResp_StatusE CANNOT_CONNECT = BleResp_StatusE._(3, _omitEnumNames ? '' : 'CANNOT_CONNECT');
|
static const BleResp_StatusE CONNECT_FAIL = BleResp_StatusE._(3, _omitEnumNames ? '' : 'CONNECT_FAIL');
|
||||||
static const BleResp_StatusE CANNOT_SEND = BleResp_StatusE._(4, _omitEnumNames ? '' : 'CANNOT_SEND');
|
static const BleResp_StatusE SEND_FAIL = BleResp_StatusE._(4, _omitEnumNames ? '' : 'SEND_FAIL');
|
||||||
static const BleResp_StatusE TIMEOUT = BleResp_StatusE._(5, _omitEnumNames ? '' : 'TIMEOUT');
|
static const BleResp_StatusE TIMEOUT = BleResp_StatusE._(5, _omitEnumNames ? '' : 'TIMEOUT');
|
||||||
|
|
||||||
static const $core.List<BleResp_StatusE> values = <BleResp_StatusE> [
|
static const $core.List<BleResp_StatusE> values = <BleResp_StatusE> [
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
FAIL,
|
FAIL,
|
||||||
NOT_FOUND,
|
NOT_FOUND,
|
||||||
CANNOT_CONNECT,
|
CONNECT_FAIL,
|
||||||
CANNOT_SEND,
|
SEND_FAIL,
|
||||||
TIMEOUT,
|
TIMEOUT,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -19,20 +19,23 @@ const BleReq$json = {
|
|||||||
'2': [
|
'2': [
|
||||||
{'1': 'bluetoothDeviceName', '3': 2, '4': 1, '5': 9, '10': 'bluetoothDeviceName'},
|
{'1': 'bluetoothDeviceName', '3': 2, '4': 1, '5': 9, '10': 'bluetoothDeviceName'},
|
||||||
{'1': 'StructData', '3': 3, '4': 1, '5': 12, '10': 'StructData'},
|
{'1': 'StructData', '3': 3, '4': 1, '5': 12, '10': 'StructData'},
|
||||||
|
{'1': 'Timeout', '3': 1, '4': 1, '5': 13, '10': 'Timeout'},
|
||||||
|
{'1': 'IdleTimeout', '3': 6, '4': 1, '5': 13, '10': 'IdleTimeout'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `BleReq`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `BleReq`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List bleReqDescriptor = $convert.base64Decode(
|
final $typed_data.Uint8List bleReqDescriptor = $convert.base64Decode(
|
||||||
'CgZCbGVSZXESMAoTYmx1ZXRvb3RoRGV2aWNlTmFtZRgCIAEoCVITYmx1ZXRvb3RoRGV2aWNlTm'
|
'CgZCbGVSZXESMAoTYmx1ZXRvb3RoRGV2aWNlTmFtZRgCIAEoCVITYmx1ZXRvb3RoRGV2aWNlTm'
|
||||||
'FtZRIeCgpTdHJ1Y3REYXRhGAMgASgMUgpTdHJ1Y3REYXRh');
|
'FtZRIeCgpTdHJ1Y3REYXRhGAMgASgMUgpTdHJ1Y3REYXRhEhgKB1RpbWVvdXQYASABKA1SB1Rp'
|
||||||
|
'bWVvdXQSIAoLSWRsZVRpbWVvdXQYBiABKA1SC0lkbGVUaW1lb3V0');
|
||||||
|
|
||||||
@$core.Deprecated('Use bleRespDescriptor instead')
|
@$core.Deprecated('Use bleRespDescriptor instead')
|
||||||
const BleResp$json = {
|
const BleResp$json = {
|
||||||
'1': 'BleResp',
|
'1': 'BleResp',
|
||||||
'2': [
|
'2': [
|
||||||
{'1': 'Status', '3': 1, '4': 1, '5': 14, '6': '.main.BleResp.StatusE', '10': 'Status'},
|
{'1': 'Status', '3': 1, '4': 1, '5': 14, '6': '.main.BleResp.StatusE', '10': 'Status'},
|
||||||
{'1': 'StructData', '3': 4, '4': 1, '5': 12, '10': 'StructData'},
|
{'1': 'StructData', '3': 2, '4': 1, '5': 12, '10': 'StructData'},
|
||||||
],
|
],
|
||||||
'4': [BleResp_StatusE$json],
|
'4': [BleResp_StatusE$json],
|
||||||
};
|
};
|
||||||
@ -44,8 +47,8 @@ const BleResp_StatusE$json = {
|
|||||||
{'1': 'SUCCESS', '2': 0},
|
{'1': 'SUCCESS', '2': 0},
|
||||||
{'1': 'FAIL', '2': 1},
|
{'1': 'FAIL', '2': 1},
|
||||||
{'1': 'NOT_FOUND', '2': 2},
|
{'1': 'NOT_FOUND', '2': 2},
|
||||||
{'1': 'CANNOT_CONNECT', '2': 3},
|
{'1': 'CONNECT_FAIL', '2': 3},
|
||||||
{'1': 'CANNOT_SEND', '2': 4},
|
{'1': 'SEND_FAIL', '2': 4},
|
||||||
{'1': 'TIMEOUT', '2': 5},
|
{'1': 'TIMEOUT', '2': 5},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -53,7 +56,7 @@ const BleResp_StatusE$json = {
|
|||||||
/// Descriptor for `BleResp`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `BleResp`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List bleRespDescriptor = $convert.base64Decode(
|
final $typed_data.Uint8List bleRespDescriptor = $convert.base64Decode(
|
||||||
'CgdCbGVSZXNwEi0KBlN0YXR1cxgBIAEoDjIVLm1haW4uQmxlUmVzcC5TdGF0dXNFUgZTdGF0dX'
|
'CgdCbGVSZXNwEi0KBlN0YXR1cxgBIAEoDjIVLm1haW4uQmxlUmVzcC5TdGF0dXNFUgZTdGF0dX'
|
||||||
'MSHgoKU3RydWN0RGF0YRgEIAEoDFIKU3RydWN0RGF0YSJhCgdTdGF0dXNFEgsKB1NVQ0NFU1MQ'
|
'MSHgoKU3RydWN0RGF0YRgCIAEoDFIKU3RydWN0RGF0YSJdCgdTdGF0dXNFEgsKB1NVQ0NFU1MQ'
|
||||||
'ABIICgRGQUlMEAESDQoJTk9UX0ZPVU5EEAISEgoOQ0FOTk9UX0NPTk5FQ1QQAxIPCgtDQU5OT1'
|
'ABIICgRGQUlMEAESDQoJTk9UX0ZPVU5EEAISEAoMQ09OTkVDVF9GQUlMEAMSDQoJU0VORF9GQU'
|
||||||
'RfU0VORBAEEgsKB1RJTUVPVVQQBQ==');
|
'lMEAQSCwoHVElNRU9VVBAF');
|
||||||
|
|
||||||
|
|||||||
@ -3,26 +3,29 @@ package main;
|
|||||||
option go_package = "./spb";
|
option go_package = "./spb";
|
||||||
|
|
||||||
// 用于蓝牙透传的数据结构
|
// 用于蓝牙透传的数据结构
|
||||||
|
|
||||||
message BleReq {
|
message BleReq {
|
||||||
// 用唯一的设备名来进行匹配而不是mac地址
|
// 用唯一的设备名来进行匹配而不是mac地址
|
||||||
string bluetoothDeviceName = 2;
|
string bluetoothDeviceName = 2;
|
||||||
// 下面是蓝牙结构内容,未加密状态
|
// 下面是蓝牙结构内容,未加密状态
|
||||||
bytes StructData = 3;
|
bytes StructData = 3;
|
||||||
|
// 扫描+发送+接受的总超时时间,单位为秒
|
||||||
|
uint32 Timeout = 1;
|
||||||
|
// 空闲断开时间(秒),0为立即断开
|
||||||
|
uint32 IdleTimeout = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BleResp {
|
message BleResp {
|
||||||
// 定义一个枚举状态【成功,失败,找不到设备,无法建立连接,无法发送数据,超时】
|
// 定义一个枚举状态【成功,失败,找不到设备,无法建立连接,无法发送数据,超时】
|
||||||
enum StatusE {
|
enum StatusE {
|
||||||
SUCCESS = 0;
|
SUCCESS = 0; // 成功
|
||||||
FAIL = 1;
|
FAIL = 1; // 其他失败(需要错误消息)
|
||||||
NOT_FOUND = 2;
|
NOT_FOUND = 2; // 找不到设备
|
||||||
CANNOT_CONNECT = 3;
|
CONNECT_FAIL = 3; // 建立连接失败
|
||||||
CANNOT_SEND = 4;
|
SEND_FAIL = 4; // 发送数据失败
|
||||||
TIMEOUT = 5;
|
TIMEOUT = 5; // 超时
|
||||||
}
|
}
|
||||||
// 状态
|
// 状态
|
||||||
StatusE Status = 1;
|
StatusE Status = 1;
|
||||||
// 下面是蓝牙结构内容,未加密状态
|
// 下面是蓝牙结构内容
|
||||||
bytes StructData = 4;
|
bytes StructData = 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
|||||||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_expect.pbserver.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_expect.pbserver.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
|
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
|
||||||
import 'package:star_lock/tools/baseGetXController.dart';
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
import 'package:star_lock/tools/deviceInfo_utils.dart';
|
import 'package:star_lock/tools/deviceInfo_utils.dart';
|
||||||
import 'package:star_lock/tools/storage.dart';
|
import 'package:star_lock/tools/storage.dart';
|
||||||
@ -221,7 +221,8 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送RbcuInfo 地址交换消息
|
// 发送RbcuInfo 地址交换消息
|
||||||
void _sendRbcuInfoMessage() async {
|
void _sendRbcuInfoMessage(
|
||||||
|
{required String ToPeerId, bool isResp = false}) async {
|
||||||
final uuid = _uuid.v1();
|
final uuid = _uuid.v1();
|
||||||
final int timestamp = DateTime.now().millisecondsSinceEpoch;
|
final int timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||||
final Int64 int64Timestamp = Int64(timestamp); // 使用构造函数
|
final Int64 int64Timestamp = Int64(timestamp); // 使用构造函数
|
||||||
@ -252,7 +253,7 @@ class StartChartManage {
|
|||||||
name: uuid,
|
name: uuid,
|
||||||
address: address,
|
address: address,
|
||||||
time: int64Timestamp,
|
time: int64Timestamp,
|
||||||
isResp: false,
|
isResp: isResp,
|
||||||
);
|
);
|
||||||
final message = MessageCommand.genericRbcuInfoMessage(
|
final message = MessageCommand.genericRbcuInfoMessage(
|
||||||
ToPeerId: ToPeerId,
|
ToPeerId: ToPeerId,
|
||||||
@ -264,12 +265,12 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 启动定时任务
|
// 启动定时任务
|
||||||
void startSendingRbcuInfoMessages() {
|
void startSendingRbcuInfoMessages({required String ToPeerId}) {
|
||||||
// 每隔 1 秒执行一次 _sendRbcuInfoMessage
|
// 每隔 1 秒执行一次 _sendRbcuInfoMessage
|
||||||
rbcuInfoTimer ??=
|
rbcuInfoTimer ??=
|
||||||
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
||||||
// 发送RbcuInfo 地址交换消息
|
// 发送RbcuInfo 地址交换消息
|
||||||
_sendRbcuInfoMessage();
|
_sendRbcuInfoMessage(ToPeerId: ToPeerId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +280,11 @@ class StartChartManage {
|
|||||||
rbcuInfoTimer = null;
|
rbcuInfoTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 回复RbcuInfo
|
||||||
|
void replyRbcuInfoMessage({required String ToPeerId}) {
|
||||||
|
_sendRbcuInfoMessage(ToPeerId: ToPeerId, isResp: true);
|
||||||
|
}
|
||||||
|
|
||||||
// 发送上线消息
|
// 发送上线消息
|
||||||
Future<void> _sendOnlineMessage() async {
|
Future<void> _sendOnlineMessage() async {
|
||||||
if (isOnlineStartChartServer) {
|
if (isOnlineStartChartServer) {
|
||||||
@ -329,7 +335,7 @@ class StartChartManage {
|
|||||||
MessageCommand.getNextMessageId(ToPeerId, increment: false);
|
MessageCommand.getNextMessageId(ToPeerId, increment: false);
|
||||||
// 组装分包数据
|
// 组装分包数据
|
||||||
final message = MessageCommand.talkDataMessage(
|
final message = MessageCommand.talkDataMessage(
|
||||||
ToPeerId: ToPeerId,
|
ToPeerId: 'D78Fo4CjNzUXz8DxuUhLtcRpnGFXhSzhzs191XzhJttS',
|
||||||
FromPeerId: FromPeerId,
|
FromPeerId: FromPeerId,
|
||||||
payload: packet,
|
payload: packet,
|
||||||
SpTotal: totalPackets,
|
SpTotal: totalPackets,
|
||||||
@ -891,8 +897,36 @@ class StartChartManage {
|
|||||||
talkExpect: talkExpectReq);
|
talkExpect: talkExpectReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 发送远程开锁
|
||||||
|
void sendRemoteUnLockMessage({
|
||||||
|
required String bluetoothDeviceName,
|
||||||
|
required List<int> openLockCommand,
|
||||||
|
}) {
|
||||||
|
sendBleMessage(
|
||||||
|
bluetoothDeviceName: bluetoothDeviceName,
|
||||||
|
bleStructData: openLockCommand,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 发送蓝牙透传消息
|
||||||
|
void sendBleMessage({
|
||||||
|
required String bluetoothDeviceName,
|
||||||
|
required List<int> bleStructData,
|
||||||
|
}) {
|
||||||
|
// 组装上线消息
|
||||||
|
final message = MessageCommand.bleMessage(
|
||||||
|
FromPeerId: FromPeerId,
|
||||||
|
ToPeerId: ToPeerId,
|
||||||
|
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
|
||||||
|
bluetoothDeviceName: bluetoothDeviceName,
|
||||||
|
bleStructData: bleStructData,
|
||||||
|
);
|
||||||
|
_sendMessage(message: message);
|
||||||
|
}
|
||||||
|
|
||||||
/// 销毁资源
|
/// 销毁资源
|
||||||
void destruction() async {
|
void destruction() async {
|
||||||
|
sendTalkHangupMessage();
|
||||||
isOnlineStartChartServer = false;
|
isOnlineStartChartServer = false;
|
||||||
stopHeartbeat();
|
stopHeartbeat();
|
||||||
stopTalkExpectMessageTimer();
|
stopTalkExpectMessageTimer();
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class AppLifecycleObserver extends WidgetsBindingObserver {
|
|||||||
void onAppPaused() {
|
void onAppPaused() {
|
||||||
// 处理应用程序进入后台的逻辑
|
// 处理应用程序进入后台的逻辑
|
||||||
print('App has entered the background.');
|
print('App has entered the background.');
|
||||||
StartChartManage().destruction();
|
// StartChartManage().destruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAppResumed() {
|
void onAppResumed() {
|
||||||
@ -16,6 +16,13 @@ import 'package:image_gallery_saver/image_gallery_saver.dart';
|
|||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:star_lock/app_settings/app_settings.dart';
|
import 'package:star_lock/app_settings/app_settings.dart';
|
||||||
|
import 'package:star_lock/blue/blue_manage.dart';
|
||||||
|
import 'package:star_lock/blue/io_protocol/io_openLock.dart';
|
||||||
|
import 'package:star_lock/blue/io_tool/io_tool.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_logic.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_state.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/lockDetail/lockNetToken_entity.dart';
|
||||||
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
|
|
||||||
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||||||
@ -24,12 +31,16 @@ import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
|
|||||||
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
|
||||||
|
|
||||||
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
|
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
|
||||||
|
import 'package:star_lock/talk/udp/udp_manage.dart';
|
||||||
|
import 'package:star_lock/talk/udp/udp_senderManage.dart';
|
||||||
|
import 'package:star_lock/tools/bugly/bugly_tool.dart';
|
||||||
|
import 'package:star_lock/tools/storage.dart';
|
||||||
|
|
||||||
import '../../../../tools/baseGetXController.dart';
|
import '../../../../tools/baseGetXController.dart';
|
||||||
|
|
||||||
class TalkViewLogic extends BaseGetXController {
|
class TalkViewLogic extends BaseGetXController {
|
||||||
final TalkViewState state = TalkViewState();
|
final TalkViewState state = TalkViewState();
|
||||||
|
final LockDetailState lockDetailState = Get.find<LockDetailLogic>().state;
|
||||||
Timer? _syncTimer; // 音视频播放刷新率定时器
|
Timer? _syncTimer; // 音视频播放刷新率定时器
|
||||||
int _startTime = 0; // 开始播放时间戳,用于判断帧数据中的时间戳位置
|
int _startTime = 0; // 开始播放时间戳,用于判断帧数据中的时间戳位置
|
||||||
final int bufferSize = 20; // 缓冲区大小(以帧为单位)
|
final int bufferSize = 20; // 缓冲区大小(以帧为单位)
|
||||||
@ -258,7 +269,61 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 开门
|
/// 开门
|
||||||
udpOpenDoorAction(List<int> list) async {}
|
udpOpenDoorAction() async {
|
||||||
|
final List<String>? privateKey =
|
||||||
|
await Storage.getStringList(saveBluePrivateKey);
|
||||||
|
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||||
|
|
||||||
|
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
|
||||||
|
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||||
|
|
||||||
|
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
||||||
|
final List<int> getTokenList = changeStringListToIntList(token!);
|
||||||
|
|
||||||
|
await _getLockNetToken();
|
||||||
|
|
||||||
|
final OpenLockCommand openLockCommand = OpenLockCommand(
|
||||||
|
lockID: BlueManage().connectDeviceName,
|
||||||
|
userID: await Storage.getUid(),
|
||||||
|
openMode: lockDetailState.openDoorModel,
|
||||||
|
openTime: _getUTCNetTime(),
|
||||||
|
onlineToken: lockDetailState.lockNetToken,
|
||||||
|
token: getTokenList,
|
||||||
|
needAuthor: 1,
|
||||||
|
signKey: signKeyDataList,
|
||||||
|
privateKey: getPrivateKeyList,
|
||||||
|
);
|
||||||
|
final messageDetail = openLockCommand.messageDetail();
|
||||||
|
// 发送远程开门消息
|
||||||
|
StartChartManage().sendRemoteUnLockMessage(
|
||||||
|
bluetoothDeviceName: BlueManage().connectDeviceName,
|
||||||
|
openLockCommand: messageDetail,
|
||||||
|
);
|
||||||
|
showToast('已发送开门通知');
|
||||||
|
}
|
||||||
|
|
||||||
|
int _getUTCNetTime() {
|
||||||
|
if (lockDetailState.isHaveNetwork) {
|
||||||
|
return DateTime.now().millisecondsSinceEpoch ~/ 1000 +
|
||||||
|
lockDetailState.differentialTime;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取手机联网token,根据锁设置里面获取的开锁时是否联网来判断是否调用这个接口
|
||||||
|
Future<void> _getLockNetToken() async {
|
||||||
|
final LockNetTokenEntity entity = await ApiRepository.to.getLockNetToken(
|
||||||
|
lockId: lockDetailState.keyInfos.value.lockId.toString());
|
||||||
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
|
lockDetailState.lockNetToken = entity.data!.token!.toString();
|
||||||
|
AppLog.log('从服务器获取联网token:${lockDetailState.lockNetToken}');
|
||||||
|
} else {
|
||||||
|
BuglyTool.uploadException(
|
||||||
|
message: '点击了需要联网开锁', detail: '点击了需要联网开锁 获取连网token失败', upload: true);
|
||||||
|
showToast('网络访问失败,请检查网络是否正常'.tr, something: () {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 获取权限状态
|
/// 获取权限状态
|
||||||
Future<bool> getPermissionStatus() async {
|
Future<bool> getPermissionStatus() async {
|
||||||
@ -285,6 +350,55 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> requestPermissions() async {
|
||||||
|
// 申请存储权限
|
||||||
|
var storageStatus = await Permission.storage.request();
|
||||||
|
// 申请录音权限
|
||||||
|
var microphoneStatus = await Permission.microphone.request();
|
||||||
|
|
||||||
|
if (storageStatus.isGranted && microphoneStatus.isGranted) {
|
||||||
|
print("Permissions granted");
|
||||||
|
} else {
|
||||||
|
print("Permissions denied");
|
||||||
|
// 如果权限被拒绝,可以提示用户或跳转到设置页面
|
||||||
|
if (await Permission.storage.isPermanentlyDenied) {
|
||||||
|
openAppSettings(); // 跳转到应用设置页面
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> startRecording() async {
|
||||||
|
requestPermissions();
|
||||||
|
if (state.isRecordingScreen.value) {
|
||||||
|
showToast('录屏已开始,请勿重复点击');
|
||||||
|
}
|
||||||
|
bool start = await FlutterScreenRecording.startRecordScreen(
|
||||||
|
"Screen Recording", // 视频文件名
|
||||||
|
titleNotification: "Recording in progress", // 通知栏标题
|
||||||
|
messageNotification: "Tap to stop recording", // 通知栏内容
|
||||||
|
);
|
||||||
|
|
||||||
|
if (start) {
|
||||||
|
state.isRecordingScreen.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> stopRecording() async {
|
||||||
|
String path = await FlutterScreenRecording.stopRecordScreen;
|
||||||
|
print("Recording saved to: $path");
|
||||||
|
|
||||||
|
// 将视频保存到系统相册
|
||||||
|
bool? success = await GallerySaver.saveVideo(path);
|
||||||
|
if (success == true) {
|
||||||
|
print("Video saved to gallery");
|
||||||
|
} else {
|
||||||
|
print("Failed to save video to gallery");
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast('录屏结束,已保存到系统相册');
|
||||||
|
state.isRecordingScreen.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onReady() {
|
void onReady() {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
@ -310,12 +424,16 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 初始化录音控制器
|
// 初始化录音控制器
|
||||||
_initAudioRecorder();
|
_initAudioRecorder();
|
||||||
|
|
||||||
|
requestPermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
_stopPlayG711Data();
|
_stopPlayG711Data();
|
||||||
state.listData.value = Uint8List(0);
|
state.listData.value = Uint8List(0);
|
||||||
|
state.audioBuffer.clear();
|
||||||
|
state.videoBuffer.clear();
|
||||||
_syncTimer?.cancel();
|
_syncTimer?.cancel();
|
||||||
_syncTimer = null;
|
_syncTimer = null;
|
||||||
}
|
}
|
||||||
@ -387,32 +505,6 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 开始录屏
|
|
||||||
Future<void> startRecording() async {
|
|
||||||
getPermissionStatus();
|
|
||||||
bool started =
|
|
||||||
await FlutterScreenRecording.startRecordScreenAndAudio("Recording");
|
|
||||||
if (started) {
|
|
||||||
state.isRecordingScreen.value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 停止录屏
|
|
||||||
Future<void> stopRecording() async {
|
|
||||||
String path = await FlutterScreenRecording.stopRecordScreen;
|
|
||||||
if (path != null) {
|
|
||||||
state.isRecordingScreen.value = false;
|
|
||||||
// 保存录制的视频到相册
|
|
||||||
// await GallerySaver.saveVideo(path).then((bool? success) {});
|
|
||||||
// 将截图保存到相册
|
|
||||||
await ImageGallerySaver.saveFile(path);
|
|
||||||
showToast('录屏已保存到相册'.tr);
|
|
||||||
} else {
|
|
||||||
state.isRecordingScreen.value = false;
|
|
||||||
print("Recording failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 初始化音频录制器
|
/// 初始化音频录制器
|
||||||
void _initAudioRecorder() {
|
void _initAudioRecorder() {
|
||||||
state.voiceProcessor = VoiceProcessor.instance;
|
state.voiceProcessor = VoiceProcessor.instance;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
@ -15,6 +17,7 @@ import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
|||||||
|
|
||||||
import 'package:star_lock/talk/startChart/views/talkView/talk_view_logic.dart';
|
import 'package:star_lock/talk/startChart/views/talkView/talk_view_logic.dart';
|
||||||
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
|
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
|
||||||
|
import 'package:star_lock/talk/udp/udp_manage.dart';
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
import '../../../../app_settings/app_colors.dart';
|
||||||
import '../../../../tools/showTFView.dart';
|
import '../../../../tools/showTFView.dart';
|
||||||
@ -35,6 +38,7 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
state.listData.value = Uint8List(0);
|
||||||
//写一个定时器,三十秒后页面自动返回
|
//写一个定时器,三十秒后页面自动返回
|
||||||
// state.autoBackTimer = Timer(const Duration(seconds: 30), Get.back);
|
// state.autoBackTimer = Timer(const Duration(seconds: 30), Get.back);
|
||||||
|
|
||||||
@ -65,43 +69,61 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Obx(
|
Obx(
|
||||||
() => state.listData.value.isEmpty
|
() {
|
||||||
? Image.asset(
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
'images/main/monitorBg.png',
|
final screenHeight = MediaQuery.of(context).size.height;
|
||||||
width: ScreenUtil().screenWidth,
|
|
||||||
height: ScreenUtil().screenHeight,
|
final logicalWidth = MediaQuery.of(context).size.width;
|
||||||
fit: BoxFit.cover,
|
final logicalHeight = MediaQuery.of(context).size.height;
|
||||||
)
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
: Container(
|
|
||||||
decoration: state.isRecordingScreen.value
|
// 计算物理像素值
|
||||||
? BoxDecoration(
|
final physicalWidth = logicalWidth * devicePixelRatio;
|
||||||
border: Border.all(color: Colors.red, width: 1))
|
final physicalHeight = logicalHeight * devicePixelRatio;
|
||||||
: BoxDecoration(),
|
|
||||||
child: PopScope(
|
// 旋转后的图片尺寸
|
||||||
|
final rotatedImageWidth = 480; // 原始高度
|
||||||
|
final rotatedImageHeight = 864; // 原始宽度
|
||||||
|
|
||||||
|
// 计算缩放比例
|
||||||
|
final scaleWidth = physicalWidth / rotatedImageWidth;
|
||||||
|
final scaleHeight = physicalHeight / rotatedImageHeight;
|
||||||
|
final scale = max(scaleWidth, scaleHeight); // 选择较大的缩放比例
|
||||||
|
|
||||||
|
return state.listData.value.isEmpty
|
||||||
|
? Image.asset(
|
||||||
|
'images/main/monitorBg.png',
|
||||||
|
width: screenWidth,
|
||||||
|
height: screenHeight,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
: PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
key: state.globalKey,
|
key: state.globalKey,
|
||||||
child: RotatedBox(
|
child: Transform.rotate(
|
||||||
quarterTurns: 1, // 顺时针旋转 90 度(1 个四分之一圈)
|
angle:
|
||||||
child: Image.memory(
|
state.rotateAngle.value * (pi / 180), // 旋转 90 度
|
||||||
state.listData.value,
|
child: Transform.scale(
|
||||||
gaplessPlayback: true,
|
scale: scale, // 动态计算的缩放比例
|
||||||
width: 1.sw,
|
child: Image.memory(
|
||||||
height: 1.sh,
|
state.listData.value,
|
||||||
fit: BoxFit.cover,
|
gaplessPlayback: true,
|
||||||
filterQuality: FilterQuality.high,
|
fit: BoxFit.cover,
|
||||||
errorBuilder: (
|
filterQuality: FilterQuality.high,
|
||||||
BuildContext context,
|
errorBuilder: (
|
||||||
Object error,
|
BuildContext context,
|
||||||
StackTrace? stackTrace,
|
Object error,
|
||||||
) {
|
StackTrace? stackTrace,
|
||||||
return Container(color: Colors.transparent);
|
) {
|
||||||
},
|
return Container(color: Colors.transparent);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
Obx(() => state.listData.value.isEmpty
|
Obx(() => state.listData.value.isEmpty
|
||||||
? Positioned(
|
? Positioned(
|
||||||
@ -200,13 +222,12 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
logic.showToast('功能暂未开放'.tr);
|
logic.showToast('功能暂未开放'.tr);
|
||||||
// if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
// if (
|
||||||
|
// state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
||||||
// if (state.isRecordingScreen.value) {
|
// if (state.isRecordingScreen.value) {
|
||||||
// await logic.stopRecording();
|
// await logic.stopRecording();
|
||||||
// print('停止录屏');
|
|
||||||
// } else {
|
// } else {
|
||||||
// await logic.startRecording();
|
// await logic.startRecording();
|
||||||
// print('开始录屏');
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
@ -276,7 +297,14 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
'images/main/icon_lockDetail_monitoringUnlock.png',
|
'images/main/icon_lockDetail_monitoringUnlock.png',
|
||||||
'开锁',
|
'开锁',
|
||||||
AppColors.mainColor,
|
AppColors.mainColor,
|
||||||
onClick: () {},
|
onClick: () {
|
||||||
|
if (UDPManage().remoteUnlock == 1) {
|
||||||
|
logic.udpOpenDoorAction();
|
||||||
|
// showDeletPasswordAlertDialog(context);
|
||||||
|
} else {
|
||||||
|
logic.showToast('请在锁设置中开启远程开锁'.tr);
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -342,7 +370,7 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ShowTFView(
|
return ShowTFView(
|
||||||
title: '请输入六位数字开锁密码'.tr,
|
title: '请输入6位数字开锁密码'.tr,
|
||||||
tipTitle: '',
|
tipTitle: '',
|
||||||
controller: state.passwordTF,
|
controller: state.passwordTF,
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
@ -350,22 +378,23 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
FilteringTextInputFormatter.allow(RegExp('[0-9]')),
|
FilteringTextInputFormatter.allow(RegExp('[0-9]')),
|
||||||
],
|
],
|
||||||
sureClick: () async {
|
sureClick: () async {
|
||||||
// //发送删除锁请求
|
//发送删除锁请求
|
||||||
// if (state.passwordTF.text.isEmpty) {
|
// if (state.passwordTF.text.isEmpty) {
|
||||||
// logic.showToast('请输入开锁密码'.tr);
|
// logic.showToast('请输入开锁密码'.tr);
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// // List<int> numbers = state.passwordTF.text.split('').map((char) => int.parse(char)).toList();
|
// List<int> numbers = state.passwordTF.text.split('').map((char) => int.parse(char)).toList();
|
||||||
// // 开锁
|
// 开锁
|
||||||
// // lockID
|
// lockID
|
||||||
// List<int> numbers = <int>[];
|
// final List<int> numbers = <int>[];
|
||||||
// List<int> lockIDData = utf8.encode(state.passwordTF.text);
|
// final List<int> lockIDData = utf8.encode(state.passwordTF.text);
|
||||||
// numbers.addAll(lockIDData);
|
// numbers.addAll(lockIDData);
|
||||||
// // topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length);
|
// // topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length);
|
||||||
// for (int i = 0; i < 6 - lockIDData.length; i++) {
|
// for (int i = 0; i < 6 - lockIDData.length; i++) {
|
||||||
// numbers.add(0);
|
// numbers.add(0);
|
||||||
// }
|
// }
|
||||||
|
logic.udpOpenDoorAction();
|
||||||
},
|
},
|
||||||
cancelClick: () {
|
cancelClick: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
@ -409,6 +438,8 @@ class _TalkViewPageState extends State<TalkViewPage>
|
|||||||
state.animationController.dispose();
|
state.animationController.dispose();
|
||||||
state.realTimePicTimer.cancel();
|
state.realTimePicTimer.cancel();
|
||||||
state.autoBackTimer.cancel();
|
state.autoBackTimer.cancel();
|
||||||
|
state.videoBuffer.clear();
|
||||||
|
state.listData.value = Uint8List(0);
|
||||||
CallTalk().finishAVData();
|
CallTalk().finishAVData();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import 'package:network_info_plus/network_info_plus.dart';
|
|||||||
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
|
||||||
import 'package:star_lock/talk/startChart/handle/other/talk_data_repository.dart';
|
import 'package:star_lock/talk/startChart/handle/other/talk_data_repository.dart';
|
||||||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||||||
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
|
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
|
||||||
|
|
||||||
import '../../../../tools/storage.dart';
|
import '../../../../tools/storage.dart';
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user