diff --git a/star_lock/images/lan/lan_en.json b/star_lock/images/lan/lan_en.json index 2b11ca5c..0ffa372b 100644 --- a/star_lock/images/lan/lan_en.json +++ b/star_lock/images/lan/lan_en.json @@ -769,9 +769,6 @@ "异常警告":"Abnormal warning", "短信提醒":"SMS reminder", "邮件提醒":"Email reminder", - "关锁":"关锁", - "功能":"功能", - "配件":"配件", "N天未开门提醒":"N days did not open the door reminder", "当被胁迫要求强行开锁时,使用胁迫指纹会触发报警,报警消息会推送给管理员,该功能需要锁联网":"When forced to open the lock, the use of coercive fingerprint will trigger the alarm, the alarm message will be pushed to the administrator, the function requires the lock network", "胁迫指纹":"Stress fingerprint", @@ -779,5 +776,8 @@ "经过以上设定的时间,锁没有被开启,系统会给指定对象发送提醒消息,该功能需要锁联网":"After the above set time, the lock is not opened, the system will send a reminder message to the specified object, this function requires the lock network", "打开提醒后,当锁电量低于20%、10%和5%,系统会给指定对象发送提醒消息。电量读取方式:网关读取或APP读取。":"After the reminder is enabled, when the lock power is below 20%, 10%, and 5%, the system will send a reminder message to the specified object. Power reading mode: gateway reading or APP reading.", "门未开时间":"Door not open time", - "添加和使用面容开锁时:":"Add and use Face when unlocking:" + "添加和使用面容开锁时:":"Add and use Face when unlocking:", + "关锁":"close lock", + "功能":"function", + "配件":"parts" } diff --git a/star_lock/ios/Podfile.lock b/star_lock/ios/Podfile.lock index bc49045f..1d1c9856 100644 --- a/star_lock/ios/Podfile.lock +++ b/star_lock/ios/Podfile.lock @@ -41,7 +41,41 @@ PODS: - ReachabilitySwift - device_info_plus (0.0.1): - Flutter + - DKImagePickerController/Core (4.3.8): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.8) + - DKImagePickerController/PhotoGallery (4.3.8): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.8) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif - EMASRest (11.1.1.2) + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter - Flutter (1.0.0) - flutter_blue_plus (0.0.1): - Flutter @@ -95,12 +129,16 @@ PODS: - permission_handler_apple (9.3.0): - Flutter - ReachabilitySwift (5.2.2) + - SDWebImage (5.19.1): + - SDWebImage/Core (= 5.19.1) + - SDWebImage/Core (5.19.1) - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - sqflite (0.0.3): - Flutter - FlutterMacOS + - SwiftyGif (5.4.5) - system_settings (0.0.1): - Flutter - Toast (4.1.1) @@ -126,6 +164,7 @@ DEPENDENCIES: - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) @@ -163,11 +202,15 @@ SPEC REPOS: - AMap3DMap - AMapFoundation - AMapLocation + - DKImagePickerController + - DKPhotoGallery - GoogleMaps - ios-voice-processor - JCore - JPush - ReachabilitySwift + - SDWebImage + - SwiftyGif - Toast - WechatOpenSDK-XCFramework @@ -194,6 +237,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter flutter_blue_plus: @@ -261,7 +306,10 @@ SPEC CHECKSUMS: camera_avfoundation: 8b8d780bcfb6a4a02b0fbe2b4bd17b5b71946e68 connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed + DKImagePickerController: a7836546cfdfe014171694f643a7d575bc8ace7f + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 EMASRest: 8df6f87836767a9415ad5cc4af739bc9d215b475 + file_picker: ce3938a0df3cc1ef404671531facef740d03f920 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96 flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 @@ -284,8 +332,10 @@ SPEC CHECKSUMS: path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149 + SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 system_settings: 8f5cdbfa72c677fc8d665b863bcc20d393d87e9d Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 diff --git a/star_lock/lib/appRouters.dart b/star_lock/lib/appRouters.dart index 9b54cce3..af486893 100644 --- a/star_lock/lib/appRouters.dart +++ b/star_lock/lib/appRouters.dart @@ -57,6 +57,7 @@ import 'login/login/starLock_login_page.dart'; import 'login/register/starLock_register_page.dart'; import 'login/selectCountryRegion/selectCountryRegion_page.dart'; import 'main/lockDetail/card/addCardType/addCardManage/addCardTypeManage_page.dart'; +import 'main/lockDetail/card/addCardType/addCardType_page.dart'; import 'main/lockDetail/card/addICCard/addICCard_page.dart'; import 'main/lockDetail/card/cardDetail/cardDetail_page.dart'; import 'main/lockDetail/card/cardList/cardList_page.dart'; @@ -416,7 +417,8 @@ abstract class Routers { '/AddRemoteControlManagePage'; // 添加遥控 static const cardListPage = '/CardListPage'; // 卡列表 - static const addCardTypeManagePage = '/AddCardTypeManagePage'; // 添加卡 + // static const addCardTypeManagePage = '/AddCardTypeManagePage'; // 添加卡 + static const addCardPage = '/AddCardPage'; // 添加卡 static const cardDetailPage = '/CardDetailPage'; // 卡详情 static const fingerprintListPage = '/FingerprintListPage'; // 指纹列表 static const addFingerprintTypeManagePage = @@ -1009,9 +1011,12 @@ abstract class AppRouters { name: Routers.addRemoteControlManagePage, page: () => const AddRemoteControlManagePage()), GetPage(name: Routers.cardListPage, page: () => const CardListPage()), + // GetPage( + // name: Routers.addCardTypeManagePage, + // page: () => const AddCardTypeManagePage()), GetPage( - name: Routers.addCardTypeManagePage, - page: () => const AddCardTypeManagePage()), + name: Routers.addCardPage, + page: () => const AddCardPage()), GetPage(name: Routers.cardDetailPage, page: () => const CardDetailPage()), GetPage( name: Routers.fingerprintListPage, diff --git a/star_lock/lib/blue/blue_manage.dart b/star_lock/lib/blue/blue_manage.dart index 996ebb9f..ee2bd718 100644 --- a/star_lock/lib/blue/blue_manage.dart +++ b/star_lock/lib/blue/blue_manage.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'dart:io'; @@ -12,7 +11,8 @@ import 'reciver_data.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; //连接状态回调 -typedef ConnectStateCallBack = Function(BluetoothConnectionState connectionState); +typedef ConnectStateCallBack = Function( + BluetoothConnectionState connectionState); typedef ScanDevicesCallBack = Function(List); class BlueManage { @@ -57,7 +57,8 @@ class BlueManage { ScanResult? scanResult; // 监听蓝牙连接状态 - BluetoothConnectionState? bluetoothConnectionState = BluetoothConnectionState.disconnected; + BluetoothConnectionState? bluetoothConnectionState = + BluetoothConnectionState.disconnected; BluetoothAdapterState? _adapterState = BluetoothAdapterState.unknown; StreamSubscription? _adapterStateStateSubscription; @@ -80,6 +81,7 @@ class BlueManage { void _initBlue() { Get.log("蓝牙功能初始化监听"); + FlutterBluePlus.setLogLevel(LogLevel.error, color: true); _initSendStreamSubscription(); _initAdapterStateStateSubscription(); // _initListenscanResults(); @@ -94,7 +96,8 @@ class BlueManage { } void _initAdapterStateStateSubscription() { - _adapterStateStateSubscription ??= FlutterBluePlus.adapterState.listen((state) { + _adapterStateStateSubscription ??= + FlutterBluePlus.adapterState.listen((state) { _adapterState = state; }); } @@ -142,14 +145,18 @@ class BlueManage { _connectionStateSubscription?.cancel(); _connectionStateSubscription = null; - _connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((state) async { + _connectionStateSubscription = + bluetoothConnectDevice!.connectionState.listen((state) async { bluetoothConnectionState = state; print("蓝牙连接状态:$state"); }); } void _initSendStreamSubscription() { - _sendStreamSubscription ??= EventBusManager().eventBus!.on().listen((EventSendModel model) { + _sendStreamSubscription ??= EventBusManager() + .eventBus! + .on() + .listen((EventSendModel model) { if (model.sendChannel == DataChannel.ble) { FlutterBluePlus.isSupported.then((isAvailable) async { if (isAvailable) { @@ -157,9 +164,7 @@ class BlueManage { // 蓝牙已开启,可以进行蓝牙操作 writeCharacteristicWithResponse(model.data); } else { - try { - - } catch (e) { + try {} catch (e) { print("Error Turning On:"); } } @@ -172,7 +177,8 @@ class BlueManage { } /// 开始指定设备名称的扫描蓝牙设备 - Future startScanSingle(String deviceName, int timeout, ScanDevicesCallBack scanDevicesCallBack) async { + Future startScanSingle(String deviceName, int timeout, + ScanDevicesCallBack scanDevicesCallBack) async { FlutterBluePlus.isSupported.then((isAvailable) async { if (isAvailable) { if (_adapterState == BluetoothAdapterState.on) { @@ -180,8 +186,10 @@ class BlueManage { FlutterBluePlus.startScan(timeout: Duration(seconds: timeout)); Completer completer = Completer(); var subscription = FlutterBluePlus.scanResults.listen((results) { - print("startScanSingle扫描到的设备:$results"); - bool isExit = results.any((element) => (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName)); + // print("startScanSingle扫描到的设备:$results"); + bool isExit = results.any((element) => + (element.device.platformName == deviceName) || + (element.advertisementData.advName == deviceName)); if (isExit) { for (var scanResult in results) { if (((scanResult.advertisementData.serviceUuids.isNotEmpty @@ -191,8 +199,11 @@ class BlueManage { .contains("758824")) && (scanResult.rssi >= -100)) { // 查询id相同的元素 - final knownDeviceIndex = scanDevices - .indexWhere((d) => (d.device.platformName == scanResult.device.platformName) || (d.advertisementData.advName == scanResult.advertisementData.advName)); + final knownDeviceIndex = scanDevices.indexWhere((d) => + (d.device.platformName == + scanResult.device.platformName) || + (d.advertisementData.advName == + scanResult.advertisementData.advName)); // 不存在的时候返回-1 if (knownDeviceIndex >= 0) { scanDevices[knownDeviceIndex] = scanResult; @@ -231,7 +242,8 @@ class BlueManage { } /// 开始扫描蓝牙设备 - Future startScan(int timeout, ScanDevicesCallBack scanDevicesCallBack, {List? idList}) async { + Future startScan(int timeout, ScanDevicesCallBack scanDevicesCallBack, + {List? idList}) async { FlutterBluePlus.isSupported.then((isAvailable) async { if (isAvailable) { if (_adapterState == BluetoothAdapterState.on) { @@ -255,8 +267,11 @@ class BlueManage { .contains("758824")) && (scanResult.rssi >= -100)) { // 查询id相同的元素 - final knownDeviceIndex = scanDevices - .indexWhere((d) => (d.device.platformName == scanResult.device.platformName) || (d.advertisementData.advName == scanResult.advertisementData.advName)); + final knownDeviceIndex = scanDevices.indexWhere((d) => + (d.device.platformName == + scanResult.device.platformName) || + (d.advertisementData.advName == + scanResult.advertisementData.advName)); // 不存在的时候返回-1 if (knownDeviceIndex >= 0) { scanDevices[knownDeviceIndex] = scanResult; @@ -294,7 +309,9 @@ class BlueManage { } /// 调用发送数据 List senderData, - Future bludSendData(String deviceName, ConnectStateCallBack stateCallBack, {bool isAddEquipment = false}) async { + Future bludSendData( + String deviceName, ConnectStateCallBack stateCallBack, + {bool isAddEquipment = false}) async { FlutterBluePlus.isSupported.then((isAvailable) async { if (isAvailable) { if (_adapterState == BluetoothAdapterState.on) { @@ -321,33 +338,43 @@ class BlueManage { } /// 连接 - Future _connect(String deviceName, ConnectStateCallBack connectStateCallBack, + Future _connect( + String deviceName, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async { connectDeviceName = deviceName; List devicesList = scanDevices; //判断列表里面有设备则不开启扫描 - bool isExistDevice = scanDevices.any((element) => element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName); + bool isExistDevice = scanDevices.any((element) => + element.device.platformName == connectDeviceName || + element.advertisementData.advName == connectDeviceName); if (isAddEquipment == false && isExistDevice == false) { // startScan(10, (scanDevices){ startScanSingle(deviceName, 10, (List scanDevices) { print("扫描到的设备:$scanDevices"); devicesList = scanDevices; - _connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment); + _connectDevice(devicesList, deviceName, connectStateCallBack, + isAddEquipment: isAddEquipment); }); } else { - _connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment); + _connectDevice(devicesList, deviceName, connectStateCallBack, + isAddEquipment: isAddEquipment); } } - Future _connectDevice( - List devicesList, String deviceName, ConnectStateCallBack connectStateCallBack, + Future _connectDevice(List devicesList, String deviceName, + ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async { // 判断数组列表里面是否有这个设备 print("devicesList:$devicesList"); - final knownDeviceIndex = devicesList.indexWhere((d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName)); + final knownDeviceIndex = devicesList.indexWhere((d) => + (d.device.platformName == deviceName) || + (d.advertisementData.advName == deviceName)); if (knownDeviceIndex >= 0) { // 存在的时候赋值 - connectDeviceMacAddress = devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty ? devicesList[knownDeviceIndex].advertisementData.advName : devicesList[knownDeviceIndex].device.platformName; + connectDeviceMacAddress = + devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty + ? devicesList[knownDeviceIndex].advertisementData.advName + : devicesList[knownDeviceIndex].device.platformName; bluetoothConnectDevice = devicesList[knownDeviceIndex].device; print('bluetoothConnectDevice: $bluetoothConnectDevice'); @@ -356,7 +383,8 @@ class BlueManage { _initGetMtuSubscription(); _initListenConnectionState(); } - print("1 connectDeviceId:$connectDeviceMacAddress connectDeviceName:$connectDeviceName"); + print( + "1 connectDeviceId:$connectDeviceMacAddress connectDeviceName:$connectDeviceName"); // stopScan(); if (connectDeviceMacAddress.isEmpty) { // connectStateCallBack(BluetoothConnectionState.disconnected!); @@ -366,7 +394,8 @@ class BlueManage { print("调用了停止扫描的方法"); await stopScan(); - if ((scanResult!.advertisementData.serviceUuids[0].toString()[31] == "0") && isAddEquipment == false) { + if ((scanResult!.advertisementData.serviceUuids[0].toString()[31] == "0") && + isAddEquipment == false) { connectStateCallBack(BluetoothConnectionState.disconnected); EasyLoading.showToast("该锁已被重置", duration: 2000.milliseconds); return; @@ -403,12 +432,14 @@ class BlueManage { " service.characteristics:${service.characteristics}" " service.includedServices:${service.includedServices}"); if (service.uuid == _serviceIdConnect) { - for (BluetoothCharacteristic characteristic in service.characteristics) { + for (BluetoothCharacteristic characteristic + in service.characteristics) { // Get.log("22222characteristic.remoteId:${characteristic.remoteId}" // " characteristic.uuid:${characteristic.uuid}" // " characteristic.secondaryServiceUuid:${characteristic.secondaryServiceUuid}" // " characteristic.characteristicUuid:${characteristic.characteristicUuid}"); - if (characteristic.characteristicUuid == _characteristicIdSubscription) { + if (characteristic.characteristicUuid == + _characteristicIdSubscription) { _subScribeToCharacteristic(characteristic); print('Discovering services finished'); bluetoothConnectionState = BluetoothConnectionState.connected; @@ -446,18 +477,21 @@ class BlueManage { } // code to handle incoming data // print("subscribeToCharacteristic: deviceId = ${characteristic.deviceId} characteristicId =${characteristic.characteristicId}---上报来的数据data = $data"); - if ((data[0] == 0xEF) && (data[1] == 0x01) && (data[2] == 0xEE) && (data[3] == 0x02)) { + if ((data[0] == 0xEF) && + (data[1] == 0x01) && + (data[2] == 0xEE) && + (data[3] == 0x02)) { // 当包有头时 // 判断是否需要分包 dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度 - print("dataLen1111:$dataLen getDataLength:${data.length} data:$data"); + // print("dataLen1111:$dataLen getDataLength:${data.length} data:$data"); if (dataLen! + 12 > data.length) { // 当前包的长度小于实际的包时 分包添加 不解析 allData.addAll(data); } else { // 当前包的长度小于实际的包时 不分包 解析 allData.addAll(data); - print("dataLen2222:$dataLen getDataLength:${data.length}"); + // print("dataLen2222:$dataLen getDataLength:${data.length}"); CommandReciverManager.appDataReceive(allData); // 发送完解析初始化数组 allData = []; @@ -466,7 +500,8 @@ class BlueManage { // 当包没有头时 是分包的包 直接添加 allData.addAll(data); // var len = allData[8] * 256 + allData[9]; - print("dataLen3333:$dataLen allData.length:${allData.length} allData:$allData"); + print( + "dataLen3333:$dataLen allData.length:${allData.length} allData:$allData"); if ((dataLen! + 14) <= allData.length) { print("44444数据被解析了"); // 当长度小于等于当前包的数据时 直接解析数据 @@ -530,44 +565,44 @@ class BlueManage { // 写入 Future writeCharacteristicWithResponse(List value) async { - bluetoothConnectDevice!.discoverServices().then((services) async { - for (BluetoothService service in services) { - // print("33333 service.remoteId:${service.remoteId}" - // " service.uuid:${service.uuid}\n\n" - // " service.characteristics:${service.characteristics}\n\n" - // " service.includedServices:${service.includedServices}"); - if (service.uuid == _serviceIdConnect) { - for (BluetoothCharacteristic characteristic in service.characteristics) { - // print("44444 characteristic.remoteId:${characteristic.remoteId}" - // " characteristic.uuid:${characteristic.uuid}\n\n" - // " characteristic.secondaryServiceUuid:${characteristic - // .secondaryServiceUuid}\n\n" - // " characteristic.characteristicUuid:${characteristic - // .characteristicUuid}"); - if (characteristic.characteristicUuid == _characteristicIdWrite) { - try { - List valueList = value; - List subData = splitList(valueList, _mtuSize!); - print('writeCharacteristicWithResponse _mtuSize:$_mtuSize 得到的分割数据:$subData'); - - for (int i = 0; i < subData.length; i++) { - await characteristic.write(subData[i]).then((value) async { - await Future.delayed(const Duration(milliseconds: 1)).then(( - value) async { - print('分包发送成功了'); - }); - }); - } - } on Exception catch (e, s) { - print('Error occurred when writing: $e'); - // Get.log(s); - rethrow; + List services = + await bluetoothConnectDevice!.discoverServices(); + for (BluetoothService service in services) { + // print("33333 service.remoteId:${service.remoteId}" + // " service.uuid:${service.uuid}\n\n" + // " service.characteristics:${service.characteristics}\n\n" + // " service.includedServices:${service.includedServices}"); + if (service.uuid == _serviceIdConnect) { + for (BluetoothCharacteristic characteristic + in service.characteristics) { + // print("44444 characteristic.remoteId:${characteristic.remoteId}" + // " characteristic.uuid:${characteristic.uuid}\n\n" + // " characteristic.secondaryServiceUuid:${characteristic + // .secondaryServiceUuid}\n\n" + // " characteristic.characteristicUuid:${characteristic + // .characteristicUuid}"); + if (characteristic.characteristicUuid == _characteristicIdWrite) { + try { + List valueList = value; + List subData = splitList(valueList, _mtuSize!); + // print('writeCharacteristicWithResponse _mtuSize:$_mtuSize 得到的分割数据:$subData'); + for (int i = 0; i < subData.length; i++) { + await characteristic.write(subData[i],withoutResponse: true).then((value) async { + // await Future.delayed(const Duration(milliseconds: 1)).then(( + // value) async { + // print('分包发送成功了'); + // }); + }); } + } on Exception catch (e, s) { + print('Error occurred when writing: $e'); + // Get.log(s); + rethrow; } } } } - }); + } // List services = await bluetoothConnectDevice!.discoverServices(); // BluetoothCharacteristic characteristic = services // .firstWhere((service) => service.uuid == _serviceIdWrite) diff --git a/star_lock/lib/blue/io_modelVendor.dart b/star_lock/lib/blue/io_modelVendor.dart new file mode 100644 index 00000000..268b206b --- /dev/null +++ b/star_lock/lib/blue/io_modelVendor.dart @@ -0,0 +1,13 @@ + +// ignore_for_file: non_constant_identifier_names + +class IoModelVendor { + + static String vendor_XHJ = 'XHJ'; + static String model_XHJ_SYD = 'SYD-BLE-01'; + static String model_XHJ_JL = 'JL-BLE-01'; + + static String vendor_XL = 'XL'; + static String model_XL_BLE = 'JL-BLE-01'; + static String model_XL_WIFI = 'JL-WIFI-01'; +} diff --git a/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart b/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart new file mode 100644 index 00000000..23e500dd --- /dev/null +++ b/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart @@ -0,0 +1,149 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:get/get.dart'; + +import '../io_tool/io_tool.dart'; +import '../sm4Encipher/sm4.dart'; +import '../io_reply.dart'; +import '../io_sender.dart'; +import '../io_type.dart'; +import 'package:crypto/crypto.dart' as crypto; + +//oat升级 +class OTAUpgradeCommand extends SenderProtocol { + String? lockID; + String? userID; + String? keyID; + int? platform; + int? product; + String? hwVersion; + String? fwVersion; + int? fwSize; + String? fwMD5; + int? needAuthor; + List? publicKey; + List? privateKey; + List? token; + + OTAUpgradeCommand( + {this.lockID, + this.userID, + this.keyID, + this.platform, + this.product, + this.hwVersion, + this.fwVersion, + this.fwSize, + this.fwMD5, + this.needAuthor, + this.publicKey, + this.privateKey, + this.token}) + : super(CommandType.startOATUpgrade); + + @override + List messageDetail() { + List data = []; + List ebcData = []; + + // 指令类型 + int type = commandType!.typeValue; + double typeDouble = type / 256; + int type1 = typeDouble.toInt(); + int type2 = type % 256; + data.add(type1); + data.add(type2); + + // 锁id 40 + int lockIDLength = utf8.encode(lockID!).length; + data.addAll(utf8.encode(lockID!)); + data = getFixedLengthList(data, 40 - lockIDLength); + + //userID 20 + int userIDLength = utf8.encode(userID!).length; + data.addAll(utf8.encode(userID!)); + data = getFixedLengthList(data, 20 - userIDLength); + + //platform 2 + int platform0 = (platform! & 0xFF00) >> 8; + int platform1 = platform! & 0xFF; + data.add(platform0); + data.add(platform1); + + //product 2 + int product0 = (product! & 0xFF00) >> 8; + int product1 = product! & 0xFF; + data.add(product0); + data.add(product1); + + //HwVersion 20 + int hwVersionLength = utf8.encode(hwVersion!).length; + data.addAll(utf8.encode(hwVersion!)); + data = getFixedLengthList(data, 20 - hwVersionLength); + + //FwVersion 20 + int fwVersionLength = utf8.encode(fwVersion!).length; + data.addAll(utf8.encode(fwVersion!)); + data = getFixedLengthList(data, 20 - fwVersionLength); + + //fwSize 4 + ByteData bytes = ByteData(4); // 创建一个长度为4的字节数据 + bytes.setInt32(0, fwSize!); + List byteList = bytes.buffer.asUint8List(); + data.addAll(byteList); + + //fwMD5 16 + int fwMD5Length = utf8.encode(fwMD5!).length; + data.addAll(utf8.encode(fwMD5!)); + data = getFixedLengthList(data, 16 - fwMD5Length); + + // token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0 + data.addAll(token!); + + if (needAuthor == 0) { + //AuthCodeLen 1 + data.add(0); + } else { + List authCodeData = []; + + //authUserID + authCodeData.addAll(utf8.encode(userID!)); + + //KeyID + authCodeData.addAll(utf8.encode(keyID!)); + + //token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 + authCodeData.addAll(token!); + + authCodeData.addAll(publicKey!); + + // 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode + var authCode = crypto.md5.convert(authCodeData); + + data.add(authCode.bytes.length); + data.addAll(authCode.bytes); + } + + if ((data.length % 16) != 0) { + int add = (16 - data.length % 16); + for (int i = 0; i < add; i++) { + data.add(0); + } + } + + Get.log("${commandType!.typeName} SM4Data:$data"); + // 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864 + ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB); + return ebcData; + } +} + +class OTAUpgradeReply extends Reply { + OTAUpgradeReply.parseData(CommandType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { + data = dataDetail; + int status = data[6]; + errorWithStstus(status); + } +} diff --git a/star_lock/lib/blue/io_protocol/io_processOtaUpgrade.dart b/star_lock/lib/blue/io_protocol/io_processOtaUpgrade.dart new file mode 100644 index 00000000..38b52bac --- /dev/null +++ b/star_lock/lib/blue/io_protocol/io_processOtaUpgrade.dart @@ -0,0 +1,74 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:get/get.dart'; + +import '../io_tool/io_tool.dart'; +import '../sm4Encipher/sm4.dart'; +import '../io_reply.dart'; +import '../io_sender.dart'; +import '../io_type.dart'; +import 'package:crypto/crypto.dart' as crypto; + +//oat升级 +class ProcessOtaUpgradeCommand extends SenderProtocol { + int? index; + int? size; + List? data; + + ProcessOtaUpgradeCommand({ + this.index, + this.size, + this.data, + }) : super(CommandType.processOTAUpgrade); + + @override + List messageDetail() { + List data = []; + + // 指令类型 + int type = commandType!.typeValue; + double typeDouble = type / 256; + int type1 = typeDouble.toInt(); + int type2 = type % 256; + data.add(type1); + data.add(type2); + + //index 2 + ByteData indexBytes = ByteData(2); // 创建一个长度为4的字节数据 + indexBytes.setInt16(0, index!); + List indexList = indexBytes.buffer.asUint8List(); + data.addAll(indexList); + + //size 2 + ByteData bytes = ByteData(2); // 创建一个长度为4的字节数据 + bytes.setInt16(0, size!); + List byteList = bytes.buffer.asUint8List(); + data.addAll(byteList); + + data.addAll(this.data!); + + //不加密 + return data; + } +} + +class ProcessOtaUpgradeReply extends Reply { + ProcessOtaUpgradeReply.parseData( + CommandType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { + data = dataDetail; + int status = data[2]; + errorWithStstus(status); + } +} + +class ConfirmationOTAUpgradeReply extends Reply { + ConfirmationOTAUpgradeReply.parseData( + CommandType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { + data = dataDetail; + int status = data[2]; + errorWithStstus(status); + } +} diff --git a/star_lock/lib/blue/io_reply.dart b/star_lock/lib/blue/io_reply.dart index d9e7f010..2cf0ea7b 100644 --- a/star_lock/lib/blue/io_reply.dart +++ b/star_lock/lib/blue/io_reply.dart @@ -14,11 +14,11 @@ abstract class Reply{ Reply.parseData(this.commandType, List dataDetail); void errorWithStstus(int status){ - Get.log("errorWithStstus status:$status commandType:$commandType"); + // Get.log("errorWithStstus status:$status commandType:$commandType"); switch(status){ case 0x00: // 成功 - Get.log("$commandType成功"); + // Get.log("$commandType成功"); break; case 0x01: // 包格式错误 @@ -134,4 +134,9 @@ abstract class Reply{ void showErrorMessage(String message){ EasyLoading.showToast(message, duration: 2000.milliseconds); } + + @override + String toString() { + return 'Reply{commandType: $commandType, status: $status, data: $data}'; + } } diff --git a/star_lock/lib/blue/io_sender.dart b/star_lock/lib/blue/io_sender.dart index 286bbcf3..004047d4 100644 --- a/star_lock/lib/blue/io_sender.dart +++ b/star_lock/lib/blue/io_sender.dart @@ -12,11 +12,17 @@ abstract class SenderProtocol extends IOData { // var uint8View1 = Uint8List(300); CommandType? commandType; //指令类型 - final List header = [0XEF, 0X01, 0XEE, 0X02]; //帧头 固定取值 0XEF01EE02,长度 4 字节 - final int ask = 0X01 ; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节 + final List header = [ + 0XEF, + 0X01, + 0XEE, + 0X02 + ]; //帧头 固定取值 0XEF01EE02,长度 4 字节 + final int ask = 0X01; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节 int? _commandIndex = 1; //包序号 - int identifier = 0x20; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) + int identifier = + 0x20; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) List? commandData = []; //数据块 // final int? tail = 0xFF; //用来校验包的完整性,采用 CRC 校验方法,长度为 2 个字节 @@ -40,9 +46,9 @@ abstract class SenderProtocol extends IOData { // 包序号 int commandIndexChange = _commandIndex!; - double commandIndexChangeDouble = commandIndexChange/256; + double commandIndexChangeDouble = commandIndexChange / 256; int commandIndexChang1 = commandIndexChangeDouble.toInt(); - int commandIndexChang2 = commandIndexChange%256; + int commandIndexChang2 = commandIndexChange % 256; commandList.add(commandIndexChang1); commandList.add(commandIndexChang2); // print("_commandIndex:$_commandIndex commandIndexChang1$commandIndexChang1 commandIndexChang2:$commandIndexChang2"); @@ -57,11 +63,11 @@ abstract class SenderProtocol extends IOData { // commandList.add(dataLength); // print("dataLen:$dataLen"); // var dataLen = 42; - double dataLength = dataLen/256; + double dataLength = dataLen / 256; commandList.add(dataLength.toInt()); - commandList.add(dataLen%256); + commandList.add(dataLen % 256); commandList.add(dataLength.toInt()); - commandList.add(dataLen%256); + commandList.add(dataLen % 256); // 数据块 commandList.addAll(commandData!); //数据块 @@ -69,46 +75,284 @@ abstract class SenderProtocol extends IOData { // 校验位 var mcrc = crc_16(commandList); - double mcrcDouble = mcrc/256; + double mcrcDouble = mcrc / 256; int mcrcDouble1 = mcrcDouble.toInt(); - int mcrcDouble2 = mcrc%256; + int mcrcDouble2 = mcrc % 256; commandList.add(mcrcDouble1); //帧尾 commandList.add(mcrcDouble2); - // print("mcrc:$mcrc"); - // print("mcrcDouble1:$mcrcDouble1"); - // print("mcrcDouble2:$mcrcDouble2"); return commandList; } //TODO:长度 int dataSourceLength() => commandData!.length; - var crcTable =[ - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0]; + var crcTable = [ + 0x0000, + 0x1021, + 0x2042, + 0x3063, + 0x4084, + 0x50a5, + 0x60c6, + 0x70e7, + 0x8108, + 0x9129, + 0xa14a, + 0xb16b, + 0xc18c, + 0xd1ad, + 0xe1ce, + 0xf1ef, + 0x1231, + 0x0210, + 0x3273, + 0x2252, + 0x52b5, + 0x4294, + 0x72f7, + 0x62d6, + 0x9339, + 0x8318, + 0xb37b, + 0xa35a, + 0xd3bd, + 0xc39c, + 0xf3ff, + 0xe3de, + 0x2462, + 0x3443, + 0x0420, + 0x1401, + 0x64e6, + 0x74c7, + 0x44a4, + 0x5485, + 0xa56a, + 0xb54b, + 0x8528, + 0x9509, + 0xe5ee, + 0xf5cf, + 0xc5ac, + 0xd58d, + 0x3653, + 0x2672, + 0x1611, + 0x0630, + 0x76d7, + 0x66f6, + 0x5695, + 0x46b4, + 0xb75b, + 0xa77a, + 0x9719, + 0x8738, + 0xf7df, + 0xe7fe, + 0xd79d, + 0xc7bc, + 0x48c4, + 0x58e5, + 0x6886, + 0x78a7, + 0x0840, + 0x1861, + 0x2802, + 0x3823, + 0xc9cc, + 0xd9ed, + 0xe98e, + 0xf9af, + 0x8948, + 0x9969, + 0xa90a, + 0xb92b, + 0x5af5, + 0x4ad4, + 0x7ab7, + 0x6a96, + 0x1a71, + 0x0a50, + 0x3a33, + 0x2a12, + 0xdbfd, + 0xcbdc, + 0xfbbf, + 0xeb9e, + 0x9b79, + 0x8b58, + 0xbb3b, + 0xab1a, + 0x6ca6, + 0x7c87, + 0x4ce4, + 0x5cc5, + 0x2c22, + 0x3c03, + 0x0c60, + 0x1c41, + 0xedae, + 0xfd8f, + 0xcdec, + 0xddcd, + 0xad2a, + 0xbd0b, + 0x8d68, + 0x9d49, + 0x7e97, + 0x6eb6, + 0x5ed5, + 0x4ef4, + 0x3e13, + 0x2e32, + 0x1e51, + 0x0e70, + 0xff9f, + 0xefbe, + 0xdfdd, + 0xcffc, + 0xbf1b, + 0xaf3a, + 0x9f59, + 0x8f78, + 0x9188, + 0x81a9, + 0xb1ca, + 0xa1eb, + 0xd10c, + 0xc12d, + 0xf14e, + 0xe16f, + 0x1080, + 0x00a1, + 0x30c2, + 0x20e3, + 0x5004, + 0x4025, + 0x7046, + 0x6067, + 0x83b9, + 0x9398, + 0xa3fb, + 0xb3da, + 0xc33d, + 0xd31c, + 0xe37f, + 0xf35e, + 0x02b1, + 0x1290, + 0x22f3, + 0x32d2, + 0x4235, + 0x5214, + 0x6277, + 0x7256, + 0xb5ea, + 0xa5cb, + 0x95a8, + 0x8589, + 0xf56e, + 0xe54f, + 0xd52c, + 0xc50d, + 0x34e2, + 0x24c3, + 0x14a0, + 0x0481, + 0x7466, + 0x6447, + 0x5424, + 0x4405, + 0xa7db, + 0xb7fa, + 0x8799, + 0x97b8, + 0xe75f, + 0xf77e, + 0xc71d, + 0xd73c, + 0x26d3, + 0x36f2, + 0x0691, + 0x16b0, + 0x6657, + 0x7676, + 0x4615, + 0x5634, + 0xd94c, + 0xc96d, + 0xf90e, + 0xe92f, + 0x99c8, + 0x89e9, + 0xb98a, + 0xa9ab, + 0x5844, + 0x4865, + 0x7806, + 0x6827, + 0x18c0, + 0x08e1, + 0x3882, + 0x28a3, + 0xcb7d, + 0xdb5c, + 0xeb3f, + 0xfb1e, + 0x8bf9, + 0x9bd8, + 0xabbb, + 0xbb9a, + 0x4a75, + 0x5a54, + 0x6a37, + 0x7a16, + 0x0af1, + 0x1ad0, + 0x2ab3, + 0x3a92, + 0xfd2e, + 0xed0f, + 0xdd6c, + 0xcd4d, + 0xbdaa, + 0xad8b, + 0x9de8, + 0x8dc9, + 0x7c26, + 0x6c07, + 0x5c64, + 0x4c45, + 0x3ca2, + 0x2c83, + 0x1ce0, + 0x0cc1, + 0xef1f, + 0xff3e, + 0xcf5d, + 0xdf7c, + 0xaf9b, + 0xbfba, + 0x8fd9, + 0x9ff8, + 0x6e17, + 0x7e36, + 0x4e55, + 0x5e74, + 0x2e93, + 0x3eb2, + 0x0ed1, + 0x1ef0 + ]; int crc_16(buffer) { var len = buffer.length; - var value_ = 0x0000;//0xa635; //初始值,根据CRC类型设定 + var value_ = 0x0000; //0xa635; //初始值,根据CRC类型设定 var tmp; - for (var i = 0; i < buffer.length; i++) - { + for (var i = 0; i < buffer.length; i++) { tmp = reverse8(buffer[i]); - value_ = ((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF; + value_ = + ((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF; } value_ = reverse16(value_); return value_; @@ -116,22 +360,21 @@ abstract class SenderProtocol extends IOData { int reverse8(data) { var i; - var temp=0; - for(i=0;i<8;i++) { + var temp = 0; + for (i = 0; i < 8; i++) { //字节反转 - temp |= ((data>>i) & 0x01)<<(7-i); + temp |= ((data >> i) & 0x01) << (7 - i); } return temp; } int reverse16(data) { var i; - var temp=0; - for(i=0;i<16;i++) { + var temp = 0; + for (i = 0; i < 16; i++) { //反转 - temp |= ((data>>i) & 0x0001)<<(15-i); + temp |= ((data >> i) & 0x0001) << (15 - i); } return temp; } - -} \ No newline at end of file +} diff --git a/star_lock/lib/blue/io_tool/io_model.dart b/star_lock/lib/blue/io_tool/io_model.dart index 9651fff6..018ce49d 100644 --- a/star_lock/lib/blue/io_tool/io_model.dart +++ b/star_lock/lib/blue/io_tool/io_model.dart @@ -1,15 +1,12 @@ - import 'package:uuid/uuid.dart'; ///发送数据类 -enum DataChannel{ - ble, - udp -} +enum DataChannel { ble, udp } extension Extension on DataChannel { - bool get isBLE => this == DataChannel.ble; - bool get isUDP => this == DataChannel.udp; + bool get isBLE => this == DataChannel.ble; + + bool get isUDP => this == DataChannel.udp; } class EventSendModel { @@ -20,8 +17,16 @@ class EventSendModel { String? deviceId; Uuid? serviceId; Uuid? characteristicId; + bool? allowLongWrite = false; - EventSendModel({required this.data,this.topic,this.sendChannel, this.deviceId, this.serviceId, this.characteristicId}); + EventSendModel( + {required this.data, + this.topic, + this.sendChannel, + this.deviceId, + this.serviceId, + this.characteristicId, + this.allowLongWrite}); } ///接收数据类 @@ -30,26 +35,23 @@ class EventReceiveModel { String? tag = ''; DataChannel? sendChannel; - EventReceiveModel({ - required this.data, - this.sendChannel, - this.tag}); + EventReceiveModel({required this.data, this.sendChannel, this.tag}); } - ///解析数据域 class EventParseModel { int? type; int? commandIndex; dynamic data; + EventParseModel({required this.type, required this.data, this.commandIndex}); } - ///debug info model class StateModel { final String title; final String subTitle; final bool result; - StateModel({this.title= '',this.subTitle = '',this.result = false}); -} \ No newline at end of file + + StateModel({this.title = '', this.subTitle = '', this.result = false}); +} diff --git a/star_lock/lib/blue/io_type.dart b/star_lock/lib/blue/io_type.dart index 4b919584..491bf6d9 100644 --- a/star_lock/lib/blue/io_type.dart +++ b/star_lock/lib/blue/io_type.dart @@ -1,4 +1,3 @@ - //TODO:发送指令类型 enum CommandType { addUser, //增加用户 = 0x3001 @@ -13,6 +12,9 @@ enum CommandType { getLockPrivateKey, // 获取锁私钥 = 0x3091 calibrationTime, // 校时 = 0x30f0 readStarLockStatusInfo, //读星锁状态信息 0x3040 + startOATUpgrade, //OTA升级开始 0x30E0 + confirmationOTAUpgrade, //OTA升级开始 0x30E1 + processOTAUpgrade, //OTA升级过程 0x30E2 generalExtendedCommond, // 通用扩展指令 = 0x3030 gecChangeAdministratorPassword, // 通用扩展指令子命令-修改管理员密码 = 2 @@ -41,11 +43,10 @@ enum CommandType { gecAddFaceConfirmation, // 通用扩展指令子命令-添加人脸确认 = 84 } -extension ExtensionCommandType on CommandType { - - static CommandType getCommandType(int value){ +extension ExtensionCommandType on CommandType { + static CommandType getCommandType(int value) { CommandType type = CommandType.readLockStatusInfo; - switch(value){ + switch (value) { case 0x3001: { type = CommandType.addUser; @@ -111,6 +112,21 @@ extension ExtensionCommandType on CommandType { type = CommandType.readStarLockStatusInfo; } break; + case 0x30E0: + { + type = CommandType.startOATUpgrade; + } + break; + case 0x30E1: + { + type = CommandType.processOTAUpgrade; + } + break; + case 0x30E2: + { + type = CommandType.confirmationOTAUpgrade; + } + break; default: { type = CommandType.readLockStatusInfo; @@ -122,7 +138,7 @@ extension ExtensionCommandType on CommandType { int get typeValue { int type = 0x300A; - switch(this){ + switch (this) { case CommandType.addUser: type = 0x3001; break; @@ -162,6 +178,15 @@ extension ExtensionCommandType on CommandType { case CommandType.readStarLockStatusInfo: type = 0x3040; break; + case CommandType.startOATUpgrade: + type = 0x30E0; + break; + case CommandType.processOTAUpgrade: + type = 0x30E1; + break; + case CommandType.confirmationOTAUpgrade: + type = 0x30E2; + break; default: type = 0x300A; break; @@ -171,10 +196,13 @@ extension ExtensionCommandType on CommandType { return type; } + //加密类型 int get identifierValue { int type = 0x23; - switch(this){ + switch (this) { case CommandType.getLockPublicKey: + case CommandType.processOTAUpgrade: + //不加密 type = 0x20; break; case CommandType.getLockPrivateKey: @@ -187,64 +215,73 @@ extension ExtensionCommandType on CommandType { return type; } - String get typeName { - String t = ''; - switch(typeValue){ + String get typeName { + String t = ''; + switch (typeValue) { case 0x3001: - t = '增加用户'; + t = '增加用户'; break; case 0x3002: - t = '删除用户'; + t = '删除用户'; break; case 0x3003: - t = '修改用户'; + t = '修改用户'; break; case 0x3004: - t = '恢复出厂设置'; + t = '恢复出厂设置'; break; case 0x3005: - t = '开门'; + t = '开门'; break; case 0x300A: - t = '读取锁状态信息'; + t = '读取锁状态信息'; break; case 0x300B: - t = '转移权限'; + t = '转移权限'; break; case 0x3020: - t = '开门记录上报'; + t = '开门记录上报'; break; case 0x3030: - t = '通用扩展指令'; + t = '通用扩展指令'; break; case 0x3090: - t = '获取锁公钥'; + t = '获取锁公钥'; break; case 0x3091: - t = '获取锁私钥'; + t = '获取锁私钥'; break; case 0x30f0: - t = '校时'; + t = '校时'; break; case 0x30f1: - t = '同步位置信息'; + t = '同步位置信息'; break; case 0x30f2: - t = '运维开锁'; + t = '运维开锁'; break; case 0x3016: - t = '写酒店信息'; + t = '写酒店信息'; break; case 0x3017: - t = '读酒店信息'; + t = '读酒店信息'; break; case 0x3040: - t = '读星锁状态信息'; + t = '读星锁状态信息'; + break; + case 0x30E0: + t = 'oat升级'; + break; + case 0x30E2: + t = '确认oat升级'; + break; + case 0x30E1: + t = 'oat升级过程'; break; default: - t = '读星锁状态信息'; + t = '读星锁状态信息'; break; } return t; } -} \ No newline at end of file +} diff --git a/star_lock/lib/blue/reciver_data.dart b/star_lock/lib/blue/reciver_data.dart index 7637dda2..a03e31c7 100644 --- a/star_lock/lib/blue/reciver_data.dart +++ b/star_lock/lib/blue/reciver_data.dart @@ -9,6 +9,8 @@ import 'package:star_lock/blue/io_protocol/io_deletUser.dart'; import 'package:star_lock/blue/io_protocol/io_editUser.dart'; import 'package:star_lock/blue/io_protocol/io_factoryDataReset.dart'; import 'package:star_lock/blue/io_protocol/io_getLockStatu.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_queryingFaceStatus.dart'; import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart'; import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart'; @@ -20,11 +22,14 @@ import 'package:star_lock/blue/io_protocol/io_timing.dart'; import 'package:star_lock/blue/io_protocol/io_transferPermissions.dart'; import '../tools/storage.dart'; + // import 'io_protocol/io_addFingerprint.dart'; import 'io_protocol/io_addFingerprintWithTimeCycleCoercion.dart'; + // import 'io_protocol/io_addICCard.dart'; import 'io_protocol/io_addICCardWithTimeCycleCoercion.dart'; import 'io_protocol/io_addStressFingerprint.dart'; + // import 'io_protocol/io_addStressICCard.dart'; import 'io_protocol/io_addStressPassword.dart'; import 'io_protocol/io_addUser.dart'; @@ -59,7 +64,7 @@ class CommandReciverManager { return; } - Get.log("appDataReceiveData:$data"); // &&(data[4] == 0x11) + // Get.log("appDataReceiveData:$data"); // &&(data[4] == 0x11) if ((data[0] == 0xEF) && (data[1] == 0x01) && (data[2] == 0xEE) && @@ -69,7 +74,7 @@ class CommandReciverManager { var dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度 var oriLen = data[10] * 256 + data[11]; // 低16位用来指示数据加密前的原长度 - print("dataLen:$dataLen oriLen:$oriLen"); + // print("dataLen:$dataLen oriLen:$oriLen"); // List dataList = []; List oriDataList = []; switch (tmpType) { @@ -109,11 +114,11 @@ class CommandReciverManager { oriDataList = SM4.decrypt(getDataList, key: getPrivateKeyList, mode: SM4CryptoMode.ECB); oriDataList = oriDataList.sublist(0, oriLen); - print("SM4 oriDataList:$oriDataList"); + // print("SM4 oriDataList:$oriDataList"); break; } parseData(oriDataList).then((value) async { - Get.log("parseData222 data:$value"); + // Get.log("parseData222 data:$value"); EasyLoading.dismiss(); await EventBusManager().eventBusFir(value); }).catchError((error) { @@ -129,7 +134,7 @@ class CommandReciverManager { CommandType commandType = ExtensionCommandType.getCommandType(cmd); await IoManager().increaseCommandIndex(); // data.removeRange(0, 2); - Get.log("parseData cmd:$cmd commandType:$commandType data:$data"); + // Get.log("parseData cmd:$cmd commandType:$commandType data:$data"); var reply; switch (commandType) { case CommandType.getLockPublicKey: @@ -154,7 +159,7 @@ class CommandReciverManager { break; case CommandType.openLock: { - Get.log("openLockReply data:$data"); + // Get.log("openLockReply data:$data"); reply = OpenDoorReply.parseData(commandType, data); } break; @@ -189,6 +194,21 @@ class CommandReciverManager { reply = GetStarLockStatuInfoReply.parseData(commandType, data); } break; + case CommandType.startOATUpgrade: + { + reply = OTAUpgradeReply.parseData(commandType, data); + } + break; + case CommandType.confirmationOTAUpgrade: + { + reply = ConfirmationOTAUpgradeReply.parseData(commandType, data); + } + break; + case CommandType.processOTAUpgrade: + { + reply = ProcessOtaUpgradeReply.parseData(commandType, data); + } + break; case CommandType.generalExtendedCommond: { // 子命令类型 @@ -279,8 +299,9 @@ class CommandReciverManager { case 36: { // 注册指纹开始(带限时、循环、胁迫...) - reply = SenderAddFingerprintWithTimeCycleCoercionReply.parseData( - commandType, data); + reply = + SenderAddFingerprintWithTimeCycleCoercionReply.parseData( + commandType, data); } break; case 40: diff --git a/star_lock/lib/blue/sender_data.dart b/star_lock/lib/blue/sender_data.dart index 90c45722..34c28c53 100644 --- a/star_lock/lib/blue/sender_data.dart +++ b/star_lock/lib/blue/sender_data.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import '../app_settings/app_settings.dart'; @@ -11,22 +10,26 @@ import 'io_tool/manager_event_bus.dart'; import 'sender_beforeDataManage.dart'; typedef CommandSendCallBack = void Function(ErrorType errorType); -class CommandSenderManager { +class CommandSenderManager { static final CommandSenderManager _manager = CommandSenderManager._init(); - factory CommandSenderManager()=>_manager; - static CommandSenderManager getInstance()=>_manager; - CommandSenderManager._init(){ + + factory CommandSenderManager() => _manager; + + static CommandSenderManager getInstance() => _manager; + + CommandSenderManager._init() { init(); } - init(){ + init() { initLockAddUserSucceedEvent(); } // 下级界面修改成功后传递数据 StreamSubscription? _passCurrentLockInformationEvent; List dataBeforeAddTheUser = []; + void initLockAddUserSucceedEvent() { // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus _passCurrentLockInformationEvent = eventBus.on().listen((event) { @@ -55,7 +58,7 @@ class CommandSenderManager { } List value = command.packageData(); - print("CommonDataManage().currentLockUserNo:${CommonDataManage().currentLockUserNo}"); + // print("CommonDataManage().currentLockUserNo:${CommonDataManage().currentLockUserNo}"); if(CommonDataManage().currentLockUserNo == 0){ // 先添加用户 var entity = await SenderBeforeDataManage().getAddUserKeyData(); @@ -63,7 +66,7 @@ class CommandSenderManager { dataBeforeAddTheUser = value; return; }else{ - print("继续发送数据了继续发送数据了继续发送数据了"); + // print("继续发送数据了继续发送数据了继续发送数据了"); _sendNormalData(value); } } @@ -132,4 +135,4 @@ class CommandSenderManager { dispose() { _passCurrentLockInformationEvent?.cancel(); } -} \ No newline at end of file +} diff --git a/star_lock/lib/blue/sender_manage.dart b/star_lock/lib/blue/sender_manage.dart index 95292dba..9f1ee9f5 100644 --- a/star_lock/lib/blue/sender_manage.dart +++ b/star_lock/lib/blue/sender_manage.dart @@ -1,9 +1,12 @@ import 'package:star_lock/blue/io_protocol/io_addFace.dart'; + // import 'package:star_lock/blue/io_protocol/io_addICCard.dart'; // import 'package:star_lock/blue/io_protocol/io_addStressICCard.dart'; import 'package:star_lock/blue/io_protocol/io_changeAdministratorPassword.dart'; import 'package:star_lock/blue/io_protocol/io_deletUser.dart'; import 'package:star_lock/blue/io_protocol/io_getLockStatu.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_queryingFaceStatus.dart'; import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart'; @@ -359,23 +362,22 @@ class IoSenderManage { //todo:添加指纹开始(带限时、循环、胁迫...) static void senderAddFingerprintWithTimeCycleCoercionCommand( - { - required String? keyID, - required String? userID, - required int? fingerNo, - required int? useCountLimit, - required int? isForce, - required List? token, - required int? isRound, - required int? weekRound, - required int? startDate, - required int? endDate, - required String? startTime, - required String? endTime, - required int? needAuthor, - required List? signKey, - required List? privateKey, - CommandSendCallBack? callBack}) { + {required String? keyID, + required String? userID, + required int? fingerNo, + required int? useCountLimit, + required int? isForce, + required List? token, + required int? isRound, + required int? weekRound, + required int? startDate, + required int? endDate, + required String? startTime, + required String? endTime, + required int? needAuthor, + required List? signKey, + required List? privateKey, + CommandSendCallBack? callBack}) { CommandSenderManager().managerSendData( command: SenderAddFingerprintWithTimeCycleCoercionCommand( keyID: keyID, @@ -428,23 +430,22 @@ class IoSenderManage { //todo:添加卡开始(带限时、循环、胁迫...) static void senderAddCardWithTimeCycleCoercionCommand( - { - required String? keyID, - required String? userID, - required int? cardNo, - required int? useCountLimit, - required int? isForce, - required List? token, - required int? isRound, - required int? weekRound, - required int? startDate, - required int? endDate, - required String? startTime, - required String? endTime, - required int? needAuthor, - required List? signKey, - required List? privateKey, - CommandSendCallBack? callBack}) { + {required String? keyID, + required String? userID, + required int? cardNo, + required int? useCountLimit, + required int? isForce, + required List? token, + required int? isRound, + required int? weekRound, + required int? startDate, + required int? endDate, + required String? startTime, + required String? endTime, + required int? needAuthor, + required List? signKey, + required List? privateKey, + CommandSendCallBack? callBack}) { CommandSenderManager().managerSendData( command: SenderAddICCardWithTimeCycleCoercionCommand( keyID: keyID, @@ -469,20 +470,20 @@ class IoSenderManage { //todo:添加人脸开始 static void senderAddFaceCommand( {required String? keyID, - required String? userID, - required int? faceNo, - required int? useCountLimit, - required int? isForce, - required List? token, - required int? isRound, - required int? weekRound, - required int? startDate, - required int? endDate, - required String? startTime, - required String? endTime, - required int? needAuthor, - required List? signKey, - required List? privateKey, + required String? userID, + required int? faceNo, + required int? useCountLimit, + required int? isForce, + required List? token, + required int? isRound, + required int? weekRound, + required int? startDate, + required int? endDate, + required String? startTime, + required String? endTime, + required int? needAuthor, + required List? signKey, + required List? privateKey, CommandSendCallBack? callBack}) { CommandSenderManager().managerSendData( command: SenderAddFaceCommand( @@ -709,12 +710,12 @@ class IoSenderManage { //todo:wifi列表 static void getWifiListCommand( {required String? keyID, - required String? userID, - required List? token, - required int? needAuthor, - required List? publicKey, - required List? privateKey, - CommandSendCallBack? callBack}) { + required String? userID, + required List? token, + required int? needAuthor, + required List? publicKey, + required List? privateKey, + CommandSendCallBack? callBack}) { CommandSenderManager().managerSendData( command: SenderGetWifiCommand( keyID: keyID, @@ -977,4 +978,54 @@ class IoSenderManage { ), callBack: callBack); } + + //开始ota 升级 + static void senderOTAUpgradeCommand( + {required String? lockID, + required String? userID, + required String? keyID, + required int? platform, + required int? product, + required String? hwVersion, + required String? fwVersion, + required int? fwSize, + required String? fwMD5, + required int? needAuthor, + required List? token, + required List? publicKey, + required List? privateKey, + CommandSendCallBack? callBack}) { + CommandSenderManager().managerSendData( + command: OTAUpgradeCommand( + lockID: lockID, + userID: userID, + keyID: keyID, + platform: platform, + product: product, + hwVersion: hwVersion, + fwVersion: fwVersion, + fwSize: fwSize, + fwMD5: fwMD5, + token: token, + needAuthor: needAuthor, + publicKey: publicKey, + privateKey: privateKey, + ), + callBack: callBack); + } + + //ota 升级过程 + static void senderProcessOtaUpgradeCommand( + {required int? index, + required int? size, + required List? data, + CommandSendCallBack? callBack}) { + CommandSenderManager().managerSendData( + command: ProcessOtaUpgradeCommand( + index: index, + size: size, + data: data, + ), + callBack: callBack); + } } diff --git a/star_lock/lib/main/lockDetail/card/addCardType/addCardManage/addCardTypeManage_tabbar.dart b/star_lock/lib/main/lockDetail/card/addCardType/addCardManage/addCardTypeManage_tabbar.dart index db9c485d..12d283e2 100644 --- a/star_lock/lib/main/lockDetail/card/addCardType/addCardManage/addCardTypeManage_tabbar.dart +++ b/star_lock/lib/main/lockDetail/card/addCardType/addCardManage/addCardTypeManage_tabbar.dart @@ -50,6 +50,7 @@ class _AddCardManageTabbarState extends State length: widget.fromType == 1 ? _itemTabs.length : _fromCheckInTypeItemTabs.length, initialIndex: widget.initialIndex); _tabController.addListener(() { + print("_tabController.indexIsChanging:${_tabController.indexIsChanging} _tabController.index:${_tabController.index}"); if (_tabController.animation!.value == _tabController.index) { FocusScope.of(context).requestFocus(FocusNode()); } @@ -107,8 +108,8 @@ class _AddCardManageTabbarState extends State controller: _tabController, children: widget.fromType == 1 - ? _itemTabs.map((ItemView item) => AddCardPage(selectType: item.selectType, lockId: widget.lockId, fromType: widget.fromType, fromTypeTwoStaffName: widget.fromTypeTwoStaffName)).toList() - : _fromCheckInTypeItemTabs.map((ItemView item) => AddCardPage(selectType: item.selectType, lockId: widget.lockId, fromType: widget.fromType, fromTypeTwoStaffName: widget.fromTypeTwoStaffName)).toList(), + ? _itemTabs.map((ItemView item) => AddCardPage()).toList() + : _fromCheckInTypeItemTabs.map((ItemView item) => AddCardPage()).toList(), ), ); } diff --git a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_logic.dart b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_logic.dart index ad989d33..ab7f5561 100644 --- a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_logic.dart +++ b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_logic.dart @@ -12,21 +12,23 @@ class AddCardTypeLogic extends BaseGetXController{ // 添加卡数据 void addCardData() async { - var fingerprintType = 0; // 永久:1;限时2,单次3,循环:4 + var carType = 0; // 永久:1;限时2,单次3,循环:4 var startDate = ""; var endDate = ""; var startTime = ""; var endTime = ""; if (state.selectType.value == "0") { - fingerprintType = 1; + print("永久卡永久卡永久卡"); + carType = 1; startDate = "0"; endDate = "0"; startTime = "0"; endTime = "0"; } else if (state.selectType.value == "1") { - fingerprintType = 2; - startDate = DateTool().dateToTimestamp(state.beginTime.value, 1).toString(); - endDate = DateTool().dateToTimestamp(state.endTime.value, 1).toString(); + print("限时卡限时卡限时卡"); + carType = 2; + startDate = DateTool().dateToTimestamp(state.timeLimitBeginTime.value, 1).toString(); + endDate = DateTool().dateToTimestamp(state.timeLimitEndTime.value, 1).toString(); startTime = "0"; endTime = "0"; @@ -49,15 +51,16 @@ class AddCardTypeLogic extends BaseGetXController{ return; } } else if (state.selectType.value == "2") { - if (state.beginTime.value.isEmpty) { + print("循环卡循环卡循环卡"); + if (state.cycleBeginTime.value.isEmpty) { showToast("请选择有效期".tr); return; } - startDate = DateTool().dateToTimestamp(state.beginTime.value, 1).toString(); - endDate = DateTool().dateToTimestamp(state.endTime.value, 1).toString(); + startDate = DateTool().dateToTimestamp(state.cycleBeginTime.value, 1).toString(); + endDate = DateTool().dateToTimestamp(state.cycleEndTime.value, 1).toString(); startTime = DateTool().dateToTimestamp(state.effectiveDateTime.value, 0).toString(); endTime = DateTool().dateToTimestamp(state.failureDateTime.value, 0).toString(); - fingerprintType = 4; + carType = 4; } // var isCoerced = state.isStressFingerprint.value == false ? "1" : "2"; // 1:非胁迫卡 2:胁迫卡 @@ -67,7 +70,7 @@ class AddCardTypeLogic extends BaseGetXController{ "addType": "1", "cardName": state.nameController.text, "cardNumber": "123456", - "cardType": fingerprintType.toString(), + "cardType": carType.toString(), "isCoerced": state.isStressFingerprint.value == false ? "1" : "2", "startDate": startDate, "weekDay": state.weekdaysList.value, diff --git a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart index c17cddb9..feba7075 100644 --- a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart +++ b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_page.dart @@ -1,3 +1,4 @@ + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -8,110 +9,113 @@ import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; +import '../../../../tools/CustomUnderlineTabIndicator.dart'; import '../../../../tools/commonItem.dart'; import '../../../../tools/dateTool.dart'; import '../../../../tools/storage.dart'; import '../../../../tools/submitBtn.dart'; +import '../../../../tools/titleAppBar.dart'; import '../../../../translations/trans_lib.dart'; import 'addCardType_logic.dart'; class AddCardPage extends StatefulWidget { - final String selectType; // 永久限时循环下标 - final int lockId; - final int fromType; // // 1从添加钥匙列表进入 2从考勤添加员工入口进入 - final String fromTypeTwoStaffName; // 从添加员工进入 传入员工名字 - - const AddCardPage( - {Key? key, - required this.selectType, - required this.lockId, - required this.fromType, - required this.fromTypeTwoStaffName}) - : super(key: key); + const AddCardPage({Key? key}) : super(key: key); @override State createState() => _AddCardPageState(); } -class _AddCardPageState extends State { +class _AddCardPageState extends State with SingleTickerProviderStateMixin { final logic = Get.put(AddCardTypeLogic()); final state = Get.find().state; - @override - Widget build(BuildContext context) { - state.selectType.value = widget.selectType; - state.lockId.value = widget.lockId; - if (widget.fromTypeTwoStaffName.isNotEmpty) { - state.nameController.text = widget.fromTypeTwoStaffName; - } - state.fromType.value = widget.fromType; - - return SingleChildScrollView( - child: indexChangeWidget() - ); - } - @override void initState() { // TODO: implement initState super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - if (state.selectType.value == "1") { - state.beginTime.value = DateTool().dateToYMDHNString( - DateTime.now().millisecondsSinceEpoch.toString()); //默认为当前时间 - state.endTime.value = DateTool().dateToYMDHNString( - DateTime.now().millisecondsSinceEpoch.toString()); //默认为当前时间 - } else { - state.beginTime.value = ""; //默认为当前时间 - state.endTime.value = ""; //默认为当前时间 + state.tabController = TabController( + vsync: this, + length: state.fromType.value == 1 ? _itemTabs.length : _fromCheckInTypeItemTabs.length, + initialIndex: 0); + state.tabController.addListener(() { + WidgetsBinding.instance.addPostFrameCallback((_) { + state.selectType.value = state.tabController.index.toString(); + }); + + if (state.tabController.animation!.value == state.tabController.index) { + FocusScope.of(context).requestFocus(FocusNode()); } }); } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.mainBackgroundColor, + appBar: TitleAppBar( + barTitle: + "${TranslationLoader.lanKeys!.addTip!.tr}${TranslationLoader.lanKeys!.card!.tr}", + haveBack: true, + backgroundColor: AppColors.mainColor), + body: Column( + children: [ + _tabBar(), + _pageWidget(), + ], + ), + ); + } Widget indexChangeWidget() { - switch (int.parse(widget.selectType)) { + switch (int.parse(state.selectType.value)) { case 0: { // 永久 - return Column( - children: [ - perpetualKeyWidget( - TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, - state.nameController), - keyBottomWidget() - ], + return SingleChildScrollView( + child: Column( + children: [ + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), + keyBottomWidget() + ], + ), ); } case 1: { // 限时 - return Column( - children: [ - perpetualKeyWidget( - TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, - state.nameController), - keyTimeLimitWidget(), - // SizedBox(height: 10.h), - keyBottomWidget() - ], + return SingleChildScrollView( + child: Column( + children: [ + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), + keyTimeLimitWidget(), + // SizedBox(height: 10.h), + keyBottomWidget() + ], + ), ); } case 2: { // 循环 - return Column( - children: [ - perpetualKeyWidget( - TranslationLoader.lanKeys!.name!.tr, - TranslationLoader.lanKeys!.pleaseEnter!.tr, - state.nameController), - keyCyclicDate(), - SizedBox(height: 10.h), - keyBottomWidget() - ], + return SingleChildScrollView( + child: Column( + children: [ + perpetualKeyWidget( + TranslationLoader.lanKeys!.name!.tr, + TranslationLoader.lanKeys!.pleaseEnter!.tr, + state.nameController), + keyCyclicDate(), + SizedBox(height: 10.h), + keyBottomWidget() + ], + ), ); } default: @@ -140,23 +144,23 @@ class _AddCardPageState extends State { children: [ Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.effectiveTime!.tr, - rightTitle: state.beginTime.value, + rightTitle: state.timeLimitBeginTime.value, isHaveLine: true, isHaveDirection: true, action: () async { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - state.beginTime.value = DateTool().getYMDHNDateString(p, 1); + state.timeLimitBeginTime.value = DateTool().getYMDHNDateString(p, 1); }); })), Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, - rightTitle: state.endTime.value, + rightTitle: state.timeLimitEndTime.value, isHaveDirection: true, action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - state.endTime.value = DateTool().getYMDHNDateString(p, 1); + state.timeLimitEndTime.value = DateTool().getYMDHNDateString(p, 1); }); })), Container(height: 10.h), @@ -170,21 +174,21 @@ class _AddCardPageState extends State { children: [ Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.periodValidity!.tr, - rightTitle: "${state.beginTime.value}\n${state.endTime.value}", + rightTitle:"${state.cycleBeginTime.value}\n${state.cycleEndTime.value}", isHaveDirection: true, isHaveLine: true, action: () async { var result = await Get.toNamed(Routers.seletKeyCyclicDatePage, arguments: { 'validityValue': state.weekdaysList.value, - 'starDate': state.beginTime.value, - 'endDate': state.endTime.value, + 'starDate': state.cycleBeginTime.value, + 'endDate': state.cycleEndTime.value, 'starTime': state.effectiveDateTime.value, 'endTime': state.failureDateTime.value }); if (result != null && result.isNotEmpty) { state.weekdaysList.value = result['validityValue']; - state.beginTime.value = result['starDate']; - state.endTime.value = result['endDate']; + state.cycleBeginTime.value = result['starDate']; + state.cycleEndTime.value = result['endDate']; state.effectiveDateTime.value = result['starTime']; state.failureDateTime.value = result['endTime']; } @@ -197,18 +201,17 @@ class _AddCardPageState extends State { isHaveDirection: true, isHaveLine: true, action: () async { - var result = await Get.toNamed(Routers.seletKeyCyclicDatePage, - arguments: { - 'validityValue': state.weekdaysList.value, - 'starDate': state.beginTime.value, - 'endDate': state.endTime.value, - 'starTime': state.effectiveDateTime.value, - 'endTime': state.failureDateTime.value - }); + var result = await Get.toNamed(Routers.seletKeyCyclicDatePage, arguments: { + 'validityValue': state.weekdaysList.value, + 'starDate': state.cycleBeginTime.value, + 'endDate': state.cycleEndTime.value, + 'starTime': state.effectiveDateTime.value, + 'endTime': state.failureDateTime.value + }); if (result != null && result.isNotEmpty) { state.weekdaysList.value = result['validityValue']; - state.beginTime.value = result['starDate']; - state.endTime.value = result['endDate']; + state.cycleBeginTime.value = result['starDate']; + state.cycleEndTime.value = result['endDate']; state.effectiveDateTime.value = result['starTime']; state.failureDateTime.value = result['endTime']; } @@ -217,25 +220,22 @@ class _AddCardPageState extends State { visible: state.effectiveDateTime.value.isNotEmpty, child: CommonItem( leftTitel: "有效时间".tr, - rightTitle: - "${state.effectiveDateTime.value}-${state.failureDateTime.value}", + rightTitle: "${state.effectiveDateTime.value}-${state.failureDateTime.value}", isHaveDirection: true, action: () async { - var result = await Get.toNamed(Routers.seletKeyCyclicDatePage, - arguments: { - 'validityValue': state.weekdaysList.value, - 'starDate': state.beginTime.value, - 'endDate': state.endTime.value, - 'starTime': state.effectiveDateTime.value, - 'endTime': state.failureDateTime.value - }); + var result = await Get.toNamed(Routers.seletKeyCyclicDatePage, arguments: { + 'validityValue': state.weekdaysList.value, + 'starDate': state.cycleBeginTime.value, + 'endDate': state.cycleEndTime.value, + 'starTime': state.effectiveDateTime.value, + 'endTime': state.failureDateTime.value + }); if (result != null && result.isNotEmpty) { state.weekdaysList.value = result['validityValue']; - state.beginTime.value = result['starDate']; - state.endTime.value = result['endDate']; + state.cycleBeginTime.value = result['starDate']; + state.cycleEndTime.value = result['endDate']; state.effectiveDateTime.value = result['starTime']; state.failureDateTime.value = result['endTime']; - Get.back(result: result); } }))), ], @@ -290,25 +290,6 @@ class _AddCardPageState extends State { ); } - String getAppBarTitle(int type) { - String title; - switch (type) { - case 0: - title = TranslationLoader.lanKeys!.stressCard!.tr; - break; - case 1: - title = TranslationLoader.lanKeys!.stressFingerprint!.tr; - break; - case 2: - title = TranslationLoader.lanKeys!.remoteControl!.tr; - break; - default: - title = ""; - break; - } - return title; - } - // 接受者信息输入框 Widget getTFWidget(String tfStr) { return Container( @@ -387,4 +368,70 @@ class _AddCardPageState extends State { }, ); } + + final List _itemTabs = [ + ItemView(title: TranslationLoader.lanKeys!.permanent!.tr, selectType: "0"), + ItemView(title: TranslationLoader.lanKeys!.timeLimit!.tr, selectType: "1"), + ItemView(title: TranslationLoader.lanKeys!.circulation!.tr, selectType: "2"), + ]; + + final List _fromCheckInTypeItemTabs = [ + ItemView(title: TranslationLoader.lanKeys!.permanent!.tr, selectType: "0"), + ItemView(title: TranslationLoader.lanKeys!.timeLimit!.tr, selectType: "1"), + ]; + + TabBar _tabBar() { + return TabBar( + controller: state.tabController, + onTap: (index) { + FocusScope.of(context).requestFocus(FocusNode()); + }, + tabs: state.fromType.value == 1 ? _itemTabs.map((ItemView item) => _tab(item)).toList() : _fromCheckInTypeItemTabs.map((ItemView item) => _tab(item)).toList(), + isScrollable: true, + indicatorColor: Colors.red, + unselectedLabelColor: Colors.black, + unselectedLabelStyle: TextStyle( + color: AppColors.mainColor, + fontSize: 24.sp, + ), + automaticIndicatorColorAdjustment: true, + labelColor: AppColors.mainColor, + labelStyle: TextStyle( + color: AppColors.mainColor, + fontSize: 24.sp, + fontWeight: FontWeight.w600), + indicator: CustomUnderlineTabIndicator( + borderSide: BorderSide(color: AppColors.mainColor, width: 4.w), + strokeCap: StrokeCap.round, + width: 30.w), + ); + } + + Tab _tab(ItemView item) { + return Tab( + child: SizedBox( + width: 1.sw / 5, + child: Text(item.title, textAlign: TextAlign.center))); + } + + Widget _pageWidget() { + return Expanded( + child: TabBarView( + controller: state.tabController, + children: + state.fromType.value == 1 + ? _itemTabs.map((ItemView item) => Obx(() => indexChangeWidget())).toList() + : _fromCheckInTypeItemTabs.map((ItemView item) => Obx(() => indexChangeWidget())).toList(), + ), + ); + } + } + +class ItemView { + const ItemView({required this.title, required this.selectType}); + + final String title; + final String selectType; +} + diff --git a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_state.dart b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_state.dart index 411be2e8..1c234082 100644 --- a/star_lock/lib/main/lockDetail/card/addCardType/addCardType_state.dart +++ b/star_lock/lib/main/lockDetail/card/addCardType/addCardType_state.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import '../../../../tools/dateTool.dart'; + class AddCardTypeState{ final lockId = 0.obs; @@ -10,16 +12,24 @@ class AddCardTypeState{ final isStressFingerprint = false.obs; final isAdministrator = false.obs;// 是否是管理员 - var beginTime = "".obs;// 开始时间 - var endTime = "".obs;// 结束时间 + var timeLimitBeginTime = DateTool().dateToYMDHNString(DateTime.now().millisecondsSinceEpoch.toString()).obs;// 限时开始时间 + var timeLimitEndTime = DateTool().dateToYMDHNString(DateTime.now().millisecondsSinceEpoch.toString()).obs;// 限时结束时间 + var cycleBeginTime = "".obs;// 循环开始时间 + var cycleEndTime = "".obs;// 循环结束时间 var effectiveDateTime = "".obs;// 生效时间 var failureDateTime = "".obs;// 失效时间 var weekdaysList = [].obs; + var fromTypeTwoStaffName = "".obs; // 从添加员工进入 传入员工名字 final TextEditingController nameController = TextEditingController(); + late TabController tabController; AddCardTypeState() { - // Map map = Get.arguments; - // lockId.value = map["lockId"]; - // fromType.value = map["fromType"]; + Map map = Get.arguments; + lockId.value = map["lockId"]; + fromType.value = map["fromType"]; + // 1从添加钥匙列表进入 2从考勤添加员工入口进入 + if(fromType.value == 2){ + fromTypeTwoStaffName.value = map["fromTypeTwoStaffName"]; // 从添加员工进入 传入员工名字 + } } } diff --git a/star_lock/lib/main/lockDetail/card/cardList/cardList_page.dart b/star_lock/lib/main/lockDetail/card/cardList/cardList_page.dart index 4e1c399c..47508f6c 100644 --- a/star_lock/lib/main/lockDetail/card/cardList/cardList_page.dart +++ b/star_lock/lib/main/lockDetail/card/cardList/cardList_page.dart @@ -104,7 +104,7 @@ class _CardListPageState extends State with RouteAware { AddBottomWhiteBtn( btnName: '${TranslationLoader.lanKeys!.add!.tr}${TranslationLoader.lanKeys!.card!.tr}', onClick: () async { - var data = await Get.toNamed(Routers.addCardTypeManagePage, arguments: { + var data = await Get.toNamed(Routers.addCardPage, arguments: { "lockId": state.lockId.value, "fromType": 1 // 1从添加钥匙列表进入 2从考勤添加员工入口进入 }); diff --git a/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_page.dart b/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_page.dart index ba974948..385570d5 100644 --- a/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_page.dart +++ b/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_page.dart @@ -151,7 +151,7 @@ class _CheckingInAddStaffPageState extends State { } var data = await Get.toNamed( - Routers.addCardTypeManagePage, + Routers.addCardPage, arguments: { "lockId": state.getKeyInfosData.value.lockId, "fromType": 2, // 1从添加钥匙列表进入 2从考勤添加员工入口进入 diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index 99bce8e2..72f72823 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -34,7 +34,7 @@ class LockDetailLogic extends BaseGetXController { // 监听设备返回的数据 void initReplySubscription() { state.replySubscription = EventBusManager().eventBus!.on().listen((reply) async { - Get.log("锁详情收到了蓝牙解析消息 reply:${reply.commandType}"); + // Get.log("锁详情收到了蓝牙解析消息 reply:${reply.commandType}"); // 开门 if (reply is OpenDoorReply && state.ifCurrentScreen.value == true) { _replyOpenLock(reply); @@ -496,7 +496,7 @@ class LockDetailLogic extends BaseGetXController { void getLockNetToken() async { LockNetTokenEntity entity = await ApiRepository.to.getLockNetToken(lockId: state.keyInfos.value.lockId.toString()); if (entity.errorCode!.codeIsSuccessful) { - state.lockNetToken = entity.data!.token!; + state.lockNetToken = entity.data!.token!.toString(); Get.log("state.lockNetToken:${state.lockNetToken}"); openDoorAction(); }else{ diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockNetToken_entity.dart b/star_lock/lib/main/lockDetail/lockDetail/lockNetToken_entity.dart index fc74063a..b1be8d76 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockNetToken_entity.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockNetToken_entity.dart @@ -27,7 +27,7 @@ class LockNetTokenEntity { } class Data { - String? token; + int? token; Data({this.token}); diff --git a/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_logic.dart b/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_logic.dart index 9c5cfb7e..69eb2bac 100644 --- a/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_logic.dart +++ b/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_logic.dart @@ -1,14 +1,41 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; - +import 'package:crypto/crypto.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:get/get.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:star_lock/blue/blue_manage.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_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/blue/sender_manage.dart'; +import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSet_logic.dart'; +import 'package:star_lock/permission/permission_dialog.dart'; +import 'package:star_lock/tools/advancedCalendar/src/datetime_util.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/commonDataManage.dart'; +import 'package:star_lock/tools/pickers/time_picker/time_utils.dart'; +import 'package:star_lock/tools/storage.dart'; import 'lockEscalation_state.dart'; -class LockEscalationLogic extends BaseGetXController{ +class LockEscalationLogic extends BaseGetXController { LockEscalationState state = LockEscalationState(); + StreamSubscription? _replySubscription; + + int otaCount = 0; + int otaIndex = 0; + Uint8List? otaBin; + int startSecond = 0; // 锁升级 - Future setLockSetGeneralSetting() async{ + Future setLockSetGeneralSetting() async { // var entity = await ApiRepository.to.getLockVersionInfoData( // lockId: state.getKeyInfosData.value.lockId.toString(), // ); @@ -17,24 +44,193 @@ class LockEscalationLogic extends BaseGetXController{ // } } + //手动升级 + Future otaUpdate() async { + var status = await PermissionDialog.request( + Permission.storage, '需要访问读写权限才能使用手动升级固件'); + if (status != true) { + return; + } + FilePickerResult? result = await FilePicker.platform.pickFiles(); + if (result == null || result.files.single.path is! String) { + return; + } + File file = File(result.files.single.path!); + Uint8List data = await file.readAsBytes(); + Map? headJson = await getHeadFile(data); + if (headJson is! Map) { + return; + } + otaBin = await checkFile(data, headJson); + if (otaBin == null) { + return; + } + startOTAData(); + blueOTAUpgrade(headJson); + } + + //蓝牙操作 ota 升级 + void blueOTAUpgrade(Map data) { + BlueManage().bludSendData(BlueManage().connectDeviceName, + (BluetoothConnectionState deviceConnectionState) async { + if (deviceConnectionState == BluetoothConnectionState.connected) { + var privateKey = await Storage.getStringList(saveBluePrivateKey); + List getPrivateKeyList = changeStringListToIntList(privateKey!); + var token = await Storage.getStringList(saveBlueToken); + List getTokenList = changeStringListToIntList(token!); + var publicKey = await Storage.getStringList(saveBluePublicKey); + List getPublicKeyList = changeStringListToIntList(publicKey!); + String lockID = CommonDataManage.shareManager() + ?.currentLockSetInfoData + .lockId + ?.toString() ?? + ''; + String keyID = + CommonDataManage.shareManager()?.currentKeyInfo.keyId?.toString() ?? + ''; + BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand( + lockID: lockID, + userID: await Storage.getUid(), + keyID: keyID, + platform: int.tryParse(data['platform']) ?? 0, + product: int.tryParse(data['product']) ?? 0, + hwVersion: data['hwVersion'], + fwVersion: data['fwVersion'], + fwSize: data['fwSize'], + fwMD5: data['fwMd5'], + needAuthor: 1, + token: getTokenList, + publicKey: getPublicKeyList, + privateKey: getPrivateKeyList) + .packageData()); + } else if (deviceConnectionState == + BluetoothConnectionState.disconnected) {} + }); + } + + //循环传输升级固件包 + Future processOtaUpgrade() async { + if (!state.otaUpdateIng.value) { + return; + } + int length = otaBin?.length ?? 0; + if (otaCount == 0) { + //首次 + int difference = length % 240; + otaCount = length ~/ 240 + (difference > 0 ? 1 : 0); + startSecond = DateTime.now().millisecondsSinceEpoch ~/ 1000; + } + if (otaCount <= otaIndex) { + int now = DateTime.now().millisecondsSinceEpoch ~/ 1000; + String msg = '传输完成 时间:${now - startSecond}秒'; + closeOTADAta(); + print(msg); + showToast(msg); + return; + } + int star = otaIndex * 240; + int end = (otaIndex + 1) * 240; + if (end > length) { + end = length; + } + List data = otaBin!.sublist(star, end); + state.otaProgress.value = otaIndex / otaCount; + await BlueManage().writeCharacteristicWithResponse( + ProcessOtaUpgradeCommand(index: otaIndex, size: length, data: data) + .packageData()); + } + + //开始 ota升级 + void startOTAData() { + state.otaUpdateIng.value = true; + } + + //清楚 ata 安装文件 + void closeOTADAta() { + state.otaUpdateIng.value = false; + state.otaProgress.value = 0; + otaIndex = 0; + otaCount = 0; + startSecond = 0; + otaBin = null; + } + +// 拦截返回事件 + void getBack() { + if (state.otaUpdateIng.value) { + closeOTADAta(); + } else { + Get.back(); + } + } + +// 检查文件头 + Future getHeadFile(Uint8List data) async { + // 检查文件头 + String header = utf8.decode(data.sublist(0, 12)); + if (header != 'SYD-BIN-DATA') { + showToast('非SYD固件,请选择正确的文件'); + return null; + } + // 解析元数据长度 + Uint8List metaLenList = data.sublist(12, 16); + int metaLen = ByteData.sublistView(metaLenList).getUint32(0); + if (metaLen < 2 || metaLen > 10240) { + showToast('元数据长度错误'); + return null; + } + // 读取和解析元数据 + Uint8List metaStrList = data.sublist(16, 16 + metaLen); + String metaStr = utf8.decode(metaStrList); + print(metaStr); + var meta = jsonDecode(metaStr); + return meta..['metaLen'] = metaLen; + } + + //检测升级文件并读取 bin + Future checkFile(Uint8List data, Map meta) async { + num binOffset = 16 + (meta['metaLen'] ?? 0); + // 获取固件数据部分 + Uint8List bin = data.sublist(binOffset.toInt(), data.length); + //md5 校验有问题,暂时不解析 + // String md5Str = md5.convert(bin).toString(); + // if (md5Str != meta['fwMd5']) { + // showToast('固件MD5校验失败'); + // return false; + // } + if (bin.length != meta['fwSize']) { + showToast('固件校验失败'); + return null; + } + return bin; + } + @override void onReady() { - // TODO: implement onReady super.onReady(); - print("onReady()"); setLockSetGeneralSetting(); } @override void onInit() { - // TODO: implement onInit super.onInit(); - print("onInit()"); + _replySubscription = + EventBusManager().eventBus!.on().listen((reply) { + if (reply is OTAUpgradeReply && reply.status == 0x00) { + //验证通过,开始发送数据包 + processOtaUpgrade(); + } else if (reply is ProcessOtaUpgradeReply && reply.status == 0x00) { + otaIndex++; + processOtaUpgrade(); + } else if (reply is ConfirmationOTAUpgradeReply && reply.status == 0x00) { + closeOTADAta(); + showToast('固件升级完成'); + } + }); } @override void onClose() { - // TODO: implement onClose + _replySubscription?.cancel(); } - } diff --git a/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_page.dart b/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_page.dart index 5826a4f7..dde24faa 100644 --- a/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_page.dart +++ b/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_page.dart @@ -16,66 +16,152 @@ class LockEscalationPage extends StatefulWidget { } class _LockEscalationPageState extends State { - final logic = Get.put(LockEscalationLogic()); - final state = Get.find().state; - @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: TitleAppBar( - barTitle: TranslationLoader.lanKeys!.lockEscalation!.tr, - haveBack: true, - backgroundColor: AppColors.mainColor), - body: Container( - padding: EdgeInsets.all(30.w), - child: Column( - children: [ - SizedBox( - height: 60.h, + return GetBuilder( + init: LockEscalationLogic(), + builder: (LockEscalationLogic logic) { + return Scaffold( + backgroundColor: Colors.white, + appBar: TitleAppBar( + barTitle: TranslationLoader.lanKeys!.lockEscalation!.tr, + haveBack: true, + backgroundColor: AppColors.mainColor, + backAction: logic.getBack, ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'images/main/icon_main_lockSet_lockEscalation.png', - width: 36.w, - height: 36.w, - ), - SizedBox( - width: 10.w, - ), - Text( - TranslationLoader.lanKeys!.haveNewVersion!.tr, - style: - TextStyle(fontSize: 24.sp, fontWeight: FontWeight.w600), - ) - ], - ), - SizedBox( - height: 30.h, - ), - Text( - "${TranslationLoader.lanKeys!.currentVersion!.tr}:1.0.0", - style: TextStyle( - fontSize: 18.sp, color: AppColors.darkGrayTextColor), - ), - SizedBox( - height: 10.h, - ), - Text( - // "${TranslationLoader.lanKeys!.newVersion!.tr}:1.0.1", - "未发现新版本", - style: TextStyle(color: AppColors.mainColor, fontSize: 18.sp), - ), - SizedBox( - height: 40.h, - ), - SubmitBtn( - btnName: TranslationLoader.lanKeys!.upgrade!.tr, - onClick: () {}), - ], - ), - )); + body: Container( + padding: EdgeInsets.all(30.w), + child: Column( + children: [ + Obx(() { + return logic.state.otaUpdateIng.value + ? PopScope( + canPop: false, + onPopInvoked: (didPop) async { + if (logic.state.otaUpdateIng.value) { + logic.closeOTADAta(); + } + }, + child: SizedBox(), + ) + : SizedBox(); + }), + SizedBox( + height: 60.h, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'images/main/icon_main_lockSet_lockEscalation.png', + width: 36.w, + height: 36.w, + ), + SizedBox( + width: 10.w, + ), + Text( + TranslationLoader.lanKeys!.haveNewVersion!.tr, + style: TextStyle( + fontSize: 24.sp, fontWeight: FontWeight.w600), + ) + ], + ), + SizedBox( + height: 30.h, + ), + Text( + "${TranslationLoader.lanKeys!.currentVersion!.tr}:1.0.0", + style: TextStyle( + fontSize: 18.sp, color: AppColors.darkGrayTextColor), + ), + SizedBox( + height: 10.h, + ), + Obx(() { + return !logic.state.otaUpdateIng.value + ? Stack( + children: [ + Container( + margin: EdgeInsets.only(top: 8, bottom: 8), + width: Get.width, + child: Center( + child: Text( + // "${TranslationLoader.lanKeys!.newVersion!.tr}:1.0.1", + "未发现新版本", + style: TextStyle( + color: AppColors.mainColor, + fontSize: 18.sp), + ), + ), + ), + Positioned( + right: 80.w, + child: GestureDetector( + onTap: () { + logic.otaUpdate(); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '手动升级', + style: TextStyle( + color: AppColors.mainColor, + fontSize: 18.sp, + fontWeight: FontWeight.w400), + ), + ), + ), + ) + ], + ) + : Padding( + padding: EdgeInsets.symmetric( + horizontal: 50.w, vertical: 15.h), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '固件传输中', + style: TextStyle( + color: AppColors.mainColor, + fontSize: 18.sp, + fontWeight: FontWeight.w400), + ), + SizedBox( + width: 10.w, + ), + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(10.r)), + child: LinearProgressIndicator( + value: logic + .state.otaProgress.value, // 50% 进度 + backgroundColor: Colors.grey[200], + valueColor: + AlwaysStoppedAnimation( + AppColors.mainColor), + ), + ), + ), + ], + ), + ); + }), + SizedBox( + height: 40.h, + ), + Obx(() { + return !logic.state.otaUpdateIng.value + ? SubmitBtn( + btnName: TranslationLoader.lanKeys!.upgrade!.tr, + onClick: () {}) + : SizedBox(); + }), + ], + ), + )); + }); } } diff --git a/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_state.dart b/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_state.dart index 3a0b472d..a53bd383 100644 --- a/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_state.dart +++ b/star_lock/lib/main/lockDetail/lockSet/lockEscalation/lockEscalation_state.dart @@ -1,4 +1,6 @@ +import 'package:get/get.dart'; -class LockEscalationState{ - +class LockEscalationState { + var otaUpdateIng = false.obs; + var otaProgress = 0.00.obs; } diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart index 4a57d055..80294890 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart @@ -10,12 +10,14 @@ import 'package:star_lock/network/api_repository.dart'; import 'package:star_lock/tools/eventBusEventManage.dart'; import '../../../../blue/blue_manage.dart'; +import '../../../../blue/io_modelVendor.dart'; import '../../../../blue/io_reply.dart'; import '../../../../blue/io_protocol/io_senderCustomPasswords.dart'; import '../../../../blue/io_tool/io_tool.dart'; import '../../../../blue/io_tool/manager_event_bus.dart'; import '../../../../blue/sender_manage.dart'; import '../../../../tools/baseGetXController.dart'; +import '../../../../tools/commonDataManage.dart'; import '../../../../tools/dateTool.dart'; import '../../../../tools/storage.dart'; @@ -46,31 +48,36 @@ class PasswordKeyPerpetualLogic extends BaseGetXController { String lockId = state.keyInfo.value.lockId.toString(); String getKeyType = state.widgetType.value.toString(); - if (state.nameController.text.isEmpty) { - showToast("请输入姓名".tr); - return; - } + if (state.nameController.text.isEmpty) { + showToast("请输入姓名".tr); + return; + } - //循环密码 - if (state.widgetType.value == 4) { - if (startDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) { - showToast("生效时间不能小于当前时间".tr); - return; - } - } if (state.widgetType.value == 0) { //永久 getKeyType = '2'; } else if (state.widgetType.value == 1) { //限时 - if (startDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) { - showToast("生效时间不能小于当前时间".tr); - return; + // 鑫鸿佳不需要生效时间 + if(CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XHJ && (CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XHJ_SYD || CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XHJ_JL)){ + if (endDate <= DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) { + showToast("失效时间要大于当前时间".tr); + return; + } } - if (startDate >= endDate) { - showToast("失效时间要大于生效时间".tr); - return; + // 芯连需要生效时间 + if(CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL && (CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_BLE || CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_WIFI)){ + //限时 + if (startDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) { + showToast("生效时间不能小于当前时间".tr); + return; + } + + if (startDate >= endDate) { + showToast("失效时间要大于生效时间".tr); + return; + } } getKeyType = '3'; } else if (state.widgetType.value == 2) { @@ -80,9 +87,16 @@ class PasswordKeyPerpetualLogic extends BaseGetXController { //自定义 } else if (state.widgetType.value == 4) { //循环 - //限时 - if (endDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) { - showToast("结束时间不能小于当前时间".tr); + // 芯连需要结束时间 + if(CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL && (CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_BLE || CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_WIFI)){ + if (endDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) { + showToast("结束时间不能小于当前时间".tr); + return; + } + } + + if (state.loopStartHours.value >= state.loopEndHours.value) { + showToast("失效时间要大于生效时间".tr); return; } diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart index d029fdd3..3f10ff8e 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_page.dart @@ -7,6 +7,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart'; +import 'package:star_lock/tools/commonDataManage.dart'; import 'package:star_lock/tools/pickers/pickers.dart'; import 'package:star_lock/tools/pickers/style/default_style.dart'; import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; @@ -14,6 +15,7 @@ import 'package:star_lock/tools/storage.dart'; import '../../../../appRouters.dart'; import '../../../../blue/blue_manage.dart'; +import '../../../../blue/io_modelVendor.dart'; import '../../../../tools/NativeInteractionTool.dart'; import '../../../../tools/appRouteObserver.dart'; import '../../../../tools/commonItem.dart'; @@ -193,22 +195,25 @@ class _PasswordKeyPerpetualPageState extends State wit Widget keyTimeLimitWidget() { return Column( children: [ - CommonItem( - leftTitel: TranslationLoader.lanKeys!.effectiveTime!.tr, - rightTitle: state.beginTime.value, - isHaveLine: true, - isHaveDirection: true, - action: () { - Pickers.showDatePicker(context, mode: state.widgetType.value == 3 ? DateMode.YMDHM:DateMode.YMDH, onConfirm: (p) { - if (state.widgetType.value == 3) { - // 自定义 - state.beginTime.value = DateTool().getYMDHNDateString(p, 1); - } else { - state.beginTime.value = DateTool().getYMDHNDateString(p, 4); - } - Get.log("beginTime:${state.beginTime.value}"); - }); - }), + Visibility( + visible: CommonDataManage().currentKeyInfo.vendor == "XHJ" ? false : true, + child: CommonItem( + leftTitel: TranslationLoader.lanKeys!.effectiveTime!.tr, + rightTitle: state.beginTime.value, + isHaveLine: true, + isHaveDirection: true, + action: () { + Pickers.showDatePicker(context, mode: state.widgetType.value == 3 ? DateMode.YMDHM:DateMode.YMDH, onConfirm: (p) { + if (state.widgetType.value == 3) { + // 自定义 + state.beginTime.value = DateTool().getYMDHNDateString(p, 1); + } else { + state.beginTime.value = DateTool().getYMDHNDateString(p, 4); + } + Get.log("beginTime:${state.beginTime.value}"); + }); + }), + ), CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, rightTitle: state.endTime.value, @@ -286,16 +291,19 @@ class _PasswordKeyPerpetualPageState extends State wit ]; showPickerView(context, pickerDataList); }), - CommonItem( - leftTitel: '结束日期', - rightTitle: state.endTime.value, - isHaveLine: true, - isHaveDirection: true, - action: () { - Pickers.showDatePicker(context, mode: DateMode.YMDH, onConfirm: (p) { - state.endTime.value = DateTool().getYMDHNDateString(p, 4); - }); - }), + Visibility( + visible: (CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL && (CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_BLE || CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_WIFI)) ? true : false, + child: CommonItem( + leftTitel: '结束日期', + rightTitle: state.endTime.value, + isHaveLine: true, + isHaveDirection: true, + action: () { + Pickers.showDatePicker(context, mode: DateMode.YMDH, onConfirm: (p) { + state.endTime.value = DateTool().getYMDHNDateString(p, 4); + }); + }), + ), CommonItem( leftTitel: TranslationLoader.lanKeys!.effectiveTime!.tr, rightTitle: state.loopEffectiveDate.value, diff --git a/star_lock/lib/main/lockMian/entity/lockListInfo_entity.dart b/star_lock/lib/main/lockMian/entity/lockListInfo_entity.dart index d359e0b0..042d2fcf 100644 --- a/star_lock/lib/main/lockMian/entity/lockListInfo_entity.dart +++ b/star_lock/lib/main/lockMian/entity/lockListInfo_entity.dart @@ -122,6 +122,10 @@ class LockListInfoItemEntity { int? senderUserId; int? electricQuantityDate; int? electricQuantityStandby; + int? isOnlyManageSelf; + int? restoreCount; + String? model; + String? vendor; Bluetooth? bluetooth; LockFeature? lockFeature; LockSetting? lockSetting; @@ -153,7 +157,11 @@ class LockListInfoItemEntity { this.lockUserNo, this.electricQuantityDate, this.electricQuantityStandby, - this.senderUserId}); + this.senderUserId, + this.isOnlyManageSelf, + this.restoreCount, + this.model, + this.vendor}); LockListInfoItemEntity.fromJson(Map json) { keyId = json['keyId']; @@ -180,6 +188,10 @@ class LockListInfoItemEntity { senderUserId = json['senderUserId']; electricQuantityDate = json['electricQuantityDate']; electricQuantityStandby = json['electricQuantityStandby']; + isOnlyManageSelf = json['isOnlyManageSelf']; + restoreCount = json['restoreCount']; + model = json['model']; + vendor = json['vendor']; bluetooth = json['bluetooth'] != null ? Bluetooth.fromJson(json['bluetooth']) : null; @@ -217,6 +229,10 @@ class LockListInfoItemEntity { data['senderUserId'] = senderUserId; data['electricQuantityDate'] = electricQuantityDate; data['electricQuantityStandby'] = electricQuantityStandby; + data['isOnlyManageSelf'] = isOnlyManageSelf; + data['restoreCount'] = restoreCount; + data['model'] = model; + data['vendor'] = vendor; if (bluetooth != null) { data['bluetooth'] = bluetooth!.toJson(); } diff --git a/star_lock/lib/permission/permission_dialog.dart b/star_lock/lib/permission/permission_dialog.dart index 891ba9d3..ce50bc24 100644 --- a/star_lock/lib/permission/permission_dialog.dart +++ b/star_lock/lib/permission/permission_dialog.dart @@ -84,7 +84,7 @@ class PermissionDialog { } //显示权限判断申请框 - static Future request(Permission permission) async { + static Future request(Permission permission, [String? content]) async { if (Get.context == null) { return false; } @@ -99,7 +99,7 @@ class PermissionDialog { canPop: false, child: CupertinoAlertDialog( title: Text('${'申请'.tr}${titles[permission] ?? ''}${'权限'.tr}'), - content: Text(contents[permission] ?? ''), + content: Text(content ?? contents[permission] ?? ''), actions: [ CupertinoDialogAction( child: Text('不允许'.tr), diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 826617e3..e4fb4ea6 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -94,7 +94,7 @@ dependencies: #跳转到外部 url_launcher: ^6.1.10 #蓝牙 -# flutter_reactive_ble: ^5.1.1 + # flutter_reactive_ble: ^5.1.1 flutter_blue_plus: ^1.31.16 # event_bus: ^2.0.0 @@ -123,7 +123,7 @@ dependencies: # 谷歌地图 google_maps_flutter: ^2.2.5 -# geocoding: ^2.1.0 + # geocoding: ^2.1.0 # 允许App发现网络的相关信息并且进行相应的配置 network_info_plus: ^4.0.2 @@ -144,12 +144,12 @@ dependencies: image_gallery_saver: ^2.0.3 convert: ^3.1.1 just_audio: ^0.9.36 - # flutter_sound: ^9.2.13 -# ffmpeg_kit_flutter: 5.1.0-LTS + # flutter_sound: ^9.2.13 + # ffmpeg_kit_flutter: 5.1.0-LTS fast_gbk: ^1.0.0 flutter_pcm_sound: ^1.1.0 intl: ^0.18.0 -# flutter_audio_capture: <1.1.5 + # flutter_audio_capture: <1.1.5 flutter_voice_processor: ^1.1.1 #监听网络连接状态 @@ -165,6 +165,7 @@ dependencies: system_settings: ^2.0.0 expandable: ^5.0.1 colorfilter_generator: ^0.0.8 + file_picker: ^5.3.1 dev_dependencies: