fix:增加添加锁时配置语音包的页面
This commit is contained in:
parent
ccad385a80
commit
b2952b3c72
@ -42,6 +42,7 @@ import 'package:star_lock/main/lockDetail/palm/palmList/palmList_page.dart';
|
|||||||
import 'package:star_lock/main/lockDetail/passwordKey/passwordKeyDetailChangeDate/passwordKeyDetailChangeDate_page.dart';
|
import 'package:star_lock/main/lockDetail/passwordKey/passwordKeyDetailChangeDate/passwordKeyDetailChangeDate_page.dart';
|
||||||
import 'package:star_lock/main/lockMian/lockMain/xhj/lockMain_xhj_page.dart';
|
import 'package:star_lock/main/lockMian/lockMain/xhj/lockMain_xhj_page.dart';
|
||||||
import 'package:star_lock/mine/about/webviewShow_page.dart';
|
import 'package:star_lock/mine/about/webviewShow_page.dart';
|
||||||
|
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_page.dart';
|
||||||
import 'package:star_lock/mine/mine/safeVerify/safeVerify_page.dart';
|
import 'package:star_lock/mine/mine/safeVerify/safeVerify_page.dart';
|
||||||
import 'package:star_lock/mine/minePersonInfo/minePersonInfoEmail/mineBindPhoneOrEmail_page.dart';
|
import 'package:star_lock/mine/minePersonInfo/minePersonInfoEmail/mineBindPhoneOrEmail_page.dart';
|
||||||
import 'package:star_lock/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_entity.dart';
|
import 'package:star_lock/mine/minePersonInfo/minePersonInfoPage/minePersonInfo_entity.dart';
|
||||||
@ -527,6 +528,8 @@ abstract class Routers {
|
|||||||
'/imageTransmissionView'; //星图对讲页面(图传)
|
'/imageTransmissionView'; //星图对讲页面(图传)
|
||||||
static const String permissionGuidancePage =
|
static const String permissionGuidancePage =
|
||||||
'/permissionGuidancePage'; // 锁屏权限通知引导页面
|
'/permissionGuidancePage'; // 锁屏权限通知引导页面
|
||||||
|
static const String lockVoiceSettingPage =
|
||||||
|
'/lockVoiceSetting'; // 锁屏权限通知引导页面
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AppRouters {
|
abstract class AppRouters {
|
||||||
@ -1214,6 +1217,9 @@ abstract class AppRouters {
|
|||||||
GetPage<dynamic>(
|
GetPage<dynamic>(
|
||||||
name: Routers.permissionGuidancePage,
|
name: Routers.permissionGuidancePage,
|
||||||
page: () => PermissionGuidancePage()),
|
page: () => PermissionGuidancePage()),
|
||||||
|
GetPage<dynamic>(
|
||||||
|
name: Routers.lockVoiceSettingPage,
|
||||||
|
page: () => LockVoiceSetting()),
|
||||||
// 插件播放页面
|
// 插件播放页面
|
||||||
// GetPage<dynamic>(name: Routers.h264View, page: () => H264WebView()), // webview播放页面
|
// GetPage<dynamic>(name: Routers.h264View, page: () => H264WebView()), // webview播放页面
|
||||||
];
|
];
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter/scheduler.dart';
|
|||||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:star_lock/apm/apm_helper.dart';
|
import 'package:star_lock/apm/apm_helper.dart';
|
||||||
|
import 'package:star_lock/blue/io_protocol/io_getDeviceModel.dart';
|
||||||
import 'package:star_lock/login/login/entity/LoginEntity.dart';
|
import 'package:star_lock/login/login/entity/LoginEntity.dart';
|
||||||
import 'package:star_lock/main/lockMian/entity/lockListInfo_entity.dart';
|
import 'package:star_lock/main/lockMian/entity/lockListInfo_entity.dart';
|
||||||
|
|
||||||
@ -66,6 +67,11 @@ class LockSetLogic extends BaseGetXController {
|
|||||||
(state.ifCurrentScreen.value == true)) {
|
(state.ifCurrentScreen.value == true)) {
|
||||||
_replyUpdataLockSetReply(reply);
|
_replyUpdataLockSetReply(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reply is GetDeviceModelReply) {
|
||||||
|
// 获取设备型号
|
||||||
|
_handlerDeviceModelReply(reply);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,6 +734,7 @@ class LockSetLogic extends BaseGetXController {
|
|||||||
|
|
||||||
getUpdataLockSet();
|
getUpdataLockSet();
|
||||||
_initReplySubscription();
|
_initReplySubscription();
|
||||||
|
sendGetDeviceModelBleMessage();
|
||||||
// _scanListDiscoveredDeviceSubscriptionAction();
|
// _scanListDiscoveredDeviceSubscriptionAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,4 +744,52 @@ class LockSetLogic extends BaseGetXController {
|
|||||||
_passCurrentLockInformationEvent!.cancel();
|
_passCurrentLockInformationEvent!.cancel();
|
||||||
// _scanListDiscoveredDeviceSubscription.cancel();
|
// _scanListDiscoveredDeviceSubscription.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送获取型号蓝牙命令
|
||||||
|
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<int> deviceModelBytes =
|
||||||
|
reply.data.sublist(startIndex, startIndex + length);
|
||||||
|
|
||||||
|
String rawData = String.fromCharCodes(deviceModelBytes);
|
||||||
|
int firstNullIndex = rawData.indexOf('\u0000');
|
||||||
|
String deviceModelValue = rawData.substring(0, firstNullIndex);
|
||||||
|
print(deviceModelValue); // 输出: 2403
|
||||||
|
print('获取到 DeviceModel (原始): $deviceModelValue');
|
||||||
|
await Storage.setString(deviceModel, deviceModelValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showToast('获取设备型号失败'.tr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,16 +60,23 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
|
|||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
showSuccess('设置成功'.tr, something: () {
|
showSuccess('设置成功'.tr, something: () {
|
||||||
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.lang=item.lang;
|
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
|
||||||
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre?.timbre=timbre.timbre;
|
?.lang = item.lang;
|
||||||
eventBus
|
state.lockSetInfoData.value.lockSettingInfo?.currentVoiceTimbre
|
||||||
.fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value));
|
?.timbre = timbre.timbre;
|
||||||
|
eventBus.fire(
|
||||||
|
PassCurrentLockInformationEvent(state.lockSetInfoData.value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await sendGetDeviceModelBleMessage();
|
state.deviceModel.value = await Storage.getString(deviceModel) ?? '';
|
||||||
|
debugPrint('设备型号:${state.deviceModel.value}');
|
||||||
|
if (state.deviceModel.value != null) {
|
||||||
|
await initList();
|
||||||
|
}
|
||||||
|
// await sendGetDeviceModelBleMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -146,6 +153,10 @@ class SpeechLanguageSettingsLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendFileToDevice(Uint8List data, List<int> token) {
|
sendFileToDevice(Uint8List data, List<int> token) {
|
||||||
|
showEasyLoading();
|
||||||
|
showBlueConnetctToastTimer(action: () {
|
||||||
|
dismissEasyLoading();
|
||||||
|
});
|
||||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||||
(BluetoothConnectionState deviceConnectionState) async {
|
(BluetoothConnectionState deviceConnectionState) async {
|
||||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:star_lock/app_settings/app_colors.dart';
|
|||||||
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||||
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_logic.dart';
|
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_logic.dart';
|
||||||
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_state.dart';
|
import 'package:star_lock/main/lockDetail/lockSet/speechLanguageSettings/speech_language_settings_state.dart';
|
||||||
|
import 'package:star_lock/tools/EasyRefreshTool.dart';
|
||||||
import 'package:star_lock/tools/titleAppBar.dart';
|
import 'package:star_lock/tools/titleAppBar.dart';
|
||||||
|
|
||||||
class SpeechLanguageSettingsPage extends StatefulWidget {
|
class SpeechLanguageSettingsPage extends StatefulWidget {
|
||||||
@ -46,7 +47,12 @@ class _SpeechLanguageSettingsPageState
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: _buildBody(),
|
body: EasyRefreshTool(
|
||||||
|
child: _buildBody(),
|
||||||
|
onRefresh: () {
|
||||||
|
logic.sendGetDeviceModelBleMessage();
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +127,6 @@ class _SpeechLanguageSettingsPageState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
// TODO: implement dispose
|
// TODO: implement dispose
|
||||||
|
|||||||
@ -0,0 +1,332 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:crypto/crypto.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/blue/blue_manage.dart';
|
||||||
|
import 'package:star_lock/blue/io_protocol/io_getDeviceModel.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/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||||
|
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_state.dart';
|
||||||
|
import 'package:star_lock/network/api_repository.dart';
|
||||||
|
import 'package:star_lock/tools/baseGetXController.dart';
|
||||||
|
import 'package:star_lock/tools/eventBusEventManage.dart';
|
||||||
|
import 'package:star_lock/tools/storage.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
class LockVoiceSettingLogic extends BaseGetXController {
|
||||||
|
LockVoiceSettingState state = LockVoiceSettingState();
|
||||||
|
StreamSubscription<Reply>? _replySubscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() async {
|
||||||
|
super.onInit();
|
||||||
|
_replySubscription =
|
||||||
|
EventBusManager().eventBus!.on<Reply>().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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await sendGetDeviceModelBleMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载语音包
|
||||||
|
Future<void> 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, <int>[0, 0, 0, 0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendFileToDevice(Uint8List data, List<int> token) {
|
||||||
|
showEasyLoading();
|
||||||
|
showBlueConnetctToastTimer(action: () {
|
||||||
|
dismissEasyLoading();
|
||||||
|
});
|
||||||
|
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||||
|
(BluetoothConnectionState deviceConnectionState) async {
|
||||||
|
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||||
|
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 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) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handlerVoicePackageConfigureProcess(
|
||||||
|
VoicePackageConfigureProcessReply reply) {
|
||||||
|
final int status = reply.data[2];
|
||||||
|
switch (status) {
|
||||||
|
case 0x00:
|
||||||
|
cancelBlueConnetctToastTimer();
|
||||||
|
state.voiceSubcontractingIndex++;
|
||||||
|
_sendNextPackage();
|
||||||
|
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<int> token = reply.data.sublist(2, 6);
|
||||||
|
print('收到token:$token');
|
||||||
|
if (state.data != null) {
|
||||||
|
sendFileToDevice(state.data!, token);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showToast('获取设备型号失败'.tr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<int> 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 (原始): $deviceModel');
|
||||||
|
state.deviceModel.value = deviceModel;
|
||||||
|
await initList();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showToast('获取设备型号失败'.tr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取列表
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送获取型号蓝牙命令
|
||||||
|
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 _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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
150
lib/mine/addLock/lock_voice_setting/lock_voice_setting_page.dart
Normal file
150
lib/mine/addLock/lock_voice_setting/lock_voice_setting_page.dart
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:get/get_utils/get_utils.dart';
|
||||||
|
import 'package:star_lock/appRouters.dart';
|
||||||
|
import 'package:star_lock/app_settings/app_colors.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||||
|
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_logic.dart';
|
||||||
|
import 'package:star_lock/mine/addLock/lock_voice_setting/lock_voice_setting_state.dart';
|
||||||
|
import 'package:star_lock/tools/EasyRefreshTool.dart';
|
||||||
|
import 'package:star_lock/tools/titleAppBar.dart';
|
||||||
|
|
||||||
|
class LockVoiceSetting extends StatefulWidget {
|
||||||
|
const LockVoiceSetting();
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LockVoiceSetting> createState() => _LockVoiceSettingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LockVoiceSettingState extends State<LockVoiceSetting> {
|
||||||
|
final LockVoiceSettingLogic logic = Get.put(LockVoiceSettingLogic());
|
||||||
|
final LockVoiceSettingState state = Get.find<LockVoiceSettingLogic>().state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return EasyRefreshTool(
|
||||||
|
onRefresh: () {
|
||||||
|
logic.sendGetDeviceModelBleMessage();
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: AppColors.mainBackgroundColor,
|
||||||
|
appBar: TitleAppBar(
|
||||||
|
barTitle: '锁语音包设置'.tr,
|
||||||
|
haveBack: false,
|
||||||
|
haveOtherLeftWidget: true,
|
||||||
|
leftWidget: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.offAllNamed(Routers.starLockMain);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'跳过',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 24.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.mainColor,
|
||||||
|
actionsList: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: logic.saveSpeechLanguageSettings,
|
||||||
|
child: Text(
|
||||||
|
'保存'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 24.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: _buildBody(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBody() {
|
||||||
|
return Obx(
|
||||||
|
() => SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: _buildList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _buildList() {
|
||||||
|
final languages = state.languages;
|
||||||
|
return List.generate(
|
||||||
|
languages.length,
|
||||||
|
(index) => _buildItem(languages[index], index),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildItem(PassthroughItem language, int index) {
|
||||||
|
final timbres = language.timbres;
|
||||||
|
final isSelected = state.selectPassthroughListIndex == index;
|
||||||
|
return ExpansionTile(
|
||||||
|
title: Text(
|
||||||
|
PassthroughLangHelper.getLangText(language.lang),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24.sp,
|
||||||
|
fontWeight: isSelected ? FontWeight.bold : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onExpansionChanged: (bool expanded) {},
|
||||||
|
initiallyExpanded: false,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
collapsedBackgroundColor: Colors.white,
|
||||||
|
expandedCrossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
expandedAlignment: Alignment.center,
|
||||||
|
shape: InputBorder.none,
|
||||||
|
maintainState: true,
|
||||||
|
// 去除展开状态下的边框
|
||||||
|
collapsedShape: InputBorder.none,
|
||||||
|
// 去除折叠状态下的边框
|
||||||
|
childrenPadding: EdgeInsets.only(left: 12.w),
|
||||||
|
children: List.generate(
|
||||||
|
timbres.length,
|
||||||
|
(int languageIndex) => ListTile(
|
||||||
|
title: Text(
|
||||||
|
timbres[languageIndex].name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22.sp,
|
||||||
|
fontWeight:
|
||||||
|
state.selectLanguageIndex == languageIndex && isSelected
|
||||||
|
? FontWeight.bold
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailing: state.selectLanguageIndex == languageIndex && isSelected
|
||||||
|
? Icon(
|
||||||
|
Icons.check_circle,
|
||||||
|
color: AppColors.mainColor,
|
||||||
|
) // 仅当选中时显示图标
|
||||||
|
: null, // 默认不显示
|
||||||
|
onTap: () {
|
||||||
|
// 更新选中的语音包
|
||||||
|
state.selectLanguageIndex.value = languageIndex;
|
||||||
|
// 更新选中的语言
|
||||||
|
state.selectPassthroughListIndex.value = index;
|
||||||
|
}, // 默认图标, // 右侧的图标
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
if (EasyLoading.isShow) {
|
||||||
|
EasyLoading.dismiss(animation: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/lockDetail/passthrough_item.dart';
|
||||||
|
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
|
||||||
|
|
||||||
|
class LockVoiceSettingState {
|
||||||
|
LockVoiceSettingState() {
|
||||||
|
final map = Get.arguments;
|
||||||
|
lockSetInfoData.value = map['lockSetInfoData'];
|
||||||
|
|
||||||
|
lockBasicInfo.value = lockSetInfoData.value.lockBasicInfo!;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
|
||||||
|
Rx<LockBasicInfo> lockBasicInfo = LockBasicInfo().obs;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 选中的语音包列表下标
|
||||||
|
RxInt selectPassthroughListIndex = 0.obs;
|
||||||
|
|
||||||
|
// 选中的语音下标
|
||||||
|
RxInt selectLanguageIndex = 0.obs;
|
||||||
|
|
||||||
|
final RxList<PassthroughItem> languages = <PassthroughItem>[].obs;
|
||||||
|
|
||||||
|
Map<int, String> languageSpeechDeviceTypeMapping = {0: '2403'};
|
||||||
|
|
||||||
|
RxBool otaUpdateIng = false.obs;
|
||||||
|
RxDouble otaProgress = 0.00.obs;
|
||||||
|
RxString deviceModel = '2403'.obs;
|
||||||
|
Uint8List? data;
|
||||||
|
|
||||||
|
// 语音包最大大小
|
||||||
|
int voiceSubcontractingSize = 256;
|
||||||
|
|
||||||
|
// 总数据包数量
|
||||||
|
int voiceSubcontractingCount = 0;
|
||||||
|
|
||||||
|
// 数据包序列号
|
||||||
|
int voiceSubcontractingIndex = 0;
|
||||||
|
|
||||||
|
// 分包发送进度(0.0~1.0)
|
||||||
|
RxDouble progress = 0.0.obs;
|
||||||
|
|
||||||
|
}
|
||||||
@ -486,7 +486,6 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
void backAction() async {
|
void backAction() async {
|
||||||
|
|
||||||
// BlueManage().disconnect();
|
// BlueManage().disconnect();
|
||||||
|
|
||||||
// 查询锁设置信息
|
// 查询锁设置信息
|
||||||
@ -502,13 +501,19 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
'lockSetInfoData': state.lockSetInfoData.value,
|
'lockSetInfoData': state.lockSetInfoData.value,
|
||||||
'pageName': 'saveLock'
|
'pageName': 'saveLock'
|
||||||
});
|
});
|
||||||
|
} else if (state.lockSetInfoData.value.lockFeature?.languageSpeech == 1) {
|
||||||
|
Get.toNamed(Routers.lockVoiceSettingPage, arguments: {
|
||||||
|
'lockSetInfoData': state.lockSetInfoData.value,
|
||||||
|
'pageName': 'saveLock'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true,isUnShowLoading: true));
|
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||||
|
clearScanDevices: true, isUnShowLoading: true));
|
||||||
Future<void>.delayed(const Duration(seconds: 1), () {
|
Future<void>.delayed(const Duration(seconds: 1), () {
|
||||||
// Get.close(state.isFromMap == 1
|
// Get.close(state.isFromMap == 1
|
||||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
||||||
// : (CommonDataManage().seletLockType == 0 ? 5 : 6));
|
// : (CommonDataManage().seletLockType == 0 ? 5 : 6));
|
||||||
Get.until((route) => route.isFirst);
|
Get.until((route) => route.isFirst);
|
||||||
});
|
});
|
||||||
//刚刚配对完,需要对开锁页锁死 2 秒
|
//刚刚配对完,需要对开锁页锁死 2 秒
|
||||||
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
||||||
@ -520,7 +525,8 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true,isUnShowLoading: true));
|
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||||
|
clearScanDevices: true, isUnShowLoading: true));
|
||||||
Future<void>.delayed(const Duration(seconds: 1), () {
|
Future<void>.delayed(const Duration(seconds: 1), () {
|
||||||
// Get.close(state.isFromMap == 1
|
// Get.close(state.isFromMap == 1
|
||||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
||||||
|
|||||||
@ -40,6 +40,7 @@ const String lockNetWorkInfo = 'lockNetWorkInfo'; //锁板配网信息
|
|||||||
|
|
||||||
const String appVersionHistoryUrl = 'appVersionHistoryUrl'; //是否同意隐私协议弹窗
|
const String appVersionHistoryUrl = 'appVersionHistoryUrl'; //是否同意隐私协议弹窗
|
||||||
const String voipToken = 'voipToken'; //是否同意隐私协议弹窗
|
const String voipToken = 'voipToken'; //是否同意隐私协议弹窗
|
||||||
|
const String deviceModel = 'deviceModel'; //设备型号
|
||||||
|
|
||||||
class Storage {
|
class Storage {
|
||||||
factory Storage() => _instance;
|
factory Storage() => _instance;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user