Merge branch 'develop_sky' into 'canary_release_sky'

Develop sky

See merge request StarlockTeam/app-starlock!274
This commit is contained in:
李仪 2025-09-04 09:19:35 +00:00
commit 472a6f20d3
6 changed files with 103 additions and 82 deletions

View File

@ -144,7 +144,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver, BaseWidget {
break; break;
case AppLifecycleState.paused: case AppLifecycleState.paused:
// AppLog.log('App--->进入后台'); // AppLog.log('App--->进入后台');
BlueManage().disconnect(); BlueManage.instance.disconnect();
break; break;
case AppLifecycleState.resumed: case AppLifecycleState.resumed:
// AppLog.log('App--->进入前台'); // AppLog.log('App--->进入前台');

View File

@ -85,6 +85,12 @@ class BlueManage {
return _manager; return _manager;
} }
// 访
static BlueManage get instance {
_manager ??= BlueManage._init();
return _manager!;
}
BlueManage? get manager => shareManager(); BlueManage? get manager => shareManager();
void _initBlue() { void _initBlue() {
@ -94,9 +100,13 @@ class BlueManage {
} }
void _initGetMtuSubscription() { void _initGetMtuSubscription() {
_mtuSubscription ??= bluetoothConnectDevice!.mtu.listen((int value) { //
_mtuSubscription?.cancel();
_mtuSubscription = null;
_mtuSubscription = bluetoothConnectDevice!.mtu.listen((int value) {
_mtuSize = value - 3; _mtuSize = value - 3;
AppLog.log('_mtuSizeValue:$value mtuSize:$_mtuSize'); AppLog.log('设备MTU变化 - 原始值:$value 计算后MTU:$_mtuSize 设备:${bluetoothConnectDevice?.remoteId.str}');
}); });
} }
@ -954,6 +964,12 @@ class BlueManage {
Future<void> disconnect() async { Future<void> disconnect() async {
try { try {
connectDeviceMacAddress = ''; connectDeviceMacAddress = '';
// MTU监听
_mtuSubscription?.cancel();
_mtuSubscription = null;
_mtuSize = 20; // MTU为默认值
if (bluetoothConnectionState == BluetoothConnectionState.connected) { if (bluetoothConnectionState == BluetoothConnectionState.connected) {
// //
await bluetoothConnectDevice!.disconnect(timeout: 3); await bluetoothConnectDevice!.disconnect(timeout: 3);
@ -975,10 +991,29 @@ class BlueManage {
} }
} }
// MTU信息
String getMtuDebugInfo() {
return 'MTU Debug Info:\n'
'- Current MTU Size: $_mtuSize\n'
'- Connected Device: ${bluetoothConnectDevice?.remoteId.str ?? "None"}\n'
'- Device Name: $connectDeviceName\n'
'- Connection State: $bluetoothConnectionState\n'
'- MTU Subscription Active: ${_mtuSubscription != null}';
}
void disposed() { void disposed() {
_sendStreamSubscription?.cancel(); _sendStreamSubscription?.cancel();
_mtuSubscription!.cancel(); _mtuSubscription?.cancel();
_adapterStateStateSubscription!.cancel(); _adapterStateStateSubscription?.cancel();
_connectionStateSubscription!.cancel(); _connectionStateSubscription?.cancel();
//
_mtuSize = 20;
connectDeviceName = '';
connectDeviceMacAddress = '';
bluetoothConnectDevice = null;
scanDevices.clear();
allData.clear();
lastTimeData.clear();
} }
} }

View File

@ -439,9 +439,24 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
_handlerVoicePackageConfigureConfirmation( _handlerVoicePackageConfigureConfirmation(
VoicePackageConfigureConfirmationReply reply, VoicePackageConfigureConfirmationReply reply,
) async { ) async {
final int status = reply.data[2]; showEasyLoading();
switch (status) { showBlueConnetctToastTimer(action: () {
case 0x00: dismissEasyLoading();
});
final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre(
data: {
'lang': state.tempLangStr.value,
'timbre': state.tempTimbreStr.value,
},
lockId: state.lockSetInfoData.value.lockId!,
);
if (entity.errorCode!.codeIsSuccessful) {
showSuccess('设置成功'.tr, something: () async {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang =
state.tempLangStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value;
await BlueManage().blueSendData(BlueManage().connectDeviceName, await BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async { (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) { if (deviceConnectionState == BluetoothConnectionState.connected) {
@ -458,10 +473,8 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
showBlueConnetctToast(); showBlueConnetctToast();
} }
}); });
break; await Future.delayed(Duration(seconds: 1));
default: });
showToast('设置'.tr + '失败'.tr);
break;
} }
} }
@ -470,24 +483,6 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
switch (status) { switch (status) {
case 0x00: case 0x00:
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
final LoginEntity entity =
await ApiRepository.to.settingCurrentVoiceTimbre(
data: {
'lang': state.tempLangStr.value,
'timbre': state.tempTimbreStr.value,
},
lockId: state.lockSetInfoData.value.lockId!,
);
if (entity.errorCode!.codeIsSuccessful) {
showSuccess('设置成功'.tr, something: () {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.lang = state.tempLangStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value;
eventBus.fire(
PassCurrentLockInformationEvent(state.lockSetInfoData.value));
});
}
dismissEasyLoading(); dismissEasyLoading();
break; break;
default: default:
@ -522,7 +517,6 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
languageCode = languageCode =
languageCode.replaceAll('\u0000', ''); // (null bytes) languageCode.replaceAll('\u0000', ''); // (null bytes)
if (languageCode != null && languageCode != '') { if (languageCode != null && languageCode != '') {
final indexWhere = state.languages final indexWhere = state.languages
.indexWhere((element) => element.lang == languageCode); .indexWhere((element) => element.lang == languageCode);

View File

@ -64,7 +64,7 @@ class _SpeechLanguageSettingsPageState
return CommonItem( return CommonItem(
leftTitel: soundType, leftTitel: soundType,
leftTitleStyle: TextStyle( leftTitleStyle: TextStyle(
fontSize: 22.sp, fontSize: 20.sp,
fontWeight: state.selectSoundTypeIndex.value == index fontWeight: state.selectSoundTypeIndex.value == index
? FontWeight.bold ? FontWeight.bold
: null, : null,
@ -111,7 +111,7 @@ class _SpeechLanguageSettingsPageState
return CommonItem( return CommonItem(
leftTitel: item.langText, leftTitel: item.langText,
leftTitleStyle: TextStyle( leftTitleStyle: TextStyle(
fontSize: 22.sp, fontSize: 20.sp,
fontWeight: state.selectPassthroughListIndex.value == index fontWeight: state.selectPassthroughListIndex.value == index
? FontWeight.bold ? FontWeight.bold
: null, : null,

View File

@ -84,22 +84,42 @@ class LockVoiceSettingLogic extends BaseGetXController {
showBlueConnetctToastTimer(action: () { showBlueConnetctToastTimer(action: () {
dismissEasyLoading(); dismissEasyLoading();
}); });
await BlueManage().blueSendData(BlueManage().connectDeviceName, final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre(
(BluetoothConnectionState deviceConnectionState) async { data: {
if (deviceConnectionState == BluetoothConnectionState.connected) { 'lang': state.tempLangStr.value,
await BlueManage().writeCharacteristicWithResponse( 'timbre': state.tempTimbreStr.value,
SetVoicePackageFinalResult( },
lockID: BlueManage().connectDeviceName, lockId: state.lockSetInfoData.value.lockId!,
languageCode: state.tempLangStr.value, );
).packageData(), if (entity.errorCode!.codeIsSuccessful) {
); showSuccess('设置成功'.tr, something: () async {
} else if (deviceConnectionState == state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang =
BluetoothConnectionState.disconnected) { state.tempLangStr.value;
dismissEasyLoading(); state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
cancelBlueConnetctToastTimer(); ?.timbre = state.tempTimbreStr.value;
showBlueConnetctToast();
} await BlueManage().blueSendData(BlueManage().connectDeviceName,
}); (BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
await BlueManage().writeCharacteristicWithResponse(
SetVoicePackageFinalResult(
lockID: BlueManage().connectDeviceName,
languageCode: state.tempLangStr.value,
).packageData(),
);
} else if (deviceConnectionState ==
BluetoothConnectionState.disconnected) {
dismissEasyLoading();
cancelBlueConnetctToastTimer();
showBlueConnetctToast();
}
});
await Future.delayed(Duration(seconds: 1));
eventBus
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
Get.offAllNamed(Routers.starLockMain);
});
}
} }
void handleSetResult(SetVoicePackageFinalResultReply reply) async { void handleSetResult(SetVoicePackageFinalResultReply reply) async {
@ -107,26 +127,6 @@ class LockVoiceSettingLogic extends BaseGetXController {
switch (status) { switch (status) {
case 0x00: case 0x00:
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
final LoginEntity entity =
await ApiRepository.to.settingCurrentVoiceTimbre(
data: {
'lang': state.tempLangStr.value,
'timbre': state.tempTimbreStr.value,
},
lockId: state.lockSetInfoData.value.lockId!,
);
if (entity.errorCode!.codeIsSuccessful) {
showSuccess('设置成功'.tr, something: () {
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.lang = state.tempLangStr.value;
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
?.timbre = state.tempTimbreStr.value;
eventBus.fire(
PassCurrentLockInformationEvent(state.lockSetInfoData.value));
Get.offAllNamed(Routers.starLockMain);
});
}
dismissEasyLoading(); dismissEasyLoading();
break; break;
default: default:
@ -473,33 +473,25 @@ class LockVoiceSettingLogic extends BaseGetXController {
// //
cancelBlueConnetctToastTimer(); cancelBlueConnetctToastTimer();
// 1. LanguageCode
// CmdID (2 bytes) + Status (1 byte) = 3 bytes -> LanguageCode 3
const int languageCodeStartIndex = 3; const int languageCodeStartIndex = 3;
const int languageCodeLength = 20; const int languageCodeLength = 20;
const int languageCodeEndIndex = const int languageCodeEndIndex =
languageCodeStartIndex + languageCodeLength; // 23 languageCodeStartIndex + languageCodeLength; // 23
// 2.
if (reply.data.length < languageCodeEndIndex) { if (reply.data.length < languageCodeEndIndex) {
throw Exception( throw Exception(
'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}'); 'Reply data is too short to contain LanguageCode. Expected at least $languageCodeEndIndex bytes, got ${reply.data.length}');
} }
// 3. LanguageCode
List<int> languageCodeBytes = List<int> languageCodeBytes =
reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex); reply.data.sublist(languageCodeStartIndex, languageCodeEndIndex);
// 4.
// UTF-8 ASCII
String languageCode = String.fromCharCodes(languageCodeBytes); String languageCode = String.fromCharCodes(languageCodeBytes);
// 5. () '\0'
// 20 '\0'
languageCode = languageCode.trim(); // languageCode = languageCode.trim(); //
languageCode = languageCode =
languageCode.replaceAll('\u0000', ''); // (null bytes) languageCode.replaceAll('\u0000', ''); // (null bytes)
// 6. 使 languageCode
print('LanguageCode: $languageCode'); // : zh_CN, en_US print('LanguageCode: $languageCode'); // : zh_CN, en_US
if (languageCode != null && languageCode != '') { if (languageCode != null && languageCode != '') {

View File

@ -96,7 +96,7 @@ class _LockVoiceSettingState extends State<LockVoiceSetting> {
return CommonItem( return CommonItem(
leftTitel: soundType, leftTitel: soundType,
leftTitleStyle: TextStyle( leftTitleStyle: TextStyle(
fontSize: 22.sp, fontSize: 20.sp,
fontWeight: state.selectSoundTypeIndex.value == index fontWeight: state.selectSoundTypeIndex.value == index
? FontWeight.bold ? FontWeight.bold
: null, : null,
@ -142,7 +142,7 @@ class _LockVoiceSettingState extends State<LockVoiceSetting> {
return CommonItem( return CommonItem(
leftTitel: item.langText, leftTitel: item.langText,
leftTitleStyle: TextStyle( leftTitleStyle: TextStyle(
fontSize: 22.sp, fontSize: 20.sp,
fontWeight: fontWeight:
state.selectPassthroughListIndex.value == index state.selectPassthroughListIndex.value == index
? FontWeight.bold ? FontWeight.bold
@ -152,7 +152,7 @@ class _LockVoiceSettingState extends State<LockVoiceSetting> {
isHaveLine: true, isHaveLine: true,
isHaveDirection: false, isHaveDirection: false,
isHaveRightWidget: true, isHaveRightWidget: true,
leftTitleMaxWidth: 0.9.sw, leftTitleMaxWidth: 0.85.sw,
rightWidget: rightWidget:
state.selectPassthroughListIndex.value == index state.selectPassthroughListIndex.value == index
? Image( ? Image(