app-starlock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart

621 lines
22 KiB
Dart
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/scheduler.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
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/main/lockMian/entity/lockListInfo_entity.dart';
import 'package:star_lock/tools/throttler.dart';
import 'package:star_lock/widget/permission/permission_dialog.dart';
import '../../../app_settings/app_settings.dart';
import '../../../blue/blue_manage.dart';
import '../../../blue/io_protocol/io_openLock.dart';
import '../../../blue/io_protocol/io_referEventRecordTime.dart';
import '../../../blue/io_reply.dart';
import '../../../blue/io_tool/io_tool.dart';
import '../../../blue/io_tool/manager_event_bus.dart';
import '../../../blue/sender_manage.dart';
import '../../../network/api_repository.dart';
import '../../../tools/baseGetXController.dart';
import '../../../tools/commonDataManage.dart';
import '../../../tools/eventBusEventManage.dart';
import '../../../tools/storage.dart';
import '../../../translations/trans_lib.dart';
import '../lockOperatingRecord/keyOperationRecord_entity.dart';
import '../lockOperatingRecord/lockOperatingRecordGetLastRecordTime_entity.dart';
import '../lockSet/basicInformation/uploadElectricQuantity/uploadElectricQuantity_entity.dart';
import 'lockDetail_state.dart';
import 'lockNetToken_entity.dart';
class LockDetailLogic extends BaseGetXController {
final LockDetailState state = LockDetailState();
//节流器,用来限制开锁按钮的触发频率
FunctionBlocker functionBlocker =
FunctionBlocker(duration: const Duration(seconds: 2));
// 监听设备返回的数据
void initReplySubscription() {
state.replySubscription =
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
// 开门
if (reply is OpenDoorReply && state.ifCurrentScreen.value == true) {
_replyOpenLock(reply);
}
// 开完锁之后上传记录
if (reply is SenderReferEventRecordTimeReply &&
state.ifCurrentScreen.value == true) {
_replyReferEventRecordTime(reply);
}
});
}
// 开门数据解析
Future<void> _replyOpenLock(Reply reply) async {
final int status = reply.data[6];
switch (status) {
case 0x00:
//成功
// _showFullScreenOverlay(Get.context!);
state.iSClosedUnlockSuccessfulPopup.value = true;
cancelBlueConnetctToastTimer();
state.closedUnlockSuccessfulTimer?.cancel();
EasyLoading.dismiss();
// 如果没有点击关闭弹窗3秒后自动关闭
state.closedUnlockSuccessfulTimer =
Timer.periodic(3.seconds, (Timer timer) {
state.iSClosedUnlockSuccessfulPopup.value = false;
timer.cancel();
eventBus.fire(RefreshLockDetailInfoDataEvent());
});
// 电量
final int power = reply.data[7];
state.electricQuantity.value = power;
// 备用电量
if (state.keyInfos.value.lockFeature!.isSupportBackupBattery == 1) {
final int powerStandby = reply.data[9];
state.electricQuantityStandby.value = powerStandby;
}
// 更新电量
uploadElectricQuantityRequest();
//锁数据更新
getLockRecordLastUploadDataTime();
resetOpenDoorState();
state.animationController!.stop();
break;
case 0x06:
//无权限
final List<String>? privateKey =
await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList =
changeStringListToIntList(privateKey!);
final List<String>? signKey =
await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
final List<int> tokenData = reply.data.sublist(2, 6);
final List<String> saveStrList = changeIntListToStringList(tokenData);
Storage.setStringList(saveBlueToken, saveStrList);
IoSenderManage.senderOpenLock(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
openMode: state.openDoorModel,
openTime: getUTCNetTime(),
onlineToken: state.lockNetToken,
token: tokenData,
needAuthor: 1,
signKey: signKeyDataList,
privateKey: getPrivateKeyList,
);
break;
case 0x16:
// 正在开锁中...
final int isOpen = reply.data[8];
String? msg;
if (isOpen == 0) {
msg = '正在开锁中...'.tr;
} else if (isOpen == 32) {
msg = '正在闭锁中...'.tr;
}
resetOpenDoorState();
if (msg != null) {
showToast(msg, something: () {
cancelBlueConnetctToastTimer();
});
}
break;
case 0x0d:
// 钥匙无效
showToast('钥匙无效'.tr);
openDoorError();
break;
case 0x0b:
// 钥匙无效
showToast('钥匙过期'.tr);
openDoorError();
break;
case 0x0a:
// 钥匙不存在
showToast('钥匙不存在');
openDoorError();
break;
case 0x0c:
// 钥匙数量已到上限
showToast('钥匙数量已到上限');
openDoorError();
break;
case 0x0e:
// 钥匙已存在
showToast('钥匙已存在');
openDoorError();
break;
case 0x0f:
// 用户已存在
showToast('用户已存在');
openDoorError();
break;
default:
//失败
AppLog.log('开锁失败');
openDoorError();
break;
}
}
Future<void> loadData({ required LockListInfoItemEntity lockListInfoItemEntity,required bool isOnlyOneData}) async {
state.keyInfos.value = lockListInfoItemEntity;
CommonDataManage().currentLockUserNo = state.keyInfos.value.lockUserNo!;
CommonDataManage().currentKeyInfo = state.keyInfos.value;
state.lockUserNo = state.keyInfos.value.lockUserNo!;
if (state.keyInfos.value.keyStatus ==
XSConstantMacro.keyStatusWaitIneffective ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusFrozen ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusExpired ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusDeleted ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusReset) {
state.openDoorBtnisUneable.value = false;
state.bottomBtnisEable.value = false;
} else {
state.openDoorBtnisUneable.value = true;
state.bottomBtnisEable.value = true;
}
state.isOnlyOneData = isOnlyOneData;
state.senderUserId = state.keyInfos.value.senderUserId!;
state.isAttendance.value = state.keyInfos.value.lockSetting!.attendance!;
state.isOpenLockNeedOnline.value =
state.keyInfos.value.lockSetting!.appUnlockOnline!;
state.electricQuantity.value = state.keyInfos.value.electricQuantity!;
state.isOpenPassageMode.value = state.keyInfos.value.passageMode!;
state.lockAlias.value = state.keyInfos.value.lockAlias!;
Storage.setString(saveLockAlias, state.lockAlias.value);
BlueManage().connectDeviceName =
state.keyInfos.value.bluetooth!.bluetoothDeviceName!;
final List<int> publicKeyData =
state.keyInfos.value.bluetooth!.publicKey!.cast<int>();
final List<String> saveStrList = changeIntListToStringList(publicKeyData);
Storage.setStringList(saveBluePublicKey, saveStrList);
// 私钥
final List<int> privateKeyData =
state.keyInfos.value.bluetooth!.privateKey!.cast<int>();
final List<String> savePrivateKeyList =
changeIntListToStringList(privateKeyData);
Storage.setStringList(saveBluePrivateKey, savePrivateKeyList);
// signKey
final List<int> signKeyData =
state.keyInfos.value.bluetooth!.signKey!.cast<int>();
final List<String> saveSignKeyList = changeIntListToStringList(signKeyData);
Storage.setStringList(saveBlueSignKey, saveSignKeyList);
final bool ifHaveKey = await Storage.ifHaveKey(saveBlueToken);
if (!ifHaveKey) {
final List<String> saveTokenList =
changeIntListToStringList(<int>[0, 0, 0, 0]);
Storage.setStringList(saveBlueToken, saveTokenList);
}
}
//开门指令失败
void openDoorError() {
resetOpenDoorState();
state.animationController!.stop();
blueManageDisconnect();
}
//清除开锁动画以及状态
void closeLuckStatus() {
state.openLockBtnState.value = 0;
// state.openDoorBtnisUneable.value = true;
state.animationController!.stop(canceled: true);
cancelBlueConnetctToastTimer();
}
// 根据时间查解析数据
Future<void> _replyReferEventRecordTime(Reply reply) async {
final int status = reply.data[2];
switch (status) {
case 0x00:
//成功
final int dataLength = (reply.data[5] << 8) + reply.data[6];
AppLog.log('dataLength:$dataLength');
if (dataLength > 0) {
reply.data.removeRange(0, 7);
// 把得到的数据按17个字节分割成数组 然后塞进一个新的数组里面
if (reply.data.length < 17) {
return;
}
final List<List<int>> getList = splitList(reply.data, 17);
AppLog.log('getList:$getList');
final List uploadList = [];
for (int i = 0; i < getList.length; i++) {
final List<int> indexList = getList[i];
AppLog.log('indexList:$indexList');
final Map indexMap = {};
indexMap['type'] = indexList[0].toString();
int operateDate = 0;
if (indexList[0] == 2) {
final List<int> passwordData = indexList.sublist(7, 17);
final String password = utf8String(passwordData);
AppLog.log('passwordData:$passwordData password:$password');
indexMap['user'] = password.toString();
} else {
final int userNo = (indexList[1] * 256) + indexList[2];
indexMap['user'] = userNo.toString();
}
indexMap['success'] = '1';
final int time = (0xff & indexList[3]) << 24 |
(0xff & indexList[4]) << 16 |
(0xff & indexList[5]) << 8 |
(0xFF & indexList[6]);
operateDate = time * 1000;
indexMap['date'] = '$operateDate';
uploadList.add(indexMap);
if (i == getList.length - 1) {
//设置最后的时间戳
state.operateDate = operateDate;
}
}
lockRecordUploadData(uploadList);
if (dataLength == state.logCountPage) {
senderReferEventRecordTime();
} else {
await blueManageDisconnect();
}
}
break;
case 0x06:
//无权限
blueManageDisconnect();
break;
default:
blueManageDisconnect();
break;
}
}
// 点击开门事件
Future<void> openDoorAction() async {
showBlueConnetctToastTimer(
outTimer: 20,
action: () {
resetOpenDoorState();
blueManageDisconnect();
});
final List<String>? privateKey =
await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> getTokenList = changeStringListToIntList(token!);
BlueManage()
.blueSendData(state.keyInfos.value.bluetooth!.bluetoothDeviceName!,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
IoSenderManage.senderOpenLock(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
openMode: state.openDoorModel,
openTime: getUTCNetTime(),
onlineToken: state.lockNetToken,
token: getTokenList,
needAuthor: 1,
signKey: signKeyDataList,
privateKey: getPrivateKeyList,
);
} else if (deviceConnectionState ==
BluetoothConnectionState.disconnected) {
cancelBlueConnetctToastTimer();
if (state.ifCurrentScreen.value == true) {
showBlueConnetctToast();
}
resetOpenDoorState();
}
});
}
//蓝牙关闭
Future<void> blueManageDisconnect() async {
//顺便清除倒计时
closeLuckStatus();
cancelBlueConnetctToastTimer();
await BlueManage().disconnect();
}
// 查询事件记录(时间查询)
void senderReferEventRecordTime() {
showBlueConnetctToastTimer(
isShowBlueConnetctToast: false,
action: () {
blueManageDisconnect();
});
BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey =
await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList =
changeStringListToIntList(privateKey!);
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> getTokenList = changeStringListToIntList(token!);
final List<String>? publicKey =
await Storage.getStringList(saveBluePublicKey);
final List<int> getPublicKeyList =
changeStringListToIntList(publicKey!);
IoSenderManage.senderReferEventRecordTimeCommand(
keyID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
logsCount: state.logCountPage,
// time:DateTime.now().millisecondsSinceEpoch~/1000,
time: state.operateDate,
token: getTokenList,
needAuthor: 1,
publicKey: getPublicKeyList,
privateKey: getPrivateKeyList,
);
}
});
}
// 从服务器获取锁的时间 开锁时传入
Future<void> getServerDatetime() async {
final GetServerDatetimeEntity entity =
await ApiRepository.to.getServerDatetimeData(isUnShowLoading: true);
if (entity.errorCode!.codeIsSuccessful) {
state.differentialTime = entity.data!.date! ~/ 1000 -
DateTime.now().millisecondsSinceEpoch ~/ 1000;
} else {
state.isHaveNetwork = false;
}
}
int getUTCNetTime() {
if (state.isHaveNetwork) {
return DateTime.now().millisecondsSinceEpoch ~/ 1000 +
state.differentialTime;
} else {
return 0;
}
}
// 获取手机联网token根据锁设置里面获取的开锁时是否联网来判断是否调用这个接口
Future<void> getLockNetToken() async {
final LockNetTokenEntity entity = await ApiRepository.to
.getLockNetToken(lockId: state.keyInfos.value.lockId.toString());
if (entity.errorCode!.codeIsSuccessful) {
state.lockNetToken = entity.data!.token!.toString();
AppLog.log('从服务器获取联网token:${state.lockNetToken}');
openDoorAction();
} else {
showToast('网络访问失败,请检查网络是否正常'.tr, something: () {
resetOpenDoorState();
cancelBlueConnetctToastTimer();
state.lockNetToken = '0';
openDoorAction();
});
}
}
//电量更新请求
Future<void> uploadElectricQuantityRequest() async {
final UploadElectricQuantityEntity entity = await ApiRepository.to
.uploadElectricQuantity(
electricQuantity: state.electricQuantity.value.toString(),
electricQuantityStandby:
state.electricQuantityStandby.value.toString(),
lockId: state.keyInfos.value.lockId.toString(),
isUnShowLoading: true);
if (entity.errorCode!.codeIsSuccessful) {
SchedulerBinding.instance.addPostFrameCallback((_) {
eventBus.fire(RefreshLockListInfoDataEvent(isUnShowLoading: true));
});
}
}
// 查询锁记录最后时间
Future<void> getLockRecordLastUploadDataTime() async {
final LockOperatingRecordGetLastRecordTimeEntity entity =
await ApiRepository.to.getLockRecordLastUploadDataTime(
lockId: state.keyInfos.value.lockId.toString());
if (entity.errorCode!.codeIsSuccessful) {
state.operateDate = entity.data!.operateDate! ~/ 1000;
senderReferEventRecordTime();
}
}
// 操作记录上传
Future<void> lockRecordUploadData(List list) async {
final KeyOperationRecordEntity entity = await ApiRepository.to
.lockRecordUploadData(
lockId: state.keyInfos.value.lockId.toString(), records: list);
if (entity.errorCode!.codeIsSuccessful) {
// mockNetworkDataRequest();
AppLog.log(
'state.keyInfos.value.keyType:${state.keyInfos.value.keyType}');
if (state.keyInfos.value.keyType == XSConstantMacro.keyTypeOnce) {
// 单次删除
deletKeyData();
}
}
}
// 普通用户或者授权管理员删除钥匙
Future<void> deletKeyData() async {
final ElectronicKeyListEntity entity = await ApiRepository.to
.deleteElectronicKey(
keyId: state.keyInfos.value.keyId.toString(), includeUnderlings: 0);
if (entity.errorCode!.codeIsSuccessful) {
BlueManage().connectDeviceMacAddress = '';
SchedulerBinding.instance.addPostFrameCallback((_) {
eventBus.fire(RefreshLockListInfoDataEvent());
});
Get.back();
}
}
/// 锁设置里面开启关闭考勤刷新锁详情
void initLockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceAction() {
// 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus
state.lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent =
eventBus
.on<LockSetChangeSetRefreshLockDetailWithType>()
.listen((LockSetChangeSetRefreshLockDetailWithType event) {
if (event.type == 0) {
// 0考勤
state.isAttendance.value = int.parse(event.setResult);
state.keyInfos.value.lockSetting!.attendance =
int.parse(event.setResult);
} else if (event.type == 1) {
// 1 开锁时是否需联网
state.isOpenLockNeedOnline.value = int.parse(event.setResult);
state.keyInfos.value.lockSetting!.appUnlockOnline =
int.parse(event.setResult);
state.lockNetToken = ''; // 改变开锁时是否联网状态的时候清空token
} else if (event.type == 2) {
// 2 常开模式
state.isOpenPassageMode.value = int.parse(event.setResult);
state.keyInfos.value.passageMode = int.parse(event.setResult);
} else if (event.type == 3) {
// 3 修改了锁名字
state.lockAlias.value = event.setResult;
state.keyInfos.value.lockAlias = event.setResult;
Storage.setString(saveLockAlias, state.lockAlias.value);
} else if (event.type == 4) {
// 4 更新了电量
// state.electricQuantity.value = int.parse(event.setResult);
// state.keyInfos.value.electricQuantity = int.parse(event.setResult);
final int electricQuantity =
int.tryParse(event.setResult['electricQuantity']) ?? 0;
state.electricQuantity.value = electricQuantity;
state.keyInfos.value.electricQuantity = electricQuantity;
state.keyInfos.value.electricQuantityDate =
event.setResult['uploadElectricQuantityDate'];
} else if (event.type == 5) {
// 5 远程开锁
state.keyInfos.value.lockSetting!.remoteUnlock =
int.parse(event.setResult);
}
CommonDataManage().currentKeyInfo = state.keyInfos.value;
eventBus.fire(RefreshLockDetailInfoDataEvent());
});
}
String getKeyStatusTextAndShow() {
String text = '';
if (state.keyInfos.value.keyStatus ==
XSConstantMacro.keyStatusWaitIneffective ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusFrozen ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusExpired ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusDeleted ||
state.keyInfos.value.keyStatus == XSConstantMacro.keyStatusReset) {
text =
"${"你的钥匙".tr}${XSConstantMacro.getKeyStatusStr(state.keyInfos.value.keyStatus!)}";
} else {
text = state.isOpenPassageMode.value == 1
? '常开模式启动!长按闭锁'.tr
: TranslationLoader.lanKeys!.clickUnlockAndHoldDownClose!.tr;
}
return text;
}
String getCurrentFormattedTime() {
// 获取当前时间
final DateTime now = DateTime.now();
// 格式化日期和时间
final String formattedTime = DateFormat('MM/dd HH:mm').format(now);
return formattedTime;
}
void resetOpenDoorState() {
state.openLockBtnState.value = 0;
// state.openDoorBtnisUneable.value = false;
state.animationController?.reset();
state.animationController?.forward();
eventBus.fire(RefreshLockDetailInfoDataEvent());
}
@override
Future<void> onReady() async {
super.onReady();
getServerDatetime();
await PermissionDialog.request(Permission.location);
await PermissionDialog.requestBluetooth();
}
@override
void onInit() {
super.onInit();
state.LockSetChangeSetRefreshLockDetailWithTypeSubscription = eventBus
.on<LockSetChangeSetRefreshLockDetailWithType>()
.listen((LockSetChangeSetRefreshLockDetailWithType event) {
//更新 开锁时是否需联网 状态
if (event.type == 1) {
state.isOpenLockNeedOnline.value = int.parse(event.setResult);
state.keyInfos.value.lockSetting!.appUnlockOnline =
int.parse(event.setResult);
state.isOpenLockNeedOnline.refresh();
}
if (event.type == 4) {
final int electricQuantity =
int.tryParse(event.setResult['electricQuantity']) ?? 0;
state.electricQuantity.value = electricQuantity;
state.keyInfos.value.electricQuantity = electricQuantity;
state.keyInfos.value.electricQuantityDate =
event.setResult['uploadElectricQuantityDate'] ?? 0;
state.keyInfos.refresh();
}
});
}
}