diff --git a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart index 25c8e43d..a940ca4e 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_logic.dart @@ -37,15 +37,24 @@ import 'configuringWifi_state.dart'; class ConfiguringWifiLogic extends BaseGetXController { final ConfiguringWifiState state = ConfiguringWifiState(); + final int _configurationTimeout = 60; // 配网超时时间(秒) + /// 获取WiFi锁服务IP和端口 Future getWifiLockServiceIpAndPort() async { - final ConfiguringWifiEntity entity = - await ApiRepository.to.getWifiLockServiceIpAndPort(); - if (entity.errorCode! == 0) { - state.configuringWifiEntity.value = entity; + try { + final ConfiguringWifiEntity entity = + await ApiRepository.to.getWifiLockServiceIpAndPort(); + if (entity.errorCode! == 0) { + state.configuringWifiEntity.value = entity; + } else { + AppLog.log('获取WiFi锁服务IP和端口失败:${entity.errorCode}'); + } + } catch (e) { + AppLog.log('获取WiFi锁服务IP和端口异常:$e'); } } + /// 更新网络信息到服务器 void updateNetworkInfo({ required String peerId, required String wifiName, @@ -53,24 +62,36 @@ class ConfiguringWifiLogic extends BaseGetXController { required String deviceMac, required String networkMac, }) async { - final LoginEntity entity = await ApiRepository.to.settingDeviceNetwork( - deviceType: 2, - deviceMac: deviceMac, - wifiName: wifiName, - networkMac: networkMac, - secretKey: secretKey, - peerId: peerId, - ); - if (entity.errorCode!.codeIsSuccessful) { - // 设置锁的peerID - StartChartManage().lockNetworkInfo = DeviceNetworkInfo( + try { + final LoginEntity entity = await ApiRepository.to.settingDeviceNetwork( + deviceType: 2, + deviceMac: deviceMac, wifiName: wifiName, networkMac: networkMac, secretKey: secretKey, peerId: peerId, ); - await _getUploadLockSet(); + if (entity.errorCode!.codeIsSuccessful) { + // 设置锁的peerID + StartChartManage().lockNetworkInfo = DeviceNetworkInfo( + wifiName: wifiName, + networkMac: networkMac, + secretKey: secretKey, + peerId: peerId, + ); + + await _getUploadLockSet(); + } else { + dismissEasyLoading(); + showToast('网络配置失败,请重试'.tr); + state.sureBtnState.value = 0; + } + } catch (e) { + dismissEasyLoading(); + showToast('网络配置异常:${e.toString()}'.tr); + state.sureBtnState.value = 0; + AppLog.log('网络配置异常:$e'); } } @@ -84,81 +105,138 @@ class ConfiguringWifiLogic extends BaseGetXController { if (reply is GatewayConfiguringWifiResultReply) { _replySenderConfiguringWifiResult(reply); } + // wifi配网命令应答结果 if (reply is GatewayConfiguringWifiReply) { - _replySenderConfiguringWifiResult(reply); + _replySenderConfiguringWifi(reply); } if (reply is GatewayGetStatusReply) { _replyGatewayGetStatusReply(reply); } - // if (reply is GatewayGetStatusReply) { - // _replyStatusInfo(reply); - // } // 上传数据获取锁设置 if (reply is UpdataLockSetReply) { _replyUpdataLockSetReply(reply); } - AppLog.log('蓝牙回调处理完毕${EasyLoading.isShow}'); }); } - // WIFI配网结果 - Future _replySenderConfiguringWifiResult(Reply reply) async { + // WIFI配网操作结果处理 + Future _replySenderConfiguringWifi(Reply reply) async { final int status = reply.data[2]; - // state.sureBtnState.value = 0; - - // 取消loading超时定时器 - state.loadingTimer?.cancel(); - state.loadingTimer = null; switch (status) { case 0x00: - await Storage.removeLockNetWorkInfoCache(); - final int secretKeyJsonLength = (reply.data[4] << 8) + reply.data[3]; - - final List secretKeyList = - reply.data.sublist(5, 5 + secretKeyJsonLength); - String result = utf8String(secretKeyList); - // 解析 JSON 字符串为 Map - Map jsonMap = json.decode(result); - - // 提取 peerId - String? peerId = jsonMap['peerId']; - String? wifiName = jsonMap['wifiName']; - String? secretKey = jsonMap['secretKey']; - String? deviceMac = jsonMap['deviceMac']; - String? networkMac = jsonMap['networkMac']; - - /// 配网成功后,赋值锁的peerId - StartChartManage().lockPeerId = peerId ?? ''; - - state.isLoading.value = false; - // 保存到缓存 - await Storage.saveLockNetWorkInfo(jsonMap); - // 上报服务器 - updateNetworkInfo( - peerId: peerId ?? '', - wifiName: wifiName ?? '', - secretKey: secretKey ?? '', - deviceMac: deviceMac ?? '', - networkMac: networkMac ?? ''); - + AppLog.log('wifi配网命令回复结果:成功'); break; default: //失败 dismissEasyLoading(); // 关闭loading - cancelBlueConnetctToastTimer(); - if (state.loadingTimer != null) { - state.loadingTimer!.cancel(); - state.loadingTimer = null; - } - showToast('配网失败'.tr); state.isLoading.value = false; break; } } -// 辅助函数:美化 JSON 输出 + // WIFI配网结果处理 + Future _replySenderConfiguringWifiResult(Reply reply) async { + final int status = reply.data[2]; + + // 收到响应后,取消蓝牙超时计时器 + cancelBlueConnetctToastTimer(); + + switch (status) { + case 0x00: + // 配网成功 - 不关闭loading,保持状态直到全部完成 + await Storage.removeLockNetWorkInfoCache(); + + try { + final int secretKeyJsonLength = (reply.data[4] << 8) + reply.data[3]; + final List secretKeyList = + reply.data.sublist(5, 5 + secretKeyJsonLength); + String result = utf8String(secretKeyList); + + AppLog.log('解析配网信息: $result'); + + // 解析 JSON 字符串为 Map + Map jsonMap = json.decode(result); + + // 提取网络信息 + String? peerId = jsonMap['peerId']; + String? wifiName = jsonMap['wifiName']; + String? secretKey = jsonMap['secretKey']; + String? deviceMac = jsonMap['deviceMac']; + String? networkMac = jsonMap['networkMac']; + + // 验证关键字段 + if (peerId == null || + peerId.isEmpty || + secretKey == null || + secretKey.isEmpty) { + throw Exception('Missing required network information'); + } + + /// 配网成功后,赋值锁的peerId + StartChartManage().lockPeerId = peerId; + + // 保存到缓存 + await Storage.saveLockNetWorkInfo(jsonMap); + + // 上报服务器 - 注意: sureBtnState 状态将在 updateNetworkInfo 方法中或其回调中完成重置 + updateNetworkInfo( + peerId: peerId, + wifiName: wifiName ?? '', + secretKey: secretKey, + deviceMac: deviceMac ?? '', + networkMac: networkMac ?? ''); + } catch (e) { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('解析配网信息失败,请重试'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + AppLog.log('解析配网信息失败: $e'); + return; // 添加return阻止后续流程 + } + break; + + case 0x01: + // WiFi密码错误 + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('WiFi密码错误,请重新输入'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + break; + + case 0x02: + // 找不到WiFi + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('找不到该WiFi网络,请确认WiFi名称正确'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + break; + + case 0x03: + // 网络连接超时 + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('连接WiFi超时,请确保网络信号良好'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + break; + + default: + // 其他错误 + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('配网失败 (错误码: $status),请重试'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + break; + } + } + + // 辅助函数:美化 JSON 输出 String prettyPrintJson(String jsonString) { var jsonObject = json.decode(jsonString); return JsonEncoder.withIndent(' ').convert(jsonObject); @@ -168,63 +246,80 @@ class ConfiguringWifiLogic extends BaseGetXController { Future senderConfiguringWifiAction() async { AppLog.log('开始配网${EasyLoading.isShow}'); - if (state.isLoading.isTrue) { + if (state.sureBtnState.value == 1) { AppLog.log('正在配网中请勿重复点击'); return; } - if (state.wifiNameController.text.isEmpty) { - showToast('请输入wifi名称'.tr); + + // 获取网关配置信息 + try { + final GetGatewayConfigurationEntity entity = await ApiRepository.to + .getGatewayConfigurationNotLoading(timeout: _configurationTimeout); + if (entity.errorCode!.codeIsSuccessful) { + state.getGatewayConfigurationStr = entity.data ?? ''; + } else { + // showToast('获取网关配置失败,请重试'.tr); + AppLog.log('获取网关配置失败,请重试'); + return; + } + + // 判断是否登录账户 + final loginData = await Storage.getLoginData(); + if (loginData == null) { + AppLog.log('未检测到登录信息,请重新登录'.tr); + return; + } + + // 获取app用户的peerId + String appPeerId = loginData.starchart?.starchartId ?? ''; + if (appPeerId.isEmpty) { + AppLog.log('用户ID获取失败,请重新登录'.tr); + return; + } + + // 处理配置字符串 + if (state.getGatewayConfigurationStr.isNotEmpty) { + // 解析 JSON 字符串为 Map + Map jsonMap = + json.decode(state.getGatewayConfigurationStr); + + // 移除指定的键 + jsonMap.remove("starCloudUrl"); + jsonMap.remove("starLockPeerId"); + + // 追加新的键值对 + jsonMap['userPeerld'] = appPeerId; + + // 将 Map 转换回 JSON 字符串 + state.getGatewayConfigurationStr = + json.encode(jsonMap).replaceAll(',', ',\n'); + + // 确保格式化输出 + state.getGatewayConfigurationStr = + prettyPrintJson(state.getGatewayConfigurationStr); + } else { + // 如果为空,则直接赋值 + state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}"; + } + } catch (e) { + AppLog.log('网关配置准备失败:${e.toString()}'.tr); return; } - if (state.wifiPWDController.text.isEmpty) { - showToast('请输入WiFi密码'.tr); - return; - } - // if (state.sureBtnState.value == 1) { - // return; - // } - // state.sureBtnState.value = 1; + // 先设置sureBtnState状态,以禁用按钮 + state.sureBtnState.value = 1; - final GetGatewayConfigurationEntity entity = - await ApiRepository.to.getGatewayConfigurationNotLoading(timeout: 60); - if (entity.errorCode!.codeIsSuccessful) { - state.getGatewayConfigurationStr = entity.data ?? ''; + // 显示loading,如果已经显示则不再重复显示 + if (!EasyLoading.isShow) { + showEasyLoading(); } - // 判断是否登录账户 - final loginData = await Storage.getLoginData(); - - // 获取app用户的peerId - String appPeerId = loginData?.starchart?.starchartId ?? ''; - // 如果已有值,则追加 - if (state.getGatewayConfigurationStr.isNotEmpty) { - // 解析 JSON 字符串为 Map - Map jsonMap = - json.decode(state.getGatewayConfigurationStr); - - // 移除指定的键 - jsonMap.remove("starCloudUrl"); - jsonMap.remove("starLockPeerId"); - - // 追加新的键值对 - jsonMap['userPeerld'] = appPeerId; - - // 将 Map 转换回 JSON 字符串 - state.getGatewayConfigurationStr = - json.encode(jsonMap).replaceAll(',', ',\n'); - - // 确保格式化输出 - state.getGatewayConfigurationStr = - prettyPrintJson(state.getGatewayConfigurationStr); - } else { - // 如果为空,则直接赋值 - state.getGatewayConfigurationStr = "{\"userPeerld\": \"$appPeerId\"}"; - } - showEasyLoading(); + // 设置蓝牙操作超时处理 showBlueConnetctToastTimer(action: () { - dismissEasyLoading(); - state.isLoading.value = false; + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + state.sureBtnState.value = 0; // 连接超时时重置状态 }); // 发送配网指令 @@ -232,16 +327,27 @@ class ConfiguringWifiLogic extends BaseGetXController { BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { if (connectionState == BluetoothConnectionState.connected) { - IoSenderManage.gatewayConfiguringWifiCommand( - ssid: state.wifiNameController.text, - password: state.wifiPWDController.text, - gatewayConfigurationStr: state.getGatewayConfigurationStr, - ); + try { + IoSenderManage.gatewayConfiguringWifiCommand( + ssid: state.wifiNameController.text, + password: state.wifiPWDController.text, + gatewayConfigurationStr: state.getGatewayConfigurationStr, + ); + // 注意:此处不要重置sureBtnState状态,等待配网结果回调 + } catch (e) { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + cancelBlueConnetctToastTimer(); + state.sureBtnState.value = 0; // 发送命令失败时重置状态 + showToast('发送配网指令失败:${e.toString()}'.tr); + } } else if (connectionState == BluetoothConnectionState.disconnected) { - dismissEasyLoading(); + if (EasyLoading.isShow) { + dismissEasyLoading(); + } cancelBlueConnetctToastTimer(); - state.isLoading.value = false; - // state.sureBtnState.value = 0; + state.sureBtnState.value = 0; // 蓝牙断开时重置状态 if (state.ifCurrentScreen.value == true) { showBlueConnetctToast(); } @@ -249,7 +355,6 @@ class ConfiguringWifiLogic extends BaseGetXController { }, isAddEquipment: false, ); - state.isLoading.value = true; } // 获取设备状态 @@ -278,11 +383,15 @@ class ConfiguringWifiLogic extends BaseGetXController { final NetworkInfo _networkInfo = NetworkInfo(); Future getWifiName() async { - String ssid = ''; - ssid = (await _networkInfo.getWifiName())!; - ssid = ssid ?? ''; - ssid = ssid.replaceAll(r'"', ''); - return ssid ?? ''; + try { + String? ssid = await _networkInfo.getWifiName(); + ssid = ssid ?? ''; + ssid = ssid.replaceAll(r'"', ''); + return ssid; + } catch (e) { + AppLog.log('获取WiFi名称失败: $e'); + return ''; + } } ///定位权限 @@ -308,17 +417,12 @@ class ConfiguringWifiLogic extends BaseGetXController { getWifiLockServiceIpAndPort(); _initReplySubscription(); - // getDevicesStatusAction(); - } - - @override - void onInit() { - super.onInit(); } @override void onClose() { _replySubscription.cancel(); + cancelBlueConnetctToastTimer(); // 确保取消蓝牙超时计时器 super.onClose(); } @@ -330,8 +434,6 @@ class ConfiguringWifiLogic extends BaseGetXController { switch (status) { case 0x00: //成功 - // state.sureBtnState.value = 0; - final GetGatewayInfoModel gatewayModel = GetGatewayInfoModel(); // 网关MAC地址 int index = 3; @@ -372,70 +474,108 @@ class ConfiguringWifiLogic extends BaseGetXController { default: //失败 dismissEasyLoading(); - showToast('配网失败'.tr); - if (state.loadingTimer != null) { - state.loadingTimer!.cancel(); - state.loadingTimer = null; - } + showToast('获取设备状态失败'.tr); break; } } // 上传数据获取设置 Future _getUploadLockSet() async { - showEasyLoading(); + // 保持已有的loading状态,不再重新显示loading showBlueConnetctToastTimer(action: () { - dismissEasyLoading(); + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + state.sureBtnState.value = 0; }); - final List? token = await Storage.getStringList(saveBlueToken); - final List getTokenList = changeStringListToIntList(token!); - - await _uploadLockSet(getTokenList); + try { + final List? token = await Storage.getStringList(saveBlueToken); + if (token == null || token.isEmpty) { + throw Exception('Token is empty'); + } + final List getTokenList = changeStringListToIntList(token); + await _uploadLockSet(getTokenList); + } catch (e) { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + cancelBlueConnetctToastTimer(); + showToast('获取设置失败:${e.toString()}'.tr); + state.sureBtnState.value = 0; + } } // 公共的上传锁设置 Future _uploadLockSet(List token) async { - final List? privateKey = - await Storage.getStringList(saveBluePrivateKey); - final List getPrivateKeyList = changeStringListToIntList(privateKey!); + try { + final List? privateKey = + await Storage.getStringList(saveBluePrivateKey); + if (privateKey == null || privateKey.isEmpty) { + throw Exception('Private key is empty'); + } + final List getPrivateKeyList = changeStringListToIntList(privateKey); - final List? signKey = await Storage.getStringList(saveBlueSignKey); - final List signKeyDataList = changeStringListToIntList(signKey!); + final List? signKey = + await Storage.getStringList(saveBlueSignKey); + if (signKey == null || signKey.isEmpty) { + throw Exception('Sign key is empty'); + } + final List signKeyDataList = changeStringListToIntList(signKey); - IoSenderManage.updataLockSetCommand( - lockID: BlueManage().connectDeviceName, - userID: await Storage.getUid(), - token: token, - needAuthor: 1, - signKey: signKeyDataList, - privateKey: getPrivateKeyList); + IoSenderManage.updataLockSetCommand( + lockID: BlueManage().connectDeviceName, + userID: await Storage.getUid(), + token: token, + needAuthor: 1, + signKey: signKeyDataList, + privateKey: getPrivateKeyList); + } catch (e) { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + cancelBlueConnetctToastTimer(); + showToast('上传设置失败:${e.toString()}'.tr); + state.sureBtnState.value = 0; + } } // 上传数据获取锁设置解析 Future _replyUpdataLockSetReply(Reply reply) async { final int status = reply.data[2]; - dismissEasyLoading(); // 关闭loading + // 保持loading状态直到整个过程完成 cancelBlueConnetctToastTimer(); + switch (status) { case 0x00: await _lockDataUpload( uploadType: 1, recordType: 0, records: reply.data.sublist(7, reply.data.length)); - break; + case 0x06: - //无权限 - final List token = reply.data.sublist(3, 7); - final List saveStrList = changeIntListToStringList(token); - Storage.setStringList(saveBlueToken, saveStrList); - - _uploadLockSet(token); + //无权限,尝试重新获取token + try { + final List token = reply.data.sublist(3, 7); + final List saveStrList = changeIntListToStringList(token); + await Storage.setStringList(saveBlueToken, saveStrList); + _uploadLockSet(token); + } catch (e) { + if (EasyLoading.isShow) { + dismissEasyLoading(); // 错误时关闭loading + } + showToast('获取设置权限失败:${e.toString()}'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + } break; + default: - dismissEasyLoading(); - cancelBlueConnetctToastTimer(); + if (EasyLoading.isShow) { + dismissEasyLoading(); // 错误时关闭loading + } + showToast('获取锁设置失败 (错误码: $status)'.tr); + state.sureBtnState.value = 0; // 确保重置状态 break; } } @@ -445,25 +585,43 @@ class ConfiguringWifiLogic extends BaseGetXController { {required int uploadType, required int recordType, required List records}) async { - final LoginEntity entity = await ApiRepository.to.lockDataUpload( - lockId: state.lockBasicInfo.value.lockId ?? -1, - uploadType: uploadType, - recordType: recordType, - records: records, - isUnShowLoading: true); - if (entity.errorCode!.codeIsSuccessful) { - showToast('配网成功'.tr, something: () { - state.isLoading.value = false; - if (state.pageName.value == 'lockSet') { - Get.close(2); - } else { - Get.offAllNamed(Routers.starLockMain); - } + try { + final LoginEntity entity = await ApiRepository.to.lockDataUpload( + lockId: state.lockBasicInfo.value.lockId ?? -1, + uploadType: uploadType, + recordType: recordType, + records: records, + isUnShowLoading: true); - eventBus - .fire(PassCurrentLockInformationEvent(state.lockSetInfoData.value)); - eventBus.fire(SuccessfulDistributionNetwork()); - }); + if (entity.errorCode!.codeIsSuccessful) { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('配网成功'.tr, something: () { + state.sureBtnState.value = 0; // 确保重置状态 + if (state.pageName.value == 'lockSet') { + Get.close(2); + } else { + Get.offAllNamed(Routers.starLockMain); + } + + eventBus.fire( + PassCurrentLockInformationEvent(state.lockSetInfoData.value)); + eventBus.fire(SuccessfulDistributionNetwork()); + }); + } else { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('数据上传失败:${entity.errorCode}'.tr); + state.sureBtnState.value = 0; // 确保重置状态 + } + } catch (e) { + if (EasyLoading.isShow) { + dismissEasyLoading(); + } + showToast('数据上传异常:${e.toString()}'.tr); + state.sureBtnState.value = 0; // 确保重置状态 } } } diff --git a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart index ed653308..51c45a9d 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_page.dart @@ -25,6 +25,9 @@ class _ConfiguringWifiPageState extends State final ConfiguringWifiLogic logic = Get.put(ConfiguringWifiLogic()); final ConfiguringWifiState state = Get.find().state; + // 添加密码可见性控制 + final RxBool _obscureText = true.obs; + @override Widget build(BuildContext context) { return Scaffold( @@ -39,19 +42,36 @@ class _ConfiguringWifiPageState extends State 'WiFi名称'.tr, '请输入WiFi名字'.tr, state.wifiNameController), Container( width: 1.sw, height: 1.h, color: AppColors.mainBackgroundColor), - configuringWifiTFWidget( + configuringWifiPasswordTFWidget( 'WiFi密码'.tr, '请输入WiFi密码'.tr, state.wifiPWDController), SizedBox( height: 50.h, ), Obx( () => SubmitBtn( - btnName: '确定'.tr, - isDisabled: state.isLoading.isFalse, - onClick: state.isLoading.isTrue + btnName: state.sureBtnState.value == 1 ? '配置中...'.tr : '确定'.tr, + // 当sureBtnState为1时按钮不可用 + isDisabled: state.sureBtnState.value == 1, + onClick: state.sureBtnState.value == 1 ? null : () { FocusScope.of(context).requestFocus(FocusNode()); + // 验证输入 + if (state.wifiNameController.text.isEmpty) { + logic.showToast('请输入WiFi名称'.tr); + return; + } + if (state.wifiPWDController.text.isEmpty) { + logic.showToast('请输入WiFi密码'.tr); + return; + } + // 检查WiFi名称是否包含5G关键字 + if (state.wifiNameController.text + .toLowerCase() + .contains('5g')) { + logic.showToast('请确保使用2.4GHz WiFi网络'.tr); + return; + } logic.senderConfiguringWifiAction(); }, ), @@ -86,7 +106,22 @@ class _ConfiguringWifiPageState extends State ); } - // 接受者信息输入框 + Widget configuringWifiPasswordTFWidget( + String titleStr, String rightTitle, TextEditingController controller) { + return Column( + children: [ + Container(height: 10.h), + CommonItem( + leftTitel: titleStr, + rightTitle: '', + isHaveRightWidget: true, + rightWidget: getPasswordTFWidget(rightTitle, controller)), + Container(height: 10.h), + ], + ); + } + + // 普通输入框 Widget getTFWidget(String tfStr, TextEditingController controller) { return Container( height: 65.h, @@ -95,18 +130,14 @@ class _ConfiguringWifiPageState extends State children: [ Expanded( child: TextField( - //输入框一行 maxLines: 1, inputFormatters: [ FilteringTextInputFormatter.deny('\n'), - // LengthLimitingTextInputFormatter(30), ], controller: controller, autofocus: false, textAlign: TextAlign.end, decoration: InputDecoration( - //输入里面输入文字内边距设置 - // contentPadding: const EdgeInsets.only(top: 12.0, bottom: 8.0), hintText: tfStr, hintStyle: TextStyle(fontSize: 22.sp), focusedBorder: const OutlineInputBorder( @@ -135,6 +166,61 @@ class _ConfiguringWifiPageState extends State ); } + // 密码输入框 + Widget getPasswordTFWidget(String tfStr, TextEditingController controller) { + return Container( + height: 65.h, + width: 300.w, + child: Row( + children: [ + Expanded( + child: Obx( + () => TextField( + maxLines: 1, + obscureText: _obscureText.value, + inputFormatters: [ + FilteringTextInputFormatter.deny('\n'), + ], + controller: controller, + autofocus: false, + textAlign: TextAlign.end, + decoration: InputDecoration( + hintText: tfStr, + hintStyle: TextStyle(fontSize: 22.sp), + focusedBorder: const OutlineInputBorder( + borderSide: + BorderSide(width: 0, color: Colors.transparent)), + disabledBorder: const OutlineInputBorder( + borderSide: + BorderSide(width: 0, color: Colors.transparent)), + enabledBorder: const OutlineInputBorder( + borderSide: + BorderSide(width: 0, color: Colors.transparent)), + border: const OutlineInputBorder( + borderSide: + BorderSide(width: 0, color: Colors.transparent)), + contentPadding: const EdgeInsets.symmetric(vertical: 0), + ), + style: TextStyle( + fontSize: 22.sp, textBaseline: TextBaseline.alphabetic), + ), + ), + ), + IconButton( + icon: Icon( + _obscureText.value ? Icons.visibility_off : Icons.visibility, + color: Colors.grey, + size: 24.sp, + ), + onPressed: () { + _obscureText.value = !_obscureText.value; + }, + ), + ], + ), + ); + } + @override void didChangeDependencies() { super.didChangeDependencies(); diff --git a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_state.dart b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_state.dart index 513fede2..350a2863 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_state.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/configuringWifi/configuringWifi_state.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:network_info_plus/network_info_plus.dart'; @@ -33,5 +31,4 @@ class ConfiguringWifiState { String getGatewayConfigurationStr = ''; RxBool isLoading = false.obs; - Timer? loadingTimer; } diff --git a/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_logic.dart b/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_logic.dart index 8f95204e..6ee5bea6 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_logic.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_logic.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:get/get.dart'; +import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/blue/io_gateway/io_gateway_getWifiList.dart'; import 'package:star_lock/blue/io_protocol/io_getWifiList.dart'; import 'package:star_lock/talk/starChart/star_chart_manage.dart'; @@ -20,7 +21,9 @@ class WifiListLogic extends BaseGetXController { // 获取解析后的数据 late StreamSubscription _replySubscription; + Timer? _connectionTimer; + /// 初始化订阅,监听设备响应 void _initReplySubscription() { _replySubscription = EventBusManager().eventBus!.on().listen((Reply reply) { @@ -31,78 +34,130 @@ class WifiListLogic extends BaseGetXController { if (reply is GatewayGetWifiListReply) { _replyGetWifiListParameters(reply); } + }, onError: (error) { + // 处理CRC校验失败等错误 + AppLog.log('WiFi列表获取过程中发生错误: $error'); + + // 取消loading状态,显示错误提示 + dismissEasyLoading(); + cancelBlueConnetctToastTimer(); + + // 重置按钮状态,允许重新扫描 + state.sureBtnState.value = 0; + + // 如果是CRC校验失败,显示特定提示 + if (error.toString().contains('CRC')) { + showToast('数据校验失败,请重新扫描'.tr); + } else { + showToast('扫描WiFi失败,请重试'.tr); + } }); } - // 发送获取wifi列表数据解析 + /// 发送获取wifi列表数据解析 Future _replySendGetWifiParameters(Reply reply) async { final int status = reply.data[2]; switch (status) { case 0x00: - //成功 - showEasyLoading(); + //成功 - 不显示loading框,UI中已经有进度指示器 cancelBlueConnetctToastTimer(); - Future.delayed(5.seconds, dismissEasyLoading); break; case 0x06: // 需要鉴权 + dismissEasyLoading(); + AppLog.log('需要设备鉴权,请重试'.tr); + state.sureBtnState.value = 0; break; default: + // 处理其他错误状态 + dismissEasyLoading(); + AppLog.log('获取WiFi列表失败,错误码:$status'.tr); + state.sureBtnState.value = 0; break; } } - // 获取WiFi数据解析 + /// 获取WiFi数据解析 Future _replyGetWifiListParameters(Reply reply) async { final int status = reply.data[2]; switch (status) { case 0x00: //成功 - // showEasyLoading(); dismissEasyLoading(); state.sureBtnState.value = 0; if (reply.data[3] > 0) { reply.data.removeRange(0, 4); - // 把得到的数据按33位分割成数组 然后塞进一个新的数组里面 + // 把得到的数据按33位分割成数组然后处理 final List> getList = splitList(reply.data, 33); final List> uploadList = >[]; + for (int i = 0; i < getList.length; i++) { final List indexList = getList[i]; final Map indexMap = {}; final List wifiName = indexList.sublist(0, 32); - indexMap['wifiName'] = utf8String(wifiName); + final String wifiNameStr = utf8String(wifiName).trim(); + + // 过滤掉空的WiFi名称 + if (wifiNameStr.isEmpty) { + continue; + } + + indexMap['wifiName'] = wifiNameStr; indexMap['rssi'] = (indexList.last - 255).toString(); uploadList.add(indexMap); - state.wifiNameDataList.value = uploadList; } + + // 按信号强度排序WiFi列表 (从强到弱) + uploadList.sort((a, b) => + int.parse(b['rssi']!).compareTo(int.parse(a['rssi']!))); + + state.wifiNameDataList.value = uploadList; + + if (uploadList.isEmpty) { + showToast('未检测到可用的WiFi网络'.tr); + } + } else { + // 处理WiFi列表为空的情况 + state.wifiNameDataList.clear(); + showToast('未检测到可用的WiFi网络'.tr); } break; default: + // 处理其他错误状态 + dismissEasyLoading(); + showToast('解析WiFi列表失败,错误码:$status'.tr); + state.sureBtnState.value = 0; break; } } - // 获取wifi列表 + /// 获取WiFi列表 Future senderGetWifiListWifiAction() async { if (state.sureBtnState.value == 1) { return; } state.sureBtnState.value = 1; + state.wifiNameDataList.clear(); // 清空之前的列表 - showEasyLoading(); + // 不显示loading框,UI中已经有进度指示器 showBlueConnetctToastTimer(action: () { - dismissEasyLoading(); state.sureBtnState.value = 0; }); + BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async { if (connectionState == BluetoothConnectionState.connected) { - IoSenderManage.gatewayGetWifiCommand( - userID: await Storage.getUid(), - ); + try { + IoSenderManage.gatewayGetWifiCommand( + userID: await Storage.getUid(), + ); + } catch (e) { + state.sureBtnState.value = 0; + cancelBlueConnetctToastTimer(); + showToast('发送获取WiFi列表请求失败:${e.toString()}'.tr); + } } else if (connectionState == BluetoothConnectionState.disconnected) { - dismissEasyLoading(); state.sureBtnState.value = 0; cancelBlueConnetctToastTimer(); if (state.ifCurrentScreen.value == true) { @@ -113,22 +168,26 @@ class WifiListLogic extends BaseGetXController { } @override - void onReady() { + void onReady() async { super.onReady(); - _initReplySubscription(); + await senderGetWifiListWifiAction(); } @override void onInit() { super.onInit(); - - senderGetWifiListWifiAction(); + // 页面进入时标记为当前页面 + state.ifCurrentScreen.value = true; } @override void onClose() { - super.onClose(); + // 取消所有计时器和订阅,防止内存泄漏 _replySubscription.cancel(); + _connectionTimer?.cancel(); + cancelBlueConnetctToastTimer(); + state.ifCurrentScreen.value = false; + super.onClose(); } } diff --git a/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_page.dart b/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_page.dart index 2508cc27..fd4c6765 100755 --- a/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_page.dart +++ b/lib/main/lockDetail/lockSet/configuringWifi/wifiList/wifiList_page.dart @@ -23,6 +23,32 @@ class _WifiListPageState extends State { final WifiListLogic logic = Get.put(WifiListLogic()); final WifiListState state = Get.find().state; + /// 计算WiFi信号强度图标 + IconData _getWifiSignalIcon(String rssi) { + final int rssiValue = int.parse(rssi); + if (rssiValue >= -50) { + return Icons.signal_wifi_4_bar; + } else if (rssiValue >= -70) { + return Icons.network_wifi; + } else if (rssiValue >= -80) { + return Icons.network_wifi_2_bar_rounded; + } else { + return Icons.signal_wifi_0_bar; + } + } + + @override + void initState() { + super.initState(); + state.ifCurrentScreen.value = true; + } + + @override + void dispose() { + state.ifCurrentScreen.value = false; + super.dispose(); + } + @override Widget build(BuildContext context) { return WillPopScope( @@ -38,13 +64,15 @@ class _WifiListPageState extends State { barTitle: 'WIFI列表'.tr, haveBack: state.pageName.value == 'lockSet', actionsList: [ - TextButton( - child: Text( - '刷新'.tr, - style: TextStyle(color: Colors.white, fontSize: 24.sp), - ), - onPressed: logic.senderGetWifiListWifiAction, - ), + Obx(() => TextButton( + child: Text( + '刷新'.tr, + style: TextStyle(color: Colors.white, fontSize: 24.sp), + ), + onPressed: state.sureBtnState.value == 0 + ? logic.senderGetWifiListWifiAction + : null, + )), ], backgroundColor: AppColors.mainColor, ), @@ -52,26 +80,56 @@ class _WifiListPageState extends State { children: [ Expanded( child: Obx(() => state.wifiNameDataList.value.isNotEmpty - ? ListView.builder( - itemCount: state.wifiNameDataList.value.length, - itemBuilder: (BuildContext c, int index) { - Map wifiNameStr = state.wifiNameDataList.value[index]; - return _messageListItem( - wifiNameStr['wifiName'], wifiNameStr['rssi'], () { - Get.toNamed(Routers.configuringWifiPage, - arguments: { - 'lockSetInfoData': - state.lockSetInfoData.value, - 'wifiName': wifiNameStr['wifiName'], - 'pageName': state.pageName.value, - }); - }); - }) - : NoData( - noDataHeight: 1.sh - - ScreenUtil().statusBarHeight - - ScreenUtil().bottomBarHeight - - 64.h)), + ? RefreshIndicator( + onRefresh: () async { + if (state.sureBtnState.value == 0) { + await logic.senderGetWifiListWifiAction(); + } + }, + child: ListView.builder( + itemCount: state.wifiNameDataList.value.length, + itemBuilder: (BuildContext c, int index) { + Map wifiNameStr = + state.wifiNameDataList.value[index]; + return _messageListItem( + wifiNameStr['wifiName'], wifiNameStr['rssi'], + () { + Get.toNamed(Routers.configuringWifiPage, + arguments: { + 'lockSetInfoData': + state.lockSetInfoData.value, + 'wifiName': wifiNameStr['wifiName'], + 'pageName': state.pageName.value, + }); + }); + }), + ) + : Obx(() => state.sureBtnState.value == 1 + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: 50.w, + height: 50.w, + child: CircularProgressIndicator( + strokeWidth: 4.w, + valueColor: AlwaysStoppedAnimation( + AppColors.mainColor, + ), + backgroundColor: Colors.grey[200], + ), + ), + SizedBox(height: 20.h), + Text('正在扫描WiFi网络...\n请确保设备处于正常状态'.tr, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 24.sp, + color: AppColors.blackColor)) + ], + ), + ) + : NoData())), ), state.pageName.value == 'saveLock' ? SubmitBtn( @@ -140,24 +198,37 @@ class _WifiListPageState extends State { height: 79.h, width: 1.sw - 20.w * 2, child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( + flex: 4, child: Text( - '$wifiName(${rssi}db)', + wifiName, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( - fontSize: 22.sp, color: AppColors.blackColor), + fontSize: 24.sp, color: AppColors.blackColor), ), ), - // Text( - // rssi, - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - // style: TextStyle( - // fontSize: 22.sp, color: AppColors.blackColor), - // ) + Flexible( + flex: 1, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon( + _getWifiSignalIcon(rssi), + color: AppColors.mainColor, + size: 24.sp, + ), + SizedBox(width: 8.w), + Text( + '$rssi dB', + style: + TextStyle(fontSize: 18.sp, color: Colors.black), + ), + ], + ), + ) ], ), ),