fix:修复 开锁会有时候一直执行动画的问题
This commit is contained in:
parent
ffd709a1ae
commit
a097f882e2
@ -144,12 +144,11 @@ class BlueManage {
|
||||
if (isAvailable) {
|
||||
if (_adapterState == BluetoothAdapterState.on) {
|
||||
try {
|
||||
//android 扫描比较慢,取样只要 8 分之一
|
||||
//android 扫描比较慢,取样只要 3 分之一
|
||||
final int divisor = Platform.isAndroid ? 3 : 1;
|
||||
FlutterBluePlus.startScan(
|
||||
continuousDivisor: divisor,
|
||||
continuousUpdates: true,
|
||||
// withServiceData:[ServiceDataFilter()],
|
||||
withKeywords: <String>[deviceName],
|
||||
timeout: Duration(seconds: timeout));
|
||||
final Completer<dynamic> completer = Completer<dynamic>();
|
||||
@ -317,7 +316,7 @@ class BlueManage {
|
||||
|
||||
if (isAddEquipment == false && isExistDevice == false) {
|
||||
//取消缓存直接使用,存在配对场景设备信息会更变
|
||||
startScanSingle(deviceName, 10, (List<ScanResult> scanDevices) {
|
||||
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
|
||||
_connectDevice(scanDevices, deviceName, connectStateCallBack,
|
||||
isAddEquipment: isAddEquipment);
|
||||
});
|
||||
|
||||
@ -8,6 +8,7 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
|
||||
import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity/ElectronicKeyListEntity.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockTime/getServerDatetime_entity.dart';
|
||||
import 'package:star_lock/tools/throttler.dart';
|
||||
|
||||
import 'package:star_lock/widget/permission/permission_dialog.dart';
|
||||
|
||||
@ -33,6 +34,10 @@ import 'lockNetToken_entity.dart';
|
||||
class LockDetailLogic extends BaseGetXController {
|
||||
final LockDetailState state = LockDetailState();
|
||||
|
||||
//节流器,用来限制开锁按钮的触发频率
|
||||
FunctionBlocker functionBlocker =
|
||||
FunctionBlocker(duration: const Duration(seconds: 2));
|
||||
|
||||
// 监听设备返回的数据
|
||||
void initReplySubscription() {
|
||||
state.replySubscription =
|
||||
@ -114,10 +119,19 @@ class LockDetailLogic extends BaseGetXController {
|
||||
break;
|
||||
case 0x16:
|
||||
// 正在开锁中...
|
||||
final int isOpen = reply.data[8];
|
||||
String? msg;
|
||||
if (isOpen == 0) {
|
||||
msg = '正在开锁中...'.tr;
|
||||
} else if (isOpen == 32) {
|
||||
msg = '正在闭锁中...'.tr;
|
||||
}
|
||||
resetOpenDoorState();
|
||||
showToast('正在开锁中...'.tr, something: () {
|
||||
cancelBlueConnetctToastTimer();
|
||||
});
|
||||
if (msg != null) {
|
||||
showToast(msg, something: () {
|
||||
cancelBlueConnetctToastTimer();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 0x0d:
|
||||
// 钥匙无效
|
||||
@ -161,14 +175,13 @@ class LockDetailLogic extends BaseGetXController {
|
||||
void openDoorError() {
|
||||
resetOpenDoorState();
|
||||
state.animationController!.stop();
|
||||
cancelBlueConnetctToastTimer();
|
||||
BlueManage().disconnect();
|
||||
blueManageDisconnect();
|
||||
}
|
||||
|
||||
//清除开锁动画以及状态
|
||||
void closeLuckStatus() {
|
||||
state.openLockBtnState.value = 0;
|
||||
state.openDoorBtnisUneable.value = false;
|
||||
state.openDoorBtnisUneable.value = true;
|
||||
state.animationController!.stop(canceled: true);
|
||||
cancelBlueConnetctToastTimer();
|
||||
}
|
||||
@ -225,29 +238,28 @@ class LockDetailLogic extends BaseGetXController {
|
||||
if (dataLength == state.logCountPage) {
|
||||
senderReferEventRecordTime();
|
||||
} else {
|
||||
await BlueManage().disconnect();
|
||||
await blueManageDisconnect();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
BlueManage().disconnect();
|
||||
cancelBlueConnetctToastTimer();
|
||||
blueManageDisconnect();
|
||||
break;
|
||||
default:
|
||||
BlueManage().disconnect();
|
||||
cancelBlueConnetctToastTimer();
|
||||
blueManageDisconnect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 点击开门事件
|
||||
Future<void> openDoorAction() async {
|
||||
showBlueConnetctToastTimer(action: () {
|
||||
resetOpenDoorState();
|
||||
closeLuckStatus();
|
||||
BlueManage().disconnect();
|
||||
});
|
||||
showBlueConnetctToastTimer(
|
||||
outTimer: 20,
|
||||
action: () {
|
||||
resetOpenDoorState();
|
||||
blueManageDisconnect();
|
||||
});
|
||||
final List<String>? privateKey =
|
||||
await Storage.getStringList(saveBluePrivateKey);
|
||||
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
@ -285,13 +297,20 @@ class LockDetailLogic extends BaseGetXController {
|
||||
});
|
||||
}
|
||||
|
||||
//蓝牙关闭
|
||||
Future<void> blueManageDisconnect() async {
|
||||
//顺便清除倒计时
|
||||
closeLuckStatus();
|
||||
cancelBlueConnetctToastTimer();
|
||||
await BlueManage().disconnect();
|
||||
}
|
||||
|
||||
// 查询事件记录(时间查询)
|
||||
void senderReferEventRecordTime() {
|
||||
showBlueConnetctToastTimer(
|
||||
isShowBlueConnetctToast: false,
|
||||
action: () {
|
||||
closeLuckStatus();
|
||||
BlueManage().disconnect();
|
||||
blueManageDisconnect();
|
||||
});
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState connectionState) async {
|
||||
@ -325,7 +344,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
}
|
||||
|
||||
// 从服务器获取锁的时间 开锁时传入
|
||||
void getServerDatetime() async {
|
||||
Future<void> getServerDatetime() async {
|
||||
final GetServerDatetimeEntity entity =
|
||||
await ApiRepository.to.getServerDatetimeData();
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
@ -341,7 +360,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
}
|
||||
|
||||
// 获取手机联网token,根据锁设置里面获取的开锁时是否联网来判断是否调用这个接口
|
||||
void getLockNetToken() async {
|
||||
Future<void> getLockNetToken() async {
|
||||
final LockNetTokenEntity entity = await ApiRepository.to
|
||||
.getLockNetToken(lockId: state.keyInfos.value.lockId.toString());
|
||||
if (entity.errorCode!.codeIsSuccessful) {
|
||||
@ -375,7 +394,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
}
|
||||
|
||||
// 查询锁记录最后时间
|
||||
void getLockRecordLastUploadDataTime() async {
|
||||
Future<void> getLockRecordLastUploadDataTime() async {
|
||||
final LockOperatingRecordGetLastRecordTimeEntity entity =
|
||||
await ApiRepository.to.getLockRecordLastUploadDataTime(
|
||||
lockId: state.keyInfos.value.lockId.toString());
|
||||
@ -402,7 +421,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
}
|
||||
|
||||
// 普通用户或者授权管理员删除钥匙
|
||||
void deletKeyData() async {
|
||||
Future<void> deletKeyData() async {
|
||||
final ElectronicKeyListEntity entity = await ApiRepository.to
|
||||
.deleteElectronicKey(
|
||||
keyId: state.keyInfos.value.keyId.toString(), includeUnderlings: 0);
|
||||
@ -497,13 +516,6 @@ class LockDetailLogic extends BaseGetXController {
|
||||
|
||||
await PermissionDialog.request(Permission.location);
|
||||
await PermissionDialog.requestBluetooth();
|
||||
|
||||
final String connectDeviceName =
|
||||
state.keyInfos.value.bluetooth!.bluetoothDeviceName!;
|
||||
if (!BlueManage().isExistScanDevices(connectDeviceName)) {
|
||||
BlueManage().startScanSingle(
|
||||
connectDeviceName, 15, (List<ScanResult> p0) => null);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -254,14 +254,20 @@ class _LockDetailPageState extends State<LockDetailPage>
|
||||
children: <Widget>[
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: state.openDoorBtnisUneable.value == true
|
||||
? isNeedRealNameAuthThenOpenLock
|
||||
: null,
|
||||
onLongPressStart: state.openDoorBtnisUneable.value == true
|
||||
? (LongPressStartDetails details) {
|
||||
setState(startUnLock);
|
||||
}
|
||||
: null,
|
||||
onTap: () {
|
||||
if (state.openDoorBtnisUneable.value == true) {
|
||||
logic.functionBlocker.block(isNeedRealNameAuthThenOpenLock);
|
||||
}
|
||||
},
|
||||
onLongPressStart: (LongPressStartDetails details) {
|
||||
if (state.openDoorBtnisUneable.value == true) {
|
||||
void callback() {
|
||||
setState(startUnLock);
|
||||
}
|
||||
|
||||
logic.functionBlocker.block(callback);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
width: 100.r,
|
||||
height: 100.r,
|
||||
@ -583,14 +589,20 @@ class _LockDetailPageState extends State<LockDetailPage>
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: GestureDetector(
|
||||
onTap: state.openDoorBtnisUneable.value == true
|
||||
? isNeedRealNameAuthThenOpenLock
|
||||
: null,
|
||||
onLongPressStart: state.openDoorBtnisUneable.value == true
|
||||
? (LongPressStartDetails details) {
|
||||
setState(startUnLock);
|
||||
}
|
||||
: null,
|
||||
onTap: () {
|
||||
if (state.openDoorBtnisUneable.value == true) {
|
||||
logic.functionBlocker.block(isNeedRealNameAuthThenOpenLock);
|
||||
}
|
||||
},
|
||||
onLongPressStart: (LongPressStartDetails details) {
|
||||
if (state.openDoorBtnisUneable.value == true) {
|
||||
void callback() {
|
||||
setState(startUnLock);
|
||||
}
|
||||
|
||||
logic.functionBlocker.block(callback);
|
||||
}
|
||||
},
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
FlavorsImg(
|
||||
@ -1347,7 +1359,7 @@ class _LockDetailPageState extends State<LockDetailPage>
|
||||
state.iSOpenLock.value = false;
|
||||
state.openLockBtnState.value = 1;
|
||||
state.animationController!.forward();
|
||||
EasyLoading.showToast('正在尝试闭锁……'.tr, duration: 2000.milliseconds);
|
||||
EasyLoading.showToast('正在尝试闭锁……'.tr, duration: 1000.milliseconds);
|
||||
AppLog.log('长按闭锁');
|
||||
if (state.isOpenLockNeedOnline.value == 0) {
|
||||
// 不需要联网
|
||||
|
||||
@ -48,16 +48,16 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
|
||||
//手动升级
|
||||
Future<void> otaUpdate() async {
|
||||
var status = await PermissionDialog.requestStorage();
|
||||
final bool status = await PermissionDialog.requestStorage();
|
||||
if (status != true) {
|
||||
return;
|
||||
}
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
||||
final 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();
|
||||
final File file = File(result.files.single.path!);
|
||||
final Uint8List data = await file.readAsBytes();
|
||||
headJson = await getHeadFile(data);
|
||||
if (headJson is! Map) {
|
||||
return;
|
||||
@ -66,15 +66,13 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
if (otaBin == null) {
|
||||
return;
|
||||
}
|
||||
String md5Str = md5.convert(otaBin!).toString();
|
||||
final String md5Str = md5.convert(otaBin!).toString();
|
||||
headJson!['fwMd5'] = md5Str;
|
||||
ShowTipView().showIosTipWithContentDialog("未避免异常情况,请在门打开时升级".tr, () async {
|
||||
ShowTipView().showIosTipWithContentDialog('未避免异常情况,请在门打开时升级'.tr, () async {
|
||||
blueOTAUpgrade(headJson!, [0, 0, 0, 0]);
|
||||
EasyLoading.show(
|
||||
status: '设备连接中...'.tr, maskType: EasyLoadingMaskType.black);
|
||||
Future.delayed(const Duration(seconds: 4), () {
|
||||
EasyLoading.dismiss();
|
||||
});
|
||||
Future.delayed(const Duration(seconds: 4), EasyLoading.dismiss);
|
||||
});
|
||||
}
|
||||
|
||||
@ -83,11 +81,11 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
String uid = await Storage.getUid() ?? '';
|
||||
final privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
final signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
final String uid = await Storage.getUid() ?? '';
|
||||
BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: uid,
|
||||
@ -113,30 +111,30 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
if (!state.otaUpdateIng.value) {
|
||||
return;
|
||||
}
|
||||
int length = otaBin?.length ?? 0;
|
||||
final int length = otaBin?.length ?? 0;
|
||||
if (otaCount == 0) {
|
||||
//首次
|
||||
int difference = length % 240;
|
||||
final int difference = length % 240;
|
||||
otaCount = length ~/ 240 + (difference > 0 ? 1 : 0);
|
||||
startSecond = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
startOTAData();
|
||||
}
|
||||
if (otaCount <= otaIndex) {
|
||||
int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
String msg =
|
||||
final int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
final String msg =
|
||||
'传输完成 时间:${now - startSecond}秒 otaCount:$otaCount otaIndex:$otaIndex ';
|
||||
closeOTADAta();
|
||||
AppLog.log(msg);
|
||||
// showToast(msg);
|
||||
return;
|
||||
}
|
||||
int star = otaIndex * 240;
|
||||
final int star = otaIndex * 240;
|
||||
int end = (otaIndex + 1) * 240;
|
||||
if (end > length) {
|
||||
end = length;
|
||||
}
|
||||
int size = end - star;
|
||||
List<int> data = otaBin!.sublist(star, end);
|
||||
final int size = end - star;
|
||||
final List<int> data = otaBin!.sublist(star, end);
|
||||
state.otaProgress.value = otaIndex / otaCount;
|
||||
await BlueManage().writeCharacteristicWithResponse(
|
||||
ProcessOtaUpgradeCommand(index: otaIndex, size: size, data: data)
|
||||
@ -176,7 +174,8 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
// 检查文件头
|
||||
String header;
|
||||
try {
|
||||
header = utf8.decode(data.sublist(0, 12));
|
||||
final Uint8List list = data.sublist(0, 12);
|
||||
header = utf8.decode(list);
|
||||
} catch (e) {
|
||||
showToast('非SYD固件,请选择正确的文件'.tr);
|
||||
return null;
|
||||
@ -210,7 +209,7 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
return null;
|
||||
}
|
||||
AppLog.log(metaStr);
|
||||
var meta = jsonDecode(metaStr);
|
||||
final meta = jsonDecode(metaStr);
|
||||
if (meta is! Map) {
|
||||
showToast('解析元数据失败,请选择正确的文件'.tr);
|
||||
return null;
|
||||
@ -220,11 +219,11 @@ class LockEscalationLogic extends BaseGetXController {
|
||||
|
||||
//检测升级文件并读取 bin
|
||||
Future<Uint8List?> checkFile(Uint8List data, Map meta) async {
|
||||
num binOffset = 16 + (meta['metaLen'] ?? 0);
|
||||
final num binOffset = 16 + (meta['metaLen'] ?? 0);
|
||||
// 获取固件数据部分
|
||||
Uint8List bin = data.sublist(binOffset.toInt(), data.length);
|
||||
final Uint8List bin = data.sublist(binOffset.toInt(), data.length);
|
||||
//md5 校验有问题,暂时不解析
|
||||
String md5Str = md5.convert(bin).toString().toUpperCase();
|
||||
final String md5Str = md5.convert(bin).toString().toUpperCase();
|
||||
AppLog.log('固件 md5 检验md5:$md5Str 固件信息 md5:${meta['fwMd5']}');
|
||||
if (md5Str != meta['fwMd5']) {
|
||||
showToast('文件校验失败 0x02'.tr);
|
||||
|
||||
73
lib/tools/throttler.dart
Normal file
73
lib/tools/throttler.dart
Normal file
@ -0,0 +1,73 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:star_lock/app_settings/app_settings.dart';
|
||||
|
||||
///
|
||||
/// 节流器 可以防止一个函数在短时间内被重复调用
|
||||
// 创建一个1秒的节流器
|
||||
// Throttler throttler = Throttler(Duration(seconds: 1));
|
||||
//
|
||||
// // 示例函数
|
||||
// void myFunction() {
|
||||
// print("函数被调用");
|
||||
// }
|
||||
//
|
||||
// // 调用示例函数,会在1秒内只输出一次
|
||||
// throttler.throttle(myFunction);
|
||||
//
|
||||
// // 在自定义时间间隔内防止函数被重复调用
|
||||
// Throttler customThrottler = Throttler(Duration(milliseconds: 500)); // 自定义500毫秒的间隔
|
||||
// customThrottler.throttle(myFunction); // 在500毫秒内多次调用只会执行一次函数
|
||||
//
|
||||
// // 在需要时取消节流器
|
||||
// customThrottler.cancel(); // 取消节流器,函数再次被调用会立即执行
|
||||
|
||||
class Throttler {
|
||||
Throttler(this._delay);
|
||||
|
||||
final Duration _delay;
|
||||
Timer? _timer;
|
||||
late Function _callback;
|
||||
|
||||
void throttle(Function callback) {
|
||||
if (_timer == null || !_timer!.isActive) {
|
||||
_callback = callback;
|
||||
_timer = Timer(_delay, () {
|
||||
_callback();
|
||||
_timer?.cancel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
_timer?.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// 防止抖动
|
||||
///
|
||||
class FunctionBlocker {
|
||||
FunctionBlocker({required this.duration});
|
||||
|
||||
bool _blocked = false;
|
||||
Duration duration;
|
||||
|
||||
void block(Function function) {
|
||||
if (!_blocked) {
|
||||
_blocked = true;
|
||||
function();
|
||||
Timer(duration, () {
|
||||
_blocked = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//倒计时禁止
|
||||
void countdownProhibited({required Duration duration}) {
|
||||
_blocked = true;
|
||||
Timer(duration, () {
|
||||
_blocked = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user