import 'dart:async'; import 'dart:typed_data'; import 'package:crypto/crypto.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.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_getDeviceModel.dart'; import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart'; import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart'; import 'package:star_lock/blue/io_protocol/io_voicePackageConfigure.dart'; import 'package:star_lock/blue/io_protocol/io_voicePackageConfigureProcess.dart'; import 'package:star_lock/blue/io_reply.dart'; import 'package:star_lock/blue/io_tool/io_tool.dart'; import 'package:star_lock/blue/io_tool/manager_event_bus.dart'; import 'package:star_lock/login/login/entity/LoginEntity.dart'; import 'package:star_lock/login/selectCountryRegion/common/index.dart'; import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart'; import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_state.dart'; import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/baseGetXController.dart'; import 'package:http/http.dart' as http; import 'package:star_lock/tools/commonDataManage.dart'; import 'package:star_lock/tools/eventBusEventManage.dart'; import 'package:star_lock/tools/storage.dart'; class SpeechLanguageSettingsLogic extends BaseGetXController { final SpeechLanguageSettingsState state = SpeechLanguageSettingsState(); StreamSubscription? _replySubscription; @override void onInit() async { super.onInit(); _replySubscription = EventBusManager().eventBus!.on().listen((Reply reply) async { if (reply is GetDeviceModelReply) { // 获取设备型号 _handlerDeviceModelReply(reply); } if (reply is VoicePackageConfigureReply) { // 语言包配置开始 _handlerStartVoicePackageConfigure(reply); } else if (reply is VoicePackageConfigureProcessReply) { _handlerVoicePackageConfigureProcess(reply); } else if (reply is VoicePackageConfigureConfirmationReply) { final PassthroughItem item = state.languages[state.selectPassthroughListIndex.value]; final timbre = item.timbres[state.selectLanguageIndex.value]; final LoginEntity entity = await ApiRepository.to.settingCurrentVoiceTimbre( data: { 'lang': item.lang, 'timbre': timbre.timbre, }, lockId: state.lockSetInfoData.value.lockId!, ); if (entity.errorCode!.codeIsSuccessful) { showSuccess('设置成功'.tr, something: () { state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre ?.lang = item.lang; state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre ?.timbre = timbre.timbre; eventBus.fire( PassCurrentLockInformationEvent(state.lockSetInfoData.value)); }); } dismissEasyLoading(); } }); state.deviceModel.value = await Storage.getString(deviceModel) ?? ''; debugPrint('设备型号:${state.deviceModel.value}'); if (state.deviceModel.value != null) { await initList(); } // await sendGetDeviceModelBleMessage(); } @override void onClose() { _replySubscription?.cancel(); } /// 获取列表 initList() async { showEasyLoading(); try { final PassthroughListResponse entity = await ApiRepository.to .getPassthroughList(data: {'deviceType': state.deviceModel.value}); if (entity.errorCode!.codeIsSuccessful) { state.languages.value = entity.data!!; final oldTimbre = state .lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre; final oldLang = state .lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang; for (int index = 0; index < state.languages.value.length; index++) { final element = state.languages.value[index]; final timbres = element.timbres; for (int i = 0; i < timbres.length; i++) { final timbre = timbres[i].timbre; if ((oldLang != null && oldLang == element.lang) && (oldTimbre != null && oldTimbre == timbre)) { state.selectPassthroughListIndex.value = index; state.selectLanguageIndex.value = i; } } } } } catch (e) { debugPrint('获取语音包出现错误:$e'); } finally { dismissEasyLoading(); } } void saveSpeechLanguageSettings() async { // 如果已经开始发送中则不处理保存点击事件 if (state.progress.value > 0) { return; } final oldTimbre = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre; final oldLang = state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang; EasyLoading.showProgress(state.progress.value, status: '正在发送数据'); final PassthroughItem item = state.languages[state.selectPassthroughListIndex.value]; final timbre = item.timbres[state.selectLanguageIndex.value]; debugPrint('选中的语音是:${timbre}'); if ((oldLang != null && oldLang == item.lang) && (oldTimbre != null && oldTimbre == timbre.timbre)) { showToast('已设置为当前选择的语音包'.tr); } await downloadFile(timbre.timbrePackUrl); } void changeSelectIndex(int index) { state.selectLanguageIndex.value = index; } //下载语音包 Future downloadFile(String url) async { final http.Response response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { state.data = response.bodyBytes; sendFileToDevice(response.bodyBytes, [0, 0, 0, 0]); } } sendFileToDevice(Uint8List data, List token) { showEasyLoading(); showBlueConnetctToastTimer(action: () { dismissEasyLoading(); }); BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async { if (deviceConnectionState == BluetoothConnectionState.connected) { final List? privateKey = await Storage.getStringList(saveBluePrivateKey); final List getPrivateKeyList = changeStringListToIntList(privateKey!); final List? signKey = await Storage.getStringList(saveBlueSignKey); final List signKeyDataList = changeStringListToIntList(signKey!); final String uid = await Storage.getUid() ?? ''; final String md5Str = md5.convert(data).toString().toUpperCase(); BlueManage().writeCharacteristicWithResponse( VoicePackageConfigure( lockID: BlueManage().connectDeviceName, userID: uid, keyID: BlueManage().connectDeviceName, platform: 0, product: 0, fwSize: data.length, fwMD5: md5Str, needAuthor: 1, token: token, signKey: signKeyDataList, privateKey: getPrivateKeyList) .packageData(), ); } else if (deviceConnectionState == BluetoothConnectionState.disconnected) {} }); } // 发送获取型号蓝牙命令 sendGetDeviceModelBleMessage() { showEasyLoading(); showBlueConnetctToastTimer(action: () { dismissEasyLoading(); }); BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async { if (deviceConnectionState == BluetoothConnectionState.connected) { BlueManage().writeCharacteristicWithResponse( GetDeviceModelCommand( lockID: BlueManage().connectDeviceName, ).packageData(), ); } else if (deviceConnectionState == BluetoothConnectionState.disconnected) { dismissEasyLoading(); cancelBlueConnetctToastTimer(); showBlueConnetctToast(); } }); } void _handlerDeviceModelReply(GetDeviceModelReply reply) async { final int status = reply.data[2]; switch (status) { case 0x00: //成功 cancelBlueConnetctToastTimer(); // 3. 解析DeviceModel(40字节,索引3~42) int startIndex = 3; int length = 40; List deviceModelBytes = reply.data.sublist(startIndex, startIndex + length); String rawData = String.fromCharCodes(deviceModelBytes); int firstNullIndex = rawData.indexOf('\u0000'); String deviceModel = rawData.substring(0, firstNullIndex); print(deviceModel); // 输出: 2403 print('获取到 DeviceModel (原始): $deviceModel'); state.deviceModel.value = deviceModel; await initList(); break; default: showToast('获取设备型号失败'.tr); break; } } // 开始配置语音包 void _handlerStartVoicePackageConfigure( VoicePackageConfigureReply reply) async { final int status = reply.data[6]; switch (status) { case 0x00: //成功 cancelBlueConnetctToastTimer(); _startSendLanguageFile(); break; case 0x06: //无权限 final List token = reply.data.sublist(2, 6); print('收到token:$token'); if (state.data != null) { sendFileToDevice(state.data!, token); } break; default: showToast('获取设备型号失败'.tr); break; } } void _startSendLanguageFile() { if (state.data == null) return; state.voiceSubcontractingIndex = 0; state.voiceSubcontractingCount = (state.data!.length + state.voiceSubcontractingSize - 1) ~/ state.voiceSubcontractingSize; state.progress.value = 0.0; // 开始前重置进度 _sendNextPackage(); } void _sendNextPackage() { if (state.voiceSubcontractingIndex >= state.voiceSubcontractingCount) { print('所有分包已发送完成'); state.progress.value = 1.0; // 发送完成 // 可在此处通知UI或做后续处理 return; } int start = state.voiceSubcontractingIndex * state.voiceSubcontractingSize; int end = start + state.voiceSubcontractingSize; if (end > state.data!.length) end = state.data!.length; Uint8List packageData = state.data!.sublist(start, end); // 更新分包进度 state.progress.value = (state.voiceSubcontractingIndex + 1) / state.voiceSubcontractingCount; EasyLoading.showProgress(state.progress.value, status: '正在发送数据 ${(state.progress.value * 100).toStringAsFixed(0)}%'); _sendLanguageFileBleMessage( index: state.voiceSubcontractingIndex, data: packageData, ); } _sendLanguageFileBleMessage({required int index, required Uint8List data}) { BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async { if (deviceConnectionState == BluetoothConnectionState.connected) { BlueManage().writeCharacteristicWithResponse( VoicePackageConfigureProcess( index: index, size: data.length, data: data, ).packageData(), ); } else if (deviceConnectionState == BluetoothConnectionState.disconnected) { dismissEasyLoading(); cancelBlueConnetctToastTimer(); showBlueConnetctToast(); } }); } void _handlerVoicePackageConfigureProcess( VoicePackageConfigureProcessReply reply) { final int status = reply.data[2]; switch (status) { case 0x00: cancelBlueConnetctToastTimer(); state.voiceSubcontractingIndex++; _sendNextPackage(); break; default: showToast('发送分包数据不成功'.tr); break; } } @override void dispose() async { super.dispose(); await _replySubscription?.cancel(); _replySubscription = null; await BlueManage().disconnect(); dismissEasyLoading(); cancelBlueConnetctToastTimer(); EasyLoading.dismiss(); // 清理分包相关状态 state.progress.value = 0.0; state.voiceSubcontractingIndex = 0; state.voiceSubcontractingCount = 0; state.data = null; } }