Compare commits
4 Commits
develop_sk
...
develop_sk
| Author | SHA1 | Date | |
|---|---|---|---|
| b0506a8910 | |||
| 4fa076565f | |||
| 8a8c81b7d2 | |||
| 7e53ecfbf5 |
BIN
images/icon_device_not_selected.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
images/icon_device_selected.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
images/icon_main_drlock_1024.png
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
images/mine/icon_message_checbox.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
images/mine/icon_message_close.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
images/mine/icon_message_readed.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
images/mine/icon_message_unread.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
@ -1185,5 +1185,6 @@
|
|||||||
"这是单次密码,只能使用一次": "这是单次密码,只能使用一次",
|
"这是单次密码,只能使用一次": "这是单次密码,只能使用一次",
|
||||||
"您好": "您好",
|
"您好": "您好",
|
||||||
"您的开门密码是": "您的开门密码是",
|
"您的开门密码是": "您的开门密码是",
|
||||||
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标"
|
"开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标": "开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标",
|
||||||
|
"锁博士": "锁博士"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,6 +150,7 @@ class AppColors {
|
|||||||
|
|
||||||
static Color openPassageModeColor = const Color(0xFFEB2A3B); // 首页开启常开模式颜色(红色)
|
static Color openPassageModeColor = const Color(0xFFEB2A3B); // 首页开启常开模式颜色(红色)
|
||||||
static Color listTimeYellowColor = const Color(0xFFF3BA37); // 首页时间过期颜色(黄色)
|
static Color listTimeYellowColor = const Color(0xFFF3BA37); // 首页时间过期颜色(黄色)
|
||||||
|
static Color messageTipsColor = const Color.fromRGBO(202, 220, 247, 1); //消息页面顶部提示条背景色
|
||||||
|
|
||||||
static Color get lockDetailBottomBtnUneable =>
|
static Color get lockDetailBottomBtnUneable =>
|
||||||
const Color(0xFF808080); // 首页时间灰色颜色(灰色)
|
const Color(0xFF808080); // 首页时间灰色颜色(灰色)
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class BlueManage {
|
|||||||
StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription;
|
StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription;
|
||||||
|
|
||||||
StreamSubscription<int>? _mtuSubscription;
|
StreamSubscription<int>? _mtuSubscription;
|
||||||
int? _mtuSize = 30;
|
int? _mtuSize = 20;
|
||||||
|
|
||||||
// 当前连接设备的名字
|
// 当前连接设备的名字
|
||||||
String connectDeviceName = '';
|
String connectDeviceName = '';
|
||||||
@ -119,7 +119,8 @@ class BlueManage {
|
|||||||
_connectionStateSubscription?.cancel();
|
_connectionStateSubscription?.cancel();
|
||||||
_connectionStateSubscription = null;
|
_connectionStateSubscription = null;
|
||||||
|
|
||||||
_connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((BluetoothConnectionState state) async {
|
_connectionStateSubscription =
|
||||||
|
bluetoothConnectDevice!.connectionState.listen((BluetoothConnectionState state) async {
|
||||||
bluetoothConnectionState = state;
|
bluetoothConnectionState = state;
|
||||||
AppLog.log('蓝牙连接回调状态:$state');
|
AppLog.log('蓝牙连接回调状态:$state');
|
||||||
});
|
});
|
||||||
@ -158,20 +159,26 @@ class BlueManage {
|
|||||||
// AppLog.log('startScanSingle 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
|
// AppLog.log('startScanSingle 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
|
||||||
if (_adapterState == BluetoothAdapterState.on) {
|
if (_adapterState == BluetoothAdapterState.on) {
|
||||||
try {
|
try {
|
||||||
BuglyTool.uploadException(message: '开始指定设备名称的扫描蓝牙设备', detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName', upload: false);
|
BuglyTool.uploadException(
|
||||||
|
message: '开始指定设备名称的扫描蓝牙设备', detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName', upload: false);
|
||||||
//android 扫描比较慢,取样只要 3 分之一
|
//android 扫描比较慢,取样只要 3 分之一
|
||||||
final int divisor = Platform.isAndroid ? 3 : 1;
|
final int divisor = Platform.isAndroid ? 3 : 1;
|
||||||
FlutterBluePlus.startScan(
|
FlutterBluePlus.startScan(
|
||||||
continuousDivisor: divisor, continuousUpdates: true, withKeywords: <String>[deviceName], timeout: Duration(seconds: timeout));
|
continuousDivisor: divisor,
|
||||||
|
continuousUpdates: true,
|
||||||
|
withKeywords: <String>[deviceName],
|
||||||
|
timeout: Duration(seconds: timeout));
|
||||||
final Completer<dynamic> completer = Completer<dynamic>();
|
final Completer<dynamic> completer = Completer<dynamic>();
|
||||||
final StreamSubscription<List<ScanResult>> subscription = FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
|
final StreamSubscription<List<ScanResult>> subscription =
|
||||||
final bool isExit = results
|
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
|
||||||
.any((ScanResult element) => (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
|
final bool isExit = results.any((ScanResult element) =>
|
||||||
|
(element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
|
||||||
final int milliseconds = DateTime.now().millisecondsSinceEpoch - start.millisecondsSinceEpoch;
|
final int milliseconds = DateTime.now().millisecondsSinceEpoch - start.millisecondsSinceEpoch;
|
||||||
AppLog.log('扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
|
AppLog.log('扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '指定设备名称的扫描蓝牙设备 监听扫描结果',
|
message: '指定设备名称的扫描蓝牙设备 监听扫描结果',
|
||||||
detail: 'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
|
detail:
|
||||||
|
'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
|
||||||
upload: false);
|
upload: false);
|
||||||
if (isExit) {
|
if (isExit) {
|
||||||
for (final ScanResult scanResult in results) {
|
for (final ScanResult scanResult in results) {
|
||||||
@ -208,7 +215,8 @@ class BlueManage {
|
|||||||
completer.complete();
|
completer.complete();
|
||||||
}
|
}
|
||||||
}, onError: (e) {
|
}, onError: (e) {
|
||||||
BuglyTool.uploadException(message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', detail: '打印失败问题 e:${e.toString()}', upload: false);
|
BuglyTool.uploadException(
|
||||||
|
message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败', detail: '打印失败问题 e:${e.toString()}', upload: false);
|
||||||
AppLog.log('扫描失败:$e');
|
AppLog.log('扫描失败:$e');
|
||||||
});
|
});
|
||||||
FlutterBluePlus.cancelWhenScanComplete(subscription);
|
FlutterBluePlus.cancelWhenScanComplete(subscription);
|
||||||
@ -216,7 +224,8 @@ class BlueManage {
|
|||||||
scanDevicesCallBack(scanDevices);
|
scanDevicesCallBack(scanDevices);
|
||||||
subscription.cancel();
|
subscription.cancel();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
BuglyTool.uploadException(message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}', upload: false);
|
BuglyTool.uploadException(
|
||||||
|
message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败', detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}', upload: false);
|
||||||
AppLog.log('扫描失败');
|
AppLog.log('扫描失败');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -233,14 +242,16 @@ class BlueManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 开始扫描蓝牙设备
|
/// 开始扫描蓝牙设备
|
||||||
Future<void> startScan(int timeout, DeviceType deviceType, ScanDevicesCallBack scanDevicesCallBack, {List<Guid>? idList}) async {
|
Future<void> startScan(int timeout, DeviceType deviceType, ScanDevicesCallBack scanDevicesCallBack,
|
||||||
|
{List<Guid>? idList}) async {
|
||||||
FlutterBluePlus.isSupported.then((bool isAvailable) async {
|
FlutterBluePlus.isSupported.then((bool isAvailable) async {
|
||||||
if (isAvailable) {
|
if (isAvailable) {
|
||||||
AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
|
AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
|
||||||
if (_adapterState == BluetoothAdapterState.on) {
|
if (_adapterState == BluetoothAdapterState.on) {
|
||||||
try {
|
try {
|
||||||
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
|
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
|
||||||
final StreamSubscription<List<ScanResult>> subscription = FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
|
final StreamSubscription<List<ScanResult>> subscription =
|
||||||
|
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
|
||||||
scanDevices.clear();
|
scanDevices.clear();
|
||||||
for (final ScanResult scanResult in results) {
|
for (final ScanResult scanResult in results) {
|
||||||
if (scanResult.advertisementData.serviceUuids.isNotEmpty) {
|
if (scanResult.advertisementData.serviceUuids.isNotEmpty) {
|
||||||
@ -409,13 +420,16 @@ class BlueManage {
|
|||||||
} else {
|
} else {
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙',
|
message: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙',
|
||||||
detail: 'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState:$bluetoothConnectionState deviceName:$deviceName',
|
detail:
|
||||||
|
'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState:$bluetoothConnectionState deviceName:$deviceName',
|
||||||
upload: false);
|
upload: false);
|
||||||
stateCallBack(bluetoothConnectionState!);
|
stateCallBack(bluetoothConnectionState!);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '点击按钮 蓝牙未打开', detail: 'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName', upload: false);
|
message: '点击按钮 蓝牙未打开',
|
||||||
|
detail: 'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
|
||||||
|
upload: false);
|
||||||
try {
|
try {
|
||||||
stateCallBack(BluetoothConnectionState.disconnected);
|
stateCallBack(BluetoothConnectionState.disconnected);
|
||||||
openBlue();
|
openBlue();
|
||||||
@ -428,7 +442,8 @@ class BlueManage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BuglyTool.uploadException(message: '点击按钮 蓝牙状态不可用', detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable', upload: false);
|
BuglyTool.uploadException(
|
||||||
|
message: '点击按钮 蓝牙状态不可用', detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable', upload: false);
|
||||||
stateCallBack(BluetoothConnectionState.disconnected);
|
stateCallBack(BluetoothConnectionState.disconnected);
|
||||||
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
|
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
|
||||||
}
|
}
|
||||||
@ -436,7 +451,8 @@ class BlueManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 连接
|
/// 连接
|
||||||
Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async {
|
Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack,
|
||||||
|
{bool isAddEquipment = false}) async {
|
||||||
connectDeviceName = deviceName;
|
connectDeviceName = deviceName;
|
||||||
// 当前已扫描到的缓存设备
|
// 当前已扫描到的缓存设备
|
||||||
final List<ScanResult> devicesList = scanDevices;
|
final List<ScanResult> devicesList = scanDevices;
|
||||||
@ -517,8 +533,8 @@ class BlueManage {
|
|||||||
|
|
||||||
//查找缓存里面是否有设备
|
//查找缓存里面是否有设备
|
||||||
bool isExistScanDevices(String connectDeviceName) {
|
bool isExistScanDevices(String connectDeviceName) {
|
||||||
final bool isExistDevice = scanDevices
|
final bool isExistDevice = scanDevices.any((ScanResult element) =>
|
||||||
.any((ScanResult element) => element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
|
element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
|
||||||
return isExistDevice;
|
return isExistDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,8 +545,11 @@ class BlueManage {
|
|||||||
bool isAddEquipment = false, // 是否是添加设备之前
|
bool isAddEquipment = false, // 是否是添加设备之前
|
||||||
bool isReconnect = true, // 是否是重连
|
bool isReconnect = true, // 是否是重连
|
||||||
}) async {
|
}) async {
|
||||||
final int knownDeviceIndex =
|
// 判断数组列表里面是否有这个设备
|
||||||
devicesList.indexWhere((ScanResult d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
|
// AppLog.log("devicesList:$devicesList");
|
||||||
|
|
||||||
|
final int knownDeviceIndex = devicesList.indexWhere(
|
||||||
|
(ScanResult d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
|
||||||
|
|
||||||
ScanResult? scanResult; //使用局部变量防止出现缓存
|
ScanResult? scanResult; //使用局部变量防止出现缓存
|
||||||
if (knownDeviceIndex >= 0) {
|
if (knownDeviceIndex >= 0) {
|
||||||
@ -541,6 +560,7 @@ class BlueManage {
|
|||||||
|
|
||||||
bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
|
bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
|
||||||
scanResult = devicesList[knownDeviceIndex];
|
scanResult = devicesList[knownDeviceIndex];
|
||||||
|
// AppLog.log('bluetoothConnectDevice: $bluetoothConnectDevice scanResult:$scanResult');
|
||||||
|
|
||||||
_initGetMtuSubscription();
|
_initGetMtuSubscription();
|
||||||
_initListenConnectionState();
|
_initListenConnectionState();
|
||||||
@ -552,13 +572,87 @@ class BlueManage {
|
|||||||
upload: false);
|
upload: false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AppLog.log('调用了停止扫描的方法');
|
||||||
|
await stopScan();
|
||||||
|
if (scanResult.advertisementData.serviceUuids[0].toString().length >= 5 &&
|
||||||
|
(scanResult.advertisementData.serviceUuids[0].toString()[5] == '0') &&
|
||||||
|
isAddEquipment == false) {
|
||||||
|
// 添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接
|
||||||
|
if (isReconnect == true) {
|
||||||
|
AppLog.log('该锁已被重置, 重新发送扫描命令');
|
||||||
|
|
||||||
|
BuglyTool.uploadException(
|
||||||
|
message: '该锁已被重置, 重新发送扫描命令startScanSingle 上传记录当前方法是:_connectDevice',
|
||||||
|
detail:
|
||||||
|
'添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接 该锁已被重置, 重新发送扫描命令 serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
|
||||||
|
upload: false);
|
||||||
|
|
||||||
|
scanDevices.clear();
|
||||||
|
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
|
||||||
|
_connectDevice(scanDevices, deviceName, connectStateCallBack,
|
||||||
|
isAddEquipment: isAddEquipment, isReconnect: false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
connectStateCallBack(BluetoothConnectionState.disconnected);
|
||||||
|
if (!F.isSKY) {
|
||||||
|
EasyLoading.showToast('该锁已被重置'.tr, duration: 2000.milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
scanDevices.clear();
|
||||||
|
|
||||||
|
BuglyTool.uploadException(
|
||||||
|
message: '提示该锁已被重置, 回调断开连接, 清除缓存,上传记录当前方法是:_connectDevice',
|
||||||
|
detail: 'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
|
||||||
|
upload: false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (scanResult.advertisementData.serviceUuids[0].toString().length >= 30 &&
|
||||||
|
(scanResult.advertisementData.serviceUuids[0].toString()[31] == '0') &&
|
||||||
|
isAddEquipment == false) {
|
||||||
|
// 添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接
|
||||||
|
if (isReconnect == true) {
|
||||||
|
AppLog.log('该锁已被重置, 重新发送扫描命令');
|
||||||
|
|
||||||
|
BuglyTool.uploadException(
|
||||||
|
message: '该锁已被重置, 重新发送扫描命令startScanSingle 上传记录当前方法是:_connectDevice',
|
||||||
|
detail:
|
||||||
|
'添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接 该锁已被重置, 重新发送扫描命令 serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
|
||||||
|
upload: false);
|
||||||
|
|
||||||
|
scanDevices.clear();
|
||||||
|
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
|
||||||
|
_connectDevice(scanDevices, deviceName, connectStateCallBack,
|
||||||
|
isAddEquipment: isAddEquipment, isReconnect: true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
connectStateCallBack(BluetoothConnectionState.disconnected);
|
||||||
|
if (!F.isSKY) {
|
||||||
|
EasyLoading.showToast('该锁已被重置'.tr, duration: 2000.milliseconds);
|
||||||
|
}
|
||||||
|
scanDevices.clear();
|
||||||
|
|
||||||
|
BuglyTool.uploadException(
|
||||||
|
message: '提示该锁已被重置, 回调断开连接, 清除缓存,上传记录当前方法是:_connectDevice',
|
||||||
|
detail: 'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
|
||||||
|
upload: false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuglyTool.uploadException(
|
||||||
|
message: '从devicesList里面查到了设备 下一步连接设备 上传记录当前方法是:_connectDevice',
|
||||||
|
detail:
|
||||||
|
'devicesList:$devicesList scanResult:${scanResult.toString()} bluetoothConnectDevice:${bluetoothConnectDevice.toString()} connectDeviceMacAddress:$connectDeviceMacAddress',
|
||||||
|
upload: false);
|
||||||
|
|
||||||
//连接设备
|
//连接设备
|
||||||
await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack);
|
await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
//直接给蓝牙设备写入
|
//直接给蓝牙设备写入
|
||||||
Future<void> doNotSearchBLE(String masAdds, ConnectStateCallBack connectStateCallBack, {bool isAddEquipment = false}) async {
|
Future<void> doNotSearchBLE(String masAdds, ConnectStateCallBack connectStateCallBack,
|
||||||
|
{bool isAddEquipment = false}) async {
|
||||||
await FlutterBluePlus.stopScan();
|
await FlutterBluePlus.stopScan();
|
||||||
|
|
||||||
if (bluetoothConnectDevice == null || bluetoothConnectDevice?.remoteId.str != masAdds) {
|
if (bluetoothConnectDevice == null || bluetoothConnectDevice?.remoteId.str != masAdds) {
|
||||||
@ -566,7 +660,9 @@ class BlueManage {
|
|||||||
_initGetMtuSubscription();
|
_initGetMtuSubscription();
|
||||||
_initListenConnectionState();
|
_initListenConnectionState();
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '直接给蓝牙设备写入 上传记录当前方法是:doNotSearchBLE', detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds:$masAdds', upload: false);
|
message: '直接给蓝牙设备写入 上传记录当前方法是:doNotSearchBLE',
|
||||||
|
detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds:$masAdds',
|
||||||
|
upload: false);
|
||||||
} else {
|
} else {
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '直接给蓝牙设备写入 上传记录当前方法是:doNotSearchBLE',
|
message: '直接给蓝牙设备写入 上传记录当前方法是:doNotSearchBLE',
|
||||||
@ -651,7 +747,9 @@ class BlueManage {
|
|||||||
connectStateCallBack(bluetoothConnectionState!);
|
connectStateCallBack(bluetoothConnectionState!);
|
||||||
AppLog.log('发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState');
|
AppLog.log('发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState');
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '发现服务时失败', detail: '发现服务时报错原因e:$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}', upload: false);
|
message: '发现服务时失败',
|
||||||
|
detail: '发现服务时报错原因e:$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
|
||||||
|
upload: false);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -721,24 +819,12 @@ class BlueManage {
|
|||||||
for (final BluetoothCharacteristic characteristic in service.characteristics) {
|
for (final BluetoothCharacteristic characteristic in service.characteristics) {
|
||||||
if (characteristic.characteristicUuid == _characteristicIdWrite) {
|
if (characteristic.characteristicUuid == _characteristicIdWrite) {
|
||||||
try {
|
try {
|
||||||
_initGetMtuSubscription();
|
|
||||||
// 如果MTU还是默认值,尝试重新请求
|
|
||||||
if ((_mtuSize == 23 || _mtuSize == 20) && bluetoothConnectDevice != null) {
|
|
||||||
try {
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
await bluetoothConnectDevice!.requestMtu(512);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
AppLog.log('重新请求MTU失败: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 添加重试机制
|
// 添加重试机制
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
const int maxRetries = 3;
|
const int maxRetries = 3;
|
||||||
const int retryDelayMs = 500;
|
const int retryDelayMs = 500;
|
||||||
|
|
||||||
final List<int> valueList = value;
|
final List<int> valueList = value;
|
||||||
AppLog.log('发送数据时当前的mtuSize是:${_mtuSize}');
|
|
||||||
final List subData = splitList(valueList, _mtuSize!);
|
final List subData = splitList(valueList, _mtuSize!);
|
||||||
|
|
||||||
for (int i = 0; i < subData.length; i++) {
|
for (int i = 0; i < subData.length; i++) {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:star_lock/blue/entity/lock_user_no_list_entity.dart';
|
import 'package:star_lock/blue/entity/lock_user_no_list_entity.dart';
|
||||||
@ -21,10 +22,10 @@ import 'io_tool/manager_event_bus.dart';
|
|||||||
import 'sender_data.dart';
|
import 'sender_data.dart';
|
||||||
|
|
||||||
class SenderBeforeDataManage {
|
class SenderBeforeDataManage {
|
||||||
|
|
||||||
factory SenderBeforeDataManage() => shareManager()!;
|
factory SenderBeforeDataManage() => shareManager()!;
|
||||||
|
|
||||||
SenderBeforeDataManage._init();
|
SenderBeforeDataManage._init();
|
||||||
|
|
||||||
static SenderBeforeDataManage? _manager;
|
static SenderBeforeDataManage? _manager;
|
||||||
|
|
||||||
static SenderBeforeDataManage? shareManager() {
|
static SenderBeforeDataManage? shareManager() {
|
||||||
@ -41,7 +42,6 @@ class SenderBeforeDataManage {
|
|||||||
|
|
||||||
// 监听设备返回的数据
|
// 监听设备返回的数据
|
||||||
StreamSubscription<Reply>? _replySubscription;
|
StreamSubscription<Reply>? _replySubscription;
|
||||||
|
|
||||||
// 是否是添加用户之前的调用
|
// 是否是添加用户之前的调用
|
||||||
bool isBeforeAddUser = true;
|
bool isBeforeAddUser = true;
|
||||||
|
|
||||||
@ -146,8 +146,10 @@ class SenderBeforeDataManage {
|
|||||||
|
|
||||||
//获取清除用户列表指令
|
//获取清除用户列表指令
|
||||||
Future<List<int>> getCleanUpUsers({List<int>? tokenList}) async {
|
Future<List<int>> getCleanUpUsers({List<int>? tokenList}) async {
|
||||||
final LockUserNoListEntity entity = await ApiRepository.to.getLockUserNoList(lockId: CommonDataManage().currentKeyInfo.lockId!);
|
final LockUserNoListEntity entity = await ApiRepository.to
|
||||||
if (!entity.errorCode!.codeIsSuccessful || (entity.data?.userNos ?? <int>[]).isEmpty) {
|
.getLockUserNoList(lockId: CommonDataManage().currentKeyInfo.lockId!);
|
||||||
|
if (!entity.errorCode!.codeIsSuccessful ||
|
||||||
|
(entity.data?.userNos ?? <int>[]).isEmpty) {
|
||||||
throw Exception('ApiRepository.to.getLockUserNoList 访问失败');
|
throw Exception('ApiRepository.to.getLockUserNoList 访问失败');
|
||||||
}
|
}
|
||||||
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||||
@ -195,20 +197,19 @@ class SenderBeforeDataManage {
|
|||||||
int endDateTime = 0;
|
int endDateTime = 0;
|
||||||
bool isRound = false;
|
bool isRound = false;
|
||||||
int useCountLimit = 0xffff;
|
int useCountLimit = 0xffff;
|
||||||
if (currentKeyInfo.keyType == XSConstantMacro.keyTypeTime) {
|
if(currentKeyInfo.keyType == XSConstantMacro.keyTypeTime){
|
||||||
// 限时
|
// 限时
|
||||||
startDateTime = currentKeyInfo.startDate! ~/ 1000;
|
startDateTime = currentKeyInfo.startDate! ~/ 1000;
|
||||||
endDateTime = currentKeyInfo.endDate! ~/ 1000;
|
endDateTime = currentKeyInfo.endDate! ~/ 1000;
|
||||||
} else if (currentKeyInfo.keyType == XSConstantMacro.keyTypeLoop) {
|
}else if(currentKeyInfo.keyType == XSConstantMacro.keyTypeLoop){
|
||||||
// 循环
|
// 循环
|
||||||
isRound = true;
|
isRound = true;
|
||||||
startTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.startDate!);
|
startTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.startDate!);
|
||||||
endTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.endDate!);
|
endTime = DateTime.fromMillisecondsSinceEpoch(currentKeyInfo.endDate!);
|
||||||
|
|
||||||
startDateTime = DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.startDate!.toString()), 1) ~/ 1000;
|
startDateTime = DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.startDate!.toString()), 1) ~/ 1000;
|
||||||
endDateTime =
|
endDateTime = (DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.endDate!.toString()), 1) + CommonDataManage().dayLatestTime) ~/ 1000;
|
||||||
(DateTool().dateToTimestamp(DateTool().dateToYMDString(currentKeyInfo.endDate!.toString()), 1) + CommonDataManage().dayLatestTime) ~/ 1000;
|
}else if(currentKeyInfo.keyType == XSConstantMacro.keyTypeOnce){
|
||||||
} else if (currentKeyInfo.keyType == XSConstantMacro.keyTypeOnce) {
|
|
||||||
// 单次
|
// 单次
|
||||||
useCountLimit = 1;
|
useCountLimit = 1;
|
||||||
}
|
}
|
||||||
@ -216,7 +217,7 @@ class SenderBeforeDataManage {
|
|||||||
// AppLog.log("startTime.hour:${startTime!.hour} startTime.minute:${startTime!.minute} endTime.hour:${endTime!.hour} endTime.minute:${endTime!.minute}}");
|
// AppLog.log("startTime.hour:${startTime!.hour} startTime.minute:${startTime!.minute} endTime.hour:${endTime!.hour} endTime.minute:${endTime!.minute}}");
|
||||||
final AddUserCommand addUserData = AddUserCommand(
|
final AddUserCommand addUserData = AddUserCommand(
|
||||||
lockID: BlueManage().connectDeviceName,
|
lockID: BlueManage().connectDeviceName,
|
||||||
authUserID: currentKeyInfo.senderUserId?.toString() ?? '1',
|
authUserID: currentKeyInfo.senderUserId!.toString(),
|
||||||
keyID: currentKeyInfo.keyId.toString(),
|
keyID: currentKeyInfo.keyId.toString(),
|
||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
openMode: 1,
|
openMode: 1,
|
||||||
@ -225,7 +226,10 @@ class SenderBeforeDataManage {
|
|||||||
expireDate: endDateTime,
|
expireDate: endDateTime,
|
||||||
useCountLimit: useCountLimit,
|
useCountLimit: useCountLimit,
|
||||||
isRound: isRound ? 1 : 0,
|
isRound: isRound ? 1 : 0,
|
||||||
weekRound: isRound ? DateTool().accordingTheCycleIntoTheCorrespondingNumber(currentKeyInfo.weekDays!) : 0,
|
weekRound: isRound
|
||||||
|
? DateTool().accordingTheCycleIntoTheCorrespondingNumber(
|
||||||
|
currentKeyInfo.weekDays!)
|
||||||
|
: 0,
|
||||||
startHour: isRound ? startTime!.hour : 0,
|
startHour: isRound ? startTime!.hour : 0,
|
||||||
startMin: isRound ? startTime!.minute : 0,
|
startMin: isRound ? startTime!.minute : 0,
|
||||||
endHour: isRound ? endTime!.hour : 0,
|
endHour: isRound ? endTime!.hour : 0,
|
||||||
@ -267,7 +271,8 @@ class SenderBeforeDataManage {
|
|||||||
// 普通用户接收电子钥匙之后 更新锁用户NO
|
// 普通用户接收电子钥匙之后 更新锁用户NO
|
||||||
Future<void> _updateLockUserNo(List<int> dataList) async {
|
Future<void> _updateLockUserNo(List<int> dataList) async {
|
||||||
final LockNetTokenEntity entity = await ApiRepository.to.updateLockUserNo(
|
final LockNetTokenEntity entity = await ApiRepository.to.updateLockUserNo(
|
||||||
keyId: CommonDataManage().currentKeyInfo.keyId.toString(), lockUserNo: CommonDataManage().currentKeyInfo.lockUserNo.toString());
|
keyId: CommonDataManage().currentKeyInfo.keyId.toString(),
|
||||||
|
lockUserNo: CommonDataManage().currentKeyInfo.lockUserNo.toString());
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
eventBus.fire(RefreshLockListInfoDataEvent());
|
eventBus.fire(RefreshLockListInfoDataEvent());
|
||||||
eventBus.fire(LockAddUserSucceedEvent(<int>[0], 0));
|
eventBus.fire(LockAddUserSucceedEvent(<int>[0], 0));
|
||||||
@ -276,8 +281,9 @@ class SenderBeforeDataManage {
|
|||||||
|
|
||||||
// 更新锁用户InitUserNo
|
// 更新锁用户InitUserNo
|
||||||
Future<void> _updateLockInitUserNo() async {
|
Future<void> _updateLockInitUserNo() async {
|
||||||
final LockNetTokenEntity entity = await ApiRepository.to
|
final LockNetTokenEntity entity = await ApiRepository.to.updateLockInitUserNo(
|
||||||
.updateLockInitUserNo(lockId: CommonDataManage().currentKeyInfo.lockId ?? 0, initUserNo: CommonDataManage().currentKeyInfo.initUserNo ?? 0);
|
lockId: CommonDataManage().currentKeyInfo.lockId ?? 0,
|
||||||
|
initUserNo: CommonDataManage().currentKeyInfo.initUserNo ?? 0);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
eventBus.fire(RefreshLockListInfoDataEvent());
|
eventBus.fire(RefreshLockListInfoDataEvent());
|
||||||
eventBus.fire(LockInitUserNoEvent());
|
eventBus.fire(LockInitUserNoEvent());
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class F {
|
|||||||
case Flavor.sky:
|
case Flavor.sky:
|
||||||
case Flavor.sky_dev:
|
case Flavor.sky_dev:
|
||||||
case Flavor.sky_pre:
|
case Flavor.sky_pre:
|
||||||
return '锁通通'.tr;
|
return '锁博士'.tr;
|
||||||
case Flavor.xhj:
|
case Flavor.xhj:
|
||||||
case Flavor.xhj_bundle:
|
case Flavor.xhj_bundle:
|
||||||
case Flavor.xhj_dev:
|
case Flavor.xhj_dev:
|
||||||
@ -119,7 +119,7 @@ class F {
|
|||||||
case Flavor.sky:
|
case Flavor.sky:
|
||||||
case Flavor.sky_dev:
|
case Flavor.sky_dev:
|
||||||
case Flavor.sky_pre:
|
case Flavor.sky_pre:
|
||||||
return '锁通通'.tr;
|
return '锁博士'.tr;
|
||||||
case Flavor.xhj:
|
case Flavor.xhj:
|
||||||
case Flavor.xhj_bundle:
|
case Flavor.xhj_bundle:
|
||||||
case Flavor.xhj_dev:
|
case Flavor.xhj_dev:
|
||||||
|
|||||||
@ -52,6 +52,13 @@ class StarLockLoginLogic extends BaseGetXController {
|
|||||||
|
|
||||||
Future<void> login() async {
|
Future<void> login() async {
|
||||||
FocusScope.of(Get.context!).requestFocus(FocusNode()); //关闭键盘
|
FocusScope.of(Get.context!).requestFocus(FocusNode()); //关闭键盘
|
||||||
|
|
||||||
|
// 添加邮箱格式验证
|
||||||
|
if (!GetUtils.isEmail(state.emailOrPhone.value)) {
|
||||||
|
showToast('请输入有效的邮箱地址');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final LoginEntity entity = await ApiRepository.to.login(
|
final LoginEntity entity = await ApiRepository.to.login(
|
||||||
loginType: '1',
|
loginType: '1',
|
||||||
password: state.pwd.value,
|
password: state.pwd.value,
|
||||||
|
|||||||
@ -88,30 +88,31 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
child: Center(child: Image.asset('images/icon_main_sky_1024.png', width: 110.w, height: 110.w))),
|
child: Center(child: Image.asset('images/icon_main_drlock_1024.png', width: 110.w, height: 110.w))),
|
||||||
SizedBox(height: 50.w),
|
SizedBox(height: 50.w),
|
||||||
Obx(() => CommonItem(
|
// Obx(() =>
|
||||||
leftTitel: '你所在的国家/地区'.tr,
|
// CommonItem(
|
||||||
rightTitle: '',
|
// leftTitel: '你所在的国家/地区'.tr,
|
||||||
isHaveLine: true,
|
// rightTitle: '',
|
||||||
isPadding: false,
|
// isHaveLine: true,
|
||||||
isHaveRightWidget: true,
|
// isPadding: false,
|
||||||
isHaveDirection: true,
|
// isHaveRightWidget: true,
|
||||||
rightWidget: Text(
|
// isHaveDirection: true,
|
||||||
'${state.countryName} +${state.countryCode.value}',
|
// rightWidget: Text(
|
||||||
textAlign: TextAlign.end,
|
// '${state.countryName} +${state.countryCode.value}',
|
||||||
style: TextStyle(fontSize: 22.sp, color: AppColors.darkGrayTextColor),
|
// textAlign: TextAlign.end,
|
||||||
),
|
// style: TextStyle(fontSize: 22.sp, color: AppColors.darkGrayTextColor),
|
||||||
action: () async {
|
// ),
|
||||||
final result = await Get.toNamed(Routers.selectCountryRegionPage);
|
// action: () async {
|
||||||
if (result != null) {
|
// final result = await Get.toNamed(Routers.selectCountryRegionPage);
|
||||||
result as Map<String, dynamic>;
|
// if (result != null) {
|
||||||
state.countryCode.value = result['code'];
|
// result as Map<String, dynamic>;
|
||||||
state.countryKey.value = result['countryName'];
|
// state.countryCode.value = result['code'];
|
||||||
logic.checkIpAction();
|
// state.countryKey.value = result['countryName'];
|
||||||
}
|
// logic.checkIpAction();
|
||||||
},
|
// }
|
||||||
)),
|
// },
|
||||||
|
// )),
|
||||||
LoginInput(
|
LoginInput(
|
||||||
focusNode: logic.state.emailOrPhoneFocusNode,
|
focusNode: logic.state.emailOrPhoneFocusNode,
|
||||||
controller: state.emailOrPhoneController,
|
controller: state.emailOrPhoneController,
|
||||||
@ -126,12 +127,16 @@ class _StarLockLoginPageState extends State<StarLockLoginPage> {
|
|||||||
height: 36.w,
|
height: 36.w,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
hintText: '请输入手机号或者邮箱'.tr,
|
// hintText: '请输入手机号或者邮箱'.tr,
|
||||||
|
hintText: '请输入邮箱'.tr,
|
||||||
// keyboardType: TextInputType.number,
|
// keyboardType: TextInputType.number,
|
||||||
|
keyboardType: TextInputType.emailAddress,
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
// FilteringTextInputFormatter.allow(RegExp('[0-9]')),
|
// FilteringTextInputFormatter.allow(RegExp('[0-9]')),
|
||||||
LengthLimitingTextInputFormatter(30),
|
LengthLimitingTextInputFormatter(30),
|
||||||
FilteringTextInputFormatter.singleLineFormatter
|
FilteringTextInputFormatter.singleLineFormatter,
|
||||||
|
// 添加邮箱格式限制
|
||||||
|
FilteringTextInputFormatter.allow(RegExp(r'^[a-zA-Z0-9@._-]+$')),
|
||||||
]),
|
]),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
LoginInput(
|
LoginInput(
|
||||||
|
|||||||
@ -30,7 +30,8 @@ class StarLockLoginState {
|
|||||||
RxString emailOrPhone = ''.obs;
|
RxString emailOrPhone = ''.obs;
|
||||||
RxString pwd = ''.obs;
|
RxString pwd = ''.obs;
|
||||||
RxBool canNext = false.obs;
|
RxBool canNext = false.obs;
|
||||||
bool get isEmailOrPhone => emailOrPhone.value.isNotEmpty;
|
// bool get isEmailOrPhone => emailOrPhone.value.isNotEmpty;
|
||||||
|
bool get isEmailOrPhone => GetUtils.isEmail(emailOrPhone.value);
|
||||||
bool get pwdIsOK => pwd.value.isNotEmpty;
|
bool get pwdIsOK => pwd.value.isNotEmpty;
|
||||||
|
|
||||||
TextEditingController emailOrPhoneController = TextEditingController();
|
TextEditingController emailOrPhoneController = TextEditingController();
|
||||||
|
|||||||
@ -41,7 +41,7 @@ class _StarLockRegisterPageState extends State<StarLockRegisterPage> {
|
|||||||
child: ListView(
|
child: ListView(
|
||||||
padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w),
|
padding: EdgeInsets.only(top: 40.h, left: 40.w, right: 40.w),
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
topSelectCountryAndRegionWidget(),
|
// topSelectCountryAndRegionWidget(),
|
||||||
middleTFWidget(),
|
middleTFWidget(),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
return SubmitBtn(
|
return SubmitBtn(
|
||||||
|
|||||||
@ -6,7 +6,7 @@ class StarLockRegisterState {
|
|||||||
StarLockRegisterState() {
|
StarLockRegisterState() {
|
||||||
// 根据系统语言设置默认选中的tab
|
// 根据系统语言设置默认选中的tab
|
||||||
final Locale? systemLocale = Get.deviceLocale;
|
final Locale? systemLocale = Get.deviceLocale;
|
||||||
isIphoneType.value = systemLocale?.languageCode == 'zh';
|
//isIphoneType.value = systemLocale?.languageCode == 'zh';
|
||||||
|
|
||||||
resetResend();
|
resetResend();
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ class StarLockRegisterState {
|
|||||||
RxString surePwd = ''.obs;
|
RxString surePwd = ''.obs;
|
||||||
RxString verificationCode = ''.obs;
|
RxString verificationCode = ''.obs;
|
||||||
RxString xWidth = ''.obs; // 滑动验证码滑动位置
|
RxString xWidth = ''.obs; // 滑动验证码滑动位置
|
||||||
RxBool isIphoneType = true.obs;
|
RxBool isIphoneType = false.obs;
|
||||||
RxBool canSub = false.obs; // 是否能提交
|
RxBool canSub = false.obs; // 是否能提交
|
||||||
RxBool agree = false.obs;
|
RxBool agree = false.obs;
|
||||||
RxBool canSendCode = false.obs; // 是否能发送验证码
|
RxBool canSendCode = false.obs; // 是否能发送验证码
|
||||||
|
|||||||
@ -69,6 +69,14 @@ FutureOr<void> main() async {
|
|||||||
String? token = await CallKitHandler.getVoipToken();
|
String? token = await CallKitHandler.getVoipToken();
|
||||||
print('获取到的VoIP Token: $token');
|
print('获取到的VoIP Token: $token');
|
||||||
}
|
}
|
||||||
|
// 在 runApp 之前设置
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(
|
||||||
|
const SystemUiOverlayStyle(
|
||||||
|
statusBarColor: Colors.transparent, // 状态栏背景色(通常透明)
|
||||||
|
statusBarIconBrightness: Brightness.dark, // Android: 黑色图标
|
||||||
|
statusBarBrightness: Brightness.dark, // iOS: 状态栏内容为深色(影响时间等颜色)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
runApp(MyApp(isLogin: isLogin));
|
runApp(MyApp(isLogin: isLogin));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -658,7 +658,6 @@ class LockDetailLogic extends BaseGetXController {
|
|||||||
if (list.isEmpty) {
|
if (list.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AppLog.log('list:${list}');
|
|
||||||
final KeyOperationRecordEntity entity =
|
final KeyOperationRecordEntity entity =
|
||||||
await ApiRepository.to.lockRecordUploadData(lockId: state.keyInfos.value.lockId.toString(), records: list);
|
await ApiRepository.to.lockRecordUploadData(lockId: state.keyInfos.value.lockId.toString(), records: list);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@ -37,25 +36,23 @@ class _LockDetailMainPageState extends State<LockDetailMainPage> {
|
|||||||
appBar: TitleAppBar(
|
appBar: TitleAppBar(
|
||||||
barTitle: F.navTitle,
|
barTitle: F.navTitle,
|
||||||
haveBack: true,
|
haveBack: true,
|
||||||
backgroundColor: AppColors.mainColor),
|
backgroundColor: Colors.white,
|
||||||
body: LockDetailPage(
|
titleColor: Colors.black,
|
||||||
isOnlyOneData: isOnlyOneData,
|
iconColor: Colors.black,
|
||||||
lockListInfoItemEntity: keyInfos),
|
),
|
||||||
|
body: LockDetailPage(isOnlyOneData: isOnlyOneData, lockListInfoItemEntity: keyInfos),
|
||||||
// body: Container(),
|
// body: Container(),
|
||||||
),
|
),
|
||||||
xhjCall: () => Scaffold(
|
xhjCall: () => Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: TitleAppBar(
|
appBar: TitleAppBar(
|
||||||
barTitle: F.sw(
|
barTitle: F.sw(xhjCall: () => '星星锁'.tr, skyCall: () => keyInfos.lockAlias),
|
||||||
xhjCall: () => '星星锁'.tr, skyCall: () => keyInfos.lockAlias),
|
|
||||||
haveBack: true,
|
haveBack: true,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
titleColor: AppColors.blackColor,
|
titleColor: AppColors.blackColor,
|
||||||
iconColor: AppColors.blackColor,
|
iconColor: AppColors.blackColor,
|
||||||
),
|
),
|
||||||
body: LockDetailPage(
|
body: LockDetailPage(isOnlyOneData: isOnlyOneData, lockListInfoItemEntity: keyInfos),
|
||||||
isOnlyOneData: isOnlyOneData,
|
|
||||||
lockListInfoItemEntity: keyInfos),
|
|
||||||
// body: Container(),
|
// body: Container(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -464,6 +464,44 @@ class _LockDetailPageState extends State<LockDetailPage> with TickerProviderStat
|
|||||||
Widget skWidget() {
|
Widget skWidget() {
|
||||||
return ListView(
|
return ListView(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
Visibility(
|
||||||
|
visible: widget.isOnlyOneData,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Image.asset('images/icon_main_drlock_1024.png', width: 68.w, height: 68.w),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
F.title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 28.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
//实现回调函数
|
||||||
|
Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
Routers.selectLockTypePage,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.add_circle_outline_rounded,
|
||||||
|
size: 48.sp,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: (state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime ||
|
visible: (state.keyInfos.value.keyType == XSConstantMacro.keyTypeTime ||
|
||||||
state.keyInfos.value.keyType == XSConstantMacro.keyTypeLoop) && // 限时、循环
|
state.keyInfos.value.keyType == XSConstantMacro.keyTypeLoop) && // 限时、循环
|
||||||
|
|||||||
@ -29,24 +29,7 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
super.onReady();
|
super.onReady();
|
||||||
await getActivateInfo();
|
await getActivateInfo();
|
||||||
_initReplySubscription();
|
_initReplySubscription();
|
||||||
await getServerDatetime();
|
getServerDatetime();
|
||||||
showEasyLoading();
|
|
||||||
showBlueConnetctToastTimer(action: () {
|
|
||||||
dismissEasyLoading();
|
|
||||||
});
|
|
||||||
BlueManage().blueSendData(
|
|
||||||
BlueManage().connectDeviceName,
|
|
||||||
(BluetoothConnectionState connectionState) async {
|
|
||||||
if (connectionState == BluetoothConnectionState.connected) {
|
|
||||||
IoSenderManage.readRegisterKey(
|
|
||||||
lockID: BlueManage().connectDeviceName,
|
|
||||||
);
|
|
||||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
|
||||||
dismissEasyLoading();
|
|
||||||
cancelBlueConnetctToastTimer();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -74,7 +57,6 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
Future<void> getServerDatetime() async {
|
Future<void> getServerDatetime() async {
|
||||||
final GetServerDatetimeEntity entity = await ApiRepository.to.getServerDatetimeData(isUnShowLoading: true);
|
final GetServerDatetimeEntity entity = await ApiRepository.to.getServerDatetimeData(isUnShowLoading: true);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.serverTime = entity.data!.date! ~/ 1000;
|
|
||||||
state.differentialTime = entity.data!.date! ~/ 1000 - DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
state.differentialTime = entity.data!.date! ~/ 1000 - DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,6 +72,7 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||||
|
AppLog.log('输出了listen:${_replySubscription.hashCode}');
|
||||||
if (reply is SenderReadRegisterKeyCommandReply) {
|
if (reply is SenderReadRegisterKeyCommandReply) {
|
||||||
_handleReadRegisterKeyReply(reply);
|
_handleReadRegisterKeyReply(reply);
|
||||||
}
|
}
|
||||||
@ -175,7 +158,7 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
uuid: response.data?.extraParams?['uuid'],
|
uuid: response.data?.extraParams?['uuid'],
|
||||||
key: response.data?.authCode,
|
key: response.data?.authCode,
|
||||||
mac: response.data?.extraParams?['mac'],
|
mac: response.data?.extraParams?['mac'],
|
||||||
platform: state.selectPlatFormIndex.value,
|
platform: 1,
|
||||||
utcTimeStamp: getUTCNetTime(),
|
utcTimeStamp: getUTCNetTime(),
|
||||||
);
|
);
|
||||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||||
@ -207,12 +190,26 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void savePlatFormSetting() {
|
void savePlatFormSetting() {
|
||||||
if (state.selectPlatFormIndex.value == 1 || state.selectPlatFormIndex.value == 0) {
|
if (state.selectPlatFormIndex.value == 1) {
|
||||||
if (state.registerKey.isNotEmpty) {
|
showEasyLoading();
|
||||||
_requestAuthorizationCode();
|
showBlueConnetctToastTimer(action: () {
|
||||||
|
dismissEasyLoading();
|
||||||
|
});
|
||||||
|
BlueManage().blueSendData(
|
||||||
|
BlueManage().connectDeviceName,
|
||||||
|
(BluetoothConnectionState connectionState) async {
|
||||||
|
if (connectionState == BluetoothConnectionState.connected) {
|
||||||
|
IoSenderManage.readRegisterKey(
|
||||||
|
lockID: BlueManage().connectDeviceName,
|
||||||
|
);
|
||||||
|
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||||
|
dismissEasyLoading();
|
||||||
|
cancelBlueConnetctToastTimer();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
showToast('目前只支持切换至涂鸦智能、锁通通协议'.tr);
|
showToast('目前只支持切换至涂鸦智能协议'.tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,14 +232,15 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
final platform = reply.data[7];
|
|
||||||
// 提取 RegisterKey (从第7个字节开始,长度为40)
|
// 提取 RegisterKey (从第7个字节开始,长度为40)
|
||||||
final List<int> registerKeyBytes = reply.data.sublist(8, 48);
|
final List<int> registerKeyBytes = reply.data.sublist(7, 47);
|
||||||
final String registerKey = String.fromCharCodes(registerKeyBytes);
|
final String registerKey = String.fromCharCodes(registerKeyBytes);
|
||||||
state.selectPlatFormIndex.value = platform;
|
|
||||||
print('platform: $platform');
|
|
||||||
print('Register Key: $registerKey');
|
print('Register Key: $registerKey');
|
||||||
state.registerKey.value = registerKey;
|
state.registerKey.value = registerKey;
|
||||||
|
if (registerKey.isNotEmpty) {
|
||||||
|
_requestAuthorizationCode();
|
||||||
|
}
|
||||||
//成功
|
//成功
|
||||||
cancelBlueConnetctToastTimer();
|
cancelBlueConnetctToastTimer();
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
@ -267,8 +265,8 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
IoSenderManage.senderGetStarLockStatuInfo(
|
IoSenderManage.senderGetStarLockStatuInfo(
|
||||||
lockID: BlueManage().connectDeviceName,
|
lockID: BlueManage().connectDeviceName,
|
||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
utcTimeStamp: state.serverTime,
|
utcTimeStamp: 0,
|
||||||
unixTimeStamp: getLocalTime2(),
|
unixTimeStamp: 0,
|
||||||
isBeforeAddUser: false,
|
isBeforeAddUser: false,
|
||||||
privateKey: getPrivateKeyList,
|
privateKey: getPrivateKeyList,
|
||||||
);
|
);
|
||||||
@ -280,18 +278,6 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLocalTime() {
|
|
||||||
final DateTime now = DateTime.now();
|
|
||||||
final Duration timeZoneOffset = now.timeZoneOffset;
|
|
||||||
return state.differentialTime + timeZoneOffset.inSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getLocalTime2() {
|
|
||||||
final DateTime now = DateTime.now();
|
|
||||||
final Duration timeZoneOffset = now.timeZoneOffset;
|
|
||||||
return state.serverTime + timeZoneOffset.inSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleAuthorizationCodeReply(SenderAuthorizationCodeCommandReply reply) {
|
void _handleAuthorizationCodeReply(SenderAuthorizationCodeCommandReply reply) {
|
||||||
final int status = reply.data[6];
|
final int status = reply.data[6];
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -299,12 +285,7 @@ class ThirdPartyPlatformLogic extends BaseGetXController {
|
|||||||
//成功
|
//成功
|
||||||
cancelBlueConnetctToastTimer();
|
cancelBlueConnetctToastTimer();
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
if (state.selectPlatFormIndex.value == 1) {
|
showToast('操作成功,请在24小时内用涂鸦APP添加门锁,否则将过期'.tr);
|
||||||
showSuccess('操作成功,请尽快用"涂鸦”APP配置,如不使用请关闭该设置支持'.tr);
|
|
||||||
} else if (state.selectPlatFormIndex.value == 0) {
|
|
||||||
showSuccess('操作成功'.tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//失败
|
//失败
|
||||||
|
|||||||
@ -128,8 +128,7 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
|
|||||||
// 最后一个元素不显示分割线(取反)
|
// 最后一个元素不显示分割线(取反)
|
||||||
isHaveDirection: false,
|
isHaveDirection: false,
|
||||||
isHaveRightWidget: true,
|
isHaveRightWidget: true,
|
||||||
rightWidget: Obx(
|
rightWidget: Radio<String>(
|
||||||
() => Radio<String>(
|
|
||||||
// Radio 的值:使用平台的唯一标识(如 id)
|
// Radio 的值:使用平台的唯一标识(如 id)
|
||||||
value: platform,
|
value: platform,
|
||||||
// 当前选中的值:与 selectPlatFormIndex 关联的 id
|
// 当前选中的值:与 selectPlatFormIndex 关联的 id
|
||||||
@ -149,7 +148,6 @@ class _ThirdPartyPlatformPageState extends State<ThirdPartyPlatformPage> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
action: () {
|
action: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
state.selectPlatFormIndex.value = index;
|
state.selectPlatFormIndex.value = index;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class ThirdPartyPlatformState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
|
Rx<LockSetInfoData> lockSetInfoData = LockSetInfoData().obs;
|
||||||
int differentialTime = 0; // 服务器时间即UTC+0时间
|
int differentialTime = 0;// 服务器时间即UTC+0时间
|
||||||
|
|
||||||
// 响应式字符串集合(自动触发 UI 更新)
|
// 响应式字符串集合(自动触发 UI 更新)
|
||||||
final RxList<String> platFormSet = List.of({
|
final RxList<String> platFormSet = List.of({
|
||||||
@ -25,11 +25,8 @@ class ThirdPartyPlatformState {
|
|||||||
// 响应式字符串集合(自动触发 UI 更新)
|
// 响应式字符串集合(自动触发 UI 更新)
|
||||||
final RxList<TppSupportInfo> tppSupportList = RxList<TppSupportInfo>([]);
|
final RxList<TppSupportInfo> tppSupportList = RxList<TppSupportInfo>([]);
|
||||||
|
|
||||||
RxInt selectPlatFormIndex = 0.obs;
|
RxInt selectPlatFormIndex = 1.obs;
|
||||||
RxBool openNumber = false.obs;
|
|
||||||
RxString registerKey = ''.obs;
|
RxString registerKey = ''.obs;
|
||||||
|
|
||||||
Map lockInfo = {};
|
Map lockInfo = {};
|
||||||
|
|
||||||
int serverTime = 0; // 服务器时间即UTC+0时间
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -300,7 +300,7 @@ class PasswordKeyDetailLogic extends BaseGetXController {
|
|||||||
'\n' +
|
'\n' +
|
||||||
'有效期'.tr +
|
'有效期'.tr +
|
||||||
':${startDateStr.toLocal().toString().substring(0, 16)} -- ${endDateStr.toLocal().toString().substring(0, 16)}\n\n' +
|
':${startDateStr.toLocal().toString().substring(0, 16)} -- ${endDateStr.toLocal().toString().substring(0, 16)}\n\n' +
|
||||||
'这是单次密码,只能使用一次\n';
|
'${'这是单次密码,只能使用一次'.tr}\n';
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
//永久 2 从开始时间开始永久有效,必需在开始时间24小时内使用一次,否则将失效
|
//永久 2 从开始时间开始永久有效,必需在开始时间24小时内使用一次,否则将失效
|
||||||
@ -309,8 +309,8 @@ class PasswordKeyDetailLogic extends BaseGetXController {
|
|||||||
':' +
|
':' +
|
||||||
'永久'.tr +
|
'永久'.tr +
|
||||||
'\n' +
|
'\n' +
|
||||||
'\n注:\n' +
|
'\n${'注:'.tr}\n' +
|
||||||
'必需在开始时间24小时内使用一次,否则将失效\n';
|
'${'必需在开始时间24小时内使用一次,否则将失效'.tr}\n';
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
//限期 3 在开始和结束时间内有效,必需在开始时间24小时内使用一次,否则将失效
|
//限期 3 在开始和结束时间内有效,必需在开始时间24小时内使用一次,否则将失效
|
||||||
@ -324,7 +324,7 @@ class PasswordKeyDetailLogic extends BaseGetXController {
|
|||||||
':${startDateStr.toLocal().toString().substring(0, 16)}-${endDateStr.toLocal().toString().substring(0, 16)}' +
|
':${startDateStr.toLocal().toString().substring(0, 16)}-${endDateStr.toLocal().toString().substring(0, 16)}' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'\n注:\n' +
|
'\n注:\n' +
|
||||||
'必需在开始时间24小时内使用一次,否则将失效\n';
|
'${'必需在开始时间24小时内使用一次,否则将失效'.tr}\n';
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
//删除 4 在锁上使用后会删除之前在锁上使用过的密码
|
//删除 4 在锁上使用后会删除之前在锁上使用过的密码
|
||||||
@ -453,9 +453,10 @@ class PasswordKeyDetailLogic extends BaseGetXController {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
// return '您好,您的密码是'.tr + ':${state.itemData.value.keyboardPwd}\n$useDateStr\n${'密码名字'.tr}:${state.itemData.value.keyboardPwdName}';
|
// return '您好,您的密码是'.tr + ':${state.itemData.value.keyboardPwd}\n$useDateStr\n${'密码名字'.tr}:${state.itemData.value.keyboardPwdName}';
|
||||||
return '您好' +
|
return '您好'.tr +
|
||||||
',\n您的开门密码是' +
|
',\n${'您的开门密码是'.tr}' +
|
||||||
':${state.itemData.value.keyboardPwd}\n$useDateStr\n${'密码名字'.tr}:${state.itemData.value.keyboardPwdName}\n\n开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标';
|
':${state.itemData.value.keyboardPwd}\n$useDateStr\n${'密码名字'.tr}:${state.itemData.value.keyboardPwdName}\n'
|
||||||
|
'\n${'开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标'.tr}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -46,32 +46,24 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
} else if (state.widgetType.value == 1) {
|
} else if (state.widgetType.value == 1) {
|
||||||
//限时
|
//限时
|
||||||
// 鑫鸿佳不需要生效时间
|
// 鑫鸿佳不需要生效时间
|
||||||
if (CommonDataManage().currentKeyInfo.vendor ==
|
if (CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XHJ &&
|
||||||
IoModelVendor.vendor_XHJ &&
|
(CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XHJ_SYD ||
|
||||||
(CommonDataManage().currentKeyInfo.model ==
|
CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XHJ_JL)) {
|
||||||
IoModelVendor.model_XHJ_SYD ||
|
if (endDate <= DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) {
|
||||||
CommonDataManage().currentKeyInfo.model ==
|
|
||||||
IoModelVendor.model_XHJ_JL)) {
|
|
||||||
if (endDate <=
|
|
||||||
DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) {
|
|
||||||
showToast('失效时间要大于当前时间'.tr);
|
showToast('失效时间要大于当前时间'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//endDate 设置当天凌晨 0 点
|
//endDate 设置当天凌晨 0 点
|
||||||
final DateTime now = DateTime.now();
|
final DateTime now = DateTime.now();
|
||||||
startDate =
|
startDate = DateTime(now.year, now.month, now.day).millisecondsSinceEpoch;
|
||||||
DateTime(now.year, now.month, now.day).millisecondsSinceEpoch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 芯连需要生效时间
|
// 芯连需要生效时间
|
||||||
if (CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL &&
|
if (CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL &&
|
||||||
(CommonDataManage().currentKeyInfo.model ==
|
(CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_BLE ||
|
||||||
IoModelVendor.model_XL_BLE ||
|
CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_WIFI)) {
|
||||||
CommonDataManage().currentKeyInfo.model ==
|
|
||||||
IoModelVendor.model_XL_WIFI)) {
|
|
||||||
//限时
|
//限时
|
||||||
if (startDate <
|
if (startDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) {
|
||||||
DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) {
|
|
||||||
showToast('生效时间不能小于当前时间'.tr);
|
showToast('生效时间不能小于当前时间'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -91,12 +83,9 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
//循环
|
//循环
|
||||||
// 芯连需要结束时间
|
// 芯连需要结束时间
|
||||||
if (CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL &&
|
if (CommonDataManage().currentKeyInfo.vendor == IoModelVendor.vendor_XL &&
|
||||||
(CommonDataManage().currentKeyInfo.model ==
|
(CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_BLE ||
|
||||||
IoModelVendor.model_XL_BLE ||
|
CommonDataManage().currentKeyInfo.model == IoModelVendor.model_XL_WIFI)) {
|
||||||
CommonDataManage().currentKeyInfo.model ==
|
if (endDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) {
|
||||||
IoModelVendor.model_XL_WIFI)) {
|
|
||||||
if (endDate <
|
|
||||||
DateTool().dateToTimestamp(DateTool().getNowDateWithType(3), 1)) {
|
|
||||||
showToast('结束时间不能小于当前时间'.tr);
|
showToast('结束时间不能小于当前时间'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -166,10 +155,8 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
//是否为永久
|
//是否为永久
|
||||||
if (state.isPermanent.value == false) {
|
if (state.isPermanent.value == false) {
|
||||||
getKeyType = '3';
|
getKeyType = '3';
|
||||||
getEffectiveDateTime =
|
getEffectiveDateTime = DateTool().dateToTimestamp(state.customBeginTime.value, 1).toString();
|
||||||
DateTool().dateToTimestamp(state.customBeginTime.value, 1).toString();
|
getFailureDateTime = DateTool().dateToTimestamp(state.customEndTime.value, 1).toString();
|
||||||
getFailureDateTime =
|
|
||||||
DateTool().dateToTimestamp(state.customEndTime.value, 1).toString();
|
|
||||||
}
|
}
|
||||||
final PasswordKeyEntity entity = await ApiRepository.to.addPasswordKey(
|
final PasswordKeyEntity entity = await ApiRepository.to.addPasswordKey(
|
||||||
lockId: lockId,
|
lockId: lockId,
|
||||||
@ -184,8 +171,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
ApmHelper.instance.trackEvent('add_password', {
|
ApmHelper.instance.trackEvent('add_password', {
|
||||||
'lock_name': BlueManage().connectDeviceName,
|
'lock_name': BlueManage().connectDeviceName,
|
||||||
'account':
|
'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
||||||
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
|
||||||
'date': DateTool().getNowDateWithType(1),
|
'date': DateTool().getNowDateWithType(1),
|
||||||
'add_password_result': '成功',
|
'add_password_result': '成功',
|
||||||
});
|
});
|
||||||
@ -202,8 +188,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
} else {
|
} else {
|
||||||
ApmHelper.instance.trackEvent('add_password', {
|
ApmHelper.instance.trackEvent('add_password', {
|
||||||
'lock_name': BlueManage().connectDeviceName,
|
'lock_name': BlueManage().connectDeviceName,
|
||||||
'account':
|
'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
||||||
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
|
||||||
'date': DateTool().getNowDateWithType(1),
|
'date': DateTool().getNowDateWithType(1),
|
||||||
'add_password_result': '${entity.errorMsg}',
|
'add_password_result': '${entity.errorMsg}',
|
||||||
});
|
});
|
||||||
@ -230,8 +215,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
showToast('请输入密码'.tr);
|
showToast('请输入密码'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PasswordKeyEntity entity =
|
final PasswordKeyEntity entity = await ApiRepository.to.checkKeyboardpwdName(
|
||||||
await ApiRepository.to.checkKeyboardpwdName(
|
|
||||||
lockId: state.keyInfo.value.lockId.toString(),
|
lockId: state.keyInfo.value.lockId.toString(),
|
||||||
keyboardPwdName: state.nameController.text,
|
keyboardPwdName: state.nameController.text,
|
||||||
keyboardPwd: state.pwdController.text,
|
keyboardPwd: state.pwdController.text,
|
||||||
@ -246,16 +230,11 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
late StreamSubscription<Reply> _replySubscription;
|
late StreamSubscription<Reply> _replySubscription;
|
||||||
|
|
||||||
void _initReplySubscription() {
|
void _initReplySubscription() {
|
||||||
_replySubscription =
|
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||||
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
|
||||||
// 设置自定义密码
|
// 设置自定义密码
|
||||||
if ((reply is SenderCustomPasswordsReply) &&
|
if ((reply is SenderCustomPasswordsReply) && (state.ifCurrentScreen.value == true)) {
|
||||||
(state.ifCurrentScreen.value == true)) {
|
|
||||||
BuglyTool.uploadException(
|
BuglyTool.uploadException(
|
||||||
message: '添加密码结果,解析数据',
|
message: '添加密码结果,解析数据', detail: '添加密码结果,解析数据:${reply.data}', eventStr: '添加密码事件结果', upload: true);
|
||||||
detail: '添加密码结果,解析数据:${reply.data}',
|
|
||||||
eventStr: '添加密码事件结果',
|
|
||||||
upload: true);
|
|
||||||
|
|
||||||
final int status = reply.data[2];
|
final int status = reply.data[2];
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -305,20 +284,14 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
final List<String> saveStrList = changeIntListToStringList(token);
|
final List<String> saveStrList = changeIntListToStringList(token);
|
||||||
Storage.setStringList(saveBlueToken, saveStrList);
|
Storage.setStringList(saveBlueToken, saveStrList);
|
||||||
|
|
||||||
final List<String>? privateKey =
|
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||||
await Storage.getStringList(saveBluePrivateKey);
|
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||||
final List<int> getPrivateKeyList =
|
|
||||||
changeStringListToIntList(privateKey!);
|
|
||||||
|
|
||||||
final List<String>? signKey =
|
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
|
||||||
await Storage.getStringList(saveBlueSignKey);
|
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||||
final List<int> signKeyDataList =
|
|
||||||
changeStringListToIntList(signKey!);
|
|
||||||
|
|
||||||
int startDate =
|
int startDate = DateTool().dateToTimestamp(state.customBeginTime.value, 1);
|
||||||
DateTool().dateToTimestamp(state.customBeginTime.value, 1);
|
int endDate = DateTool().dateToTimestamp(state.customEndTime.value, 1);
|
||||||
int endDate =
|
|
||||||
DateTool().dateToTimestamp(state.customEndTime.value, 1);
|
|
||||||
//非永久 须有时限
|
//非永久 须有时限
|
||||||
if (state.isPermanent.value == true) {
|
if (state.isPermanent.value == true) {
|
||||||
startDate = 0;
|
startDate = 0;
|
||||||
@ -367,8 +340,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
int endDate = DateTool().dateToTimestamp(state.customEndTime.value, 1);
|
int endDate = DateTool().dateToTimestamp(state.customEndTime.value, 1);
|
||||||
//非永久 须有时限
|
//非永久 须有时限
|
||||||
if (state.isPermanent.value == false) {
|
if (state.isPermanent.value == false) {
|
||||||
if (startDate <
|
if (startDate < DateTool().dateToTimestamp(DateTool().getNowDateWithType(2), 1)) {
|
||||||
DateTool().dateToTimestamp(DateTool().getNowDateWithType(2), 1)) {
|
|
||||||
showToast('生效时间需晚于当前时间'.tr);
|
showToast('生效时间需晚于当前时间'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -382,8 +354,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
endDate = 0;
|
endDate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.pwdController.text.length < 6 ||
|
if (state.pwdController.text.length < 6 || state.pwdController.text.length > 9) {
|
||||||
state.pwdController.text.length > 9) {
|
|
||||||
showToast('请输入6-9位数字'.tr);
|
showToast('请输入6-9位数字'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -396,8 +367,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
|
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
|
||||||
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||||
|
|
||||||
final List<String>? privateKey =
|
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||||
await Storage.getStringList(saveBluePrivateKey);
|
|
||||||
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||||
|
|
||||||
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
||||||
@ -424,8 +394,7 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
final String getMobile = (await Storage.getMobile())!;
|
final String getMobile = (await Storage.getMobile())!;
|
||||||
ApmHelper.instance.trackEvent('add_password', {
|
ApmHelper.instance.trackEvent('add_password', {
|
||||||
'lock_name': BlueManage().connectDeviceName,
|
'lock_name': BlueManage().connectDeviceName,
|
||||||
'account':
|
'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
||||||
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
|
||||||
'date': DateTool().getNowDateWithType(1),
|
'date': DateTool().getNowDateWithType(1),
|
||||||
'add_password_result': '添加自定义密码超时',
|
'add_password_result': '添加自定义密码超时',
|
||||||
});
|
});
|
||||||
@ -439,17 +408,13 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
state.sureBtnState.value = 0;
|
state.sureBtnState.value = 0;
|
||||||
});
|
});
|
||||||
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
|
||||||
(BluetoothConnectionState deviceConnectionState) async {
|
|
||||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||||
final List<String>? signKey =
|
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
|
||||||
await Storage.getStringList(saveBlueSignKey);
|
|
||||||
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||||
|
|
||||||
final List<String>? privateKey =
|
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||||
await Storage.getStringList(saveBluePrivateKey);
|
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||||
final List<int> getPrivateKeyList =
|
|
||||||
changeStringListToIntList(privateKey!);
|
|
||||||
|
|
||||||
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
||||||
final List<int> getTokenList = changeStringListToIntList(token!);
|
final List<int> getTokenList = changeStringListToIntList(token!);
|
||||||
@ -469,13 +434,11 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
signKey: signKeyDataList,
|
signKey: signKeyDataList,
|
||||||
privateKey: getPrivateKeyList,
|
privateKey: getPrivateKeyList,
|
||||||
token: getTokenList);
|
token: getTokenList);
|
||||||
} else if (deviceConnectionState ==
|
} else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
|
||||||
BluetoothConnectionState.disconnected) {
|
|
||||||
final String getMobile = (await Storage.getMobile())!;
|
final String getMobile = (await Storage.getMobile())!;
|
||||||
ApmHelper.instance.trackEvent('add_password', {
|
ApmHelper.instance.trackEvent('add_password', {
|
||||||
'lock_name': BlueManage().connectDeviceName,
|
'lock_name': BlueManage().connectDeviceName,
|
||||||
'account':
|
'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
||||||
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
|
||||||
'date': DateTool().getNowDateWithType(1),
|
'date': DateTool().getNowDateWithType(1),
|
||||||
'add_password_result': '添加自定义密码断开',
|
'add_password_result': '添加自定义密码断开',
|
||||||
});
|
});
|
||||||
@ -517,17 +480,11 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
'\n' +
|
'\n' +
|
||||||
'有效期'.tr +
|
'有效期'.tr +
|
||||||
':${startDateStr.toLocal().toString().substring(0, 16)} -- ${endDateStr.toLocal().toString().substring(0, 16)}\n\n' +
|
':${startDateStr.toLocal().toString().substring(0, 16)} -- ${endDateStr.toLocal().toString().substring(0, 16)}\n\n' +
|
||||||
'这是单次密码,只能使用一次\n';
|
'${'这是单次密码,只能使用一次'.tr}\n';
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
//永久 2 从开始时间开始永久有效,必需在开始时间24小时内使用一次,否则将失效
|
//永久 2 从开始时间开始永久有效,必需在开始时间24小时内使用一次,否则将失效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '永久'.tr + '\n' + '\n注:\n' + '${'必需在开始时间24小时内使用一次,否则将失效'.tr}\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'永久'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n注:\n' +
|
|
||||||
'必需在开始时间24小时内使用一次,否则将失效\n';
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//限期 3 在开始和结束时间内有效,必需在开始时间24小时内使用一次,否则将失效
|
//限期 3 在开始和结束时间内有效,必需在开始时间24小时内使用一次,否则将失效
|
||||||
@ -540,15 +497,14 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
'有效期'.tr +
|
'有效期'.tr +
|
||||||
':${startDateStr.toLocal().toString().substring(0, 16)}-${endDateStr.toLocal().toString().substring(0, 16)}' +
|
':${startDateStr.toLocal().toString().substring(0, 16)}-${endDateStr.toLocal().toString().substring(0, 16)}' +
|
||||||
'\n' +
|
'\n' +
|
||||||
'\n注:\n' +
|
'\n${'注:'.tr}\n' +
|
||||||
'必需在开始时间24小时内使用一次,否则将失效\n';
|
'${'必需在开始时间24小时内使用一次,否则将失效'.tr}\n';
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
//自定义
|
//自定义
|
||||||
if (state.isPermanent.value == false) {
|
if (state.isPermanent.value == false) {
|
||||||
useDateStr = '类型'.tr +
|
useDateStr =
|
||||||
':' +
|
'类型'.tr + ':' + '自定义-限时\n${'有效期'.tr}:${state.customBeginTime.value} -- ${state.customEndTime.value}';
|
||||||
'自定义-限时\n${'有效期'.tr}:${state.customBeginTime.value} -- ${state.customEndTime.value}';
|
|
||||||
} else {
|
} else {
|
||||||
useDateStr = '类型:自定义-永久'.tr;
|
useDateStr = '类型:自定义-永久'.tr;
|
||||||
}
|
}
|
||||||
@ -559,171 +515,51 @@ class PasswordKeyPerpetualLogic extends BaseGetXController {
|
|||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
//周未循环 5 在周未开始和结束时间指定时间段内有效
|
//周未循环 5 在周未开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周末'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周末'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
//每日循环 6 每天开始和结束时间指定时间段内有效
|
//每日循环 6 每天开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '每日'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'每日'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
//工作日循环 7 工作日开始和结束时间指定的时间段内有效
|
//工作日循环 7 工作日开始和结束时间指定的时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '工作日'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'工作日'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
//周一循环 8 每周一开始和结束时间指定时间段内有效
|
//周一循环 8 每周一开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周一'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周一'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
//周二循环 9 每周二开始和结束时间指定时间段内有效
|
//周二循环 9 每周二开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周二'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周二'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
//周三循环 10 每周三开始和结束时间指定时间段内有效
|
//周三循环 10 每周三开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周三'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周三'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
//周四循环 11 每周四开始和结束时间指定时间段内有效
|
//周四循环 11 每周四开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周四'.tr + ' $starHour:00 -$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周四'.tr +
|
|
||||||
' $starHour:00 -$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
//周五循环 12 每周五开始和结束时间指定时间段内有效
|
//周五循环 12 每周五开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周五'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周五'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
//周六循环 13 每周六开始和结束时间指定时间段内有效
|
//周六循环 13 每周六开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周六'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周六'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
//周日循环 14 每周日开始和结束时间指定时间段内有效
|
//周日循环 14 每周日开始和结束时间指定时间段内有效
|
||||||
useDateStr = '\n' +
|
useDateStr = '\n' + '类型'.tr + ':' + '循环'.tr + '\n' + '\n' + '周日'.tr + ' $starHour:00-$endHour:00' + '\n';
|
||||||
'类型'.tr +
|
|
||||||
':' +
|
|
||||||
'循环'.tr +
|
|
||||||
'\n' +
|
|
||||||
'\n' +
|
|
||||||
'周日'.tr +
|
|
||||||
' $starHour:00-$endHour:00' +
|
|
||||||
'\n';
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
// return '您好,您的密码是'.tr + ':${state.itemData.value.keyboardPwd}\n$useDateStr\n${'密码名字'.tr}:${state.itemData.value.keyboardPwdName}';
|
|
||||||
return '您好' +
|
return '您好'.tr +
|
||||||
',\n您的开门密码是' +
|
',\n${'您的开门密码是'.tr}' +
|
||||||
':${state.getPwdStr.value}\n$useDateStr\n${'密码名字'.tr}:${state.pwdNameStr}\n\n开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标';
|
':${state.getPwdStr.value}\n$useDateStr\n${'密码名字'.tr}:${state.pwdNameStr}\n'
|
||||||
// switch (getPwdType) {
|
'\n${'开锁时,先激活锁键盘,再输入密码,以#号结束,#号键在键盘右下角,有可能是其他图标'.tr}';
|
||||||
// case 0:
|
|
||||||
// // 永久 从开始时间开始永久有效,必需在开始时间24小时内使用一次,否则将失效
|
|
||||||
// useDateStr = '类型'.tr + ':' + '永久';
|
|
||||||
// break;
|
|
||||||
// case 1:
|
|
||||||
// //限时 在开始和结束时间内有效,必需在开始时间24小时内使用一次,否则将失效
|
|
||||||
// useDateStr = '类型'.tr +
|
|
||||||
// ':' +
|
|
||||||
// '限时\n${'有效期'.tr}:${state.beginTime.value} -- ${state.endTime.value}';
|
|
||||||
// break;
|
|
||||||
// case 2:
|
|
||||||
// //单次 只能在开始时间后6小时内使用一次
|
|
||||||
// useDateStr = '类型'.tr +
|
|
||||||
// ':' +
|
|
||||||
// '单次\n${'有效期'.tr}:${state.beginTime.value} -- ${state.endTime.value}';
|
|
||||||
// break;
|
|
||||||
// case 3:
|
|
||||||
// //自定义
|
|
||||||
// if (state.isPermanent.value == false) {
|
|
||||||
// useDateStr = '类型'.tr +
|
|
||||||
// ':' +
|
|
||||||
// '自定义-限时\n${'有效期'.tr}:${state.customBeginTime.value} -- ${state.customEndTime.value}';
|
|
||||||
// } else {
|
|
||||||
// useDateStr = '类型:自定义-永久'.tr;
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// case 4:
|
|
||||||
// //周未循环 在周未开始和结束时间指定时间段内有效
|
|
||||||
// useDateStr = '类型'.tr +
|
|
||||||
// ':' +
|
|
||||||
// '循环\n${state.loopModeStr.value} ${state.loopEffectiveDate.value}:00-${state.loopFailureDate.value}';
|
|
||||||
// break;
|
|
||||||
// case 5:
|
|
||||||
// //删除 4 在锁上使用后会删除之前在锁上使用过的密码
|
|
||||||
// useDateStr = '类型:清空';
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// default:
|
|
||||||
// }
|
|
||||||
// return '${'您好,您的密码是'.tr}:${state.getPwdStr.value}\n$useDateStr\n${'密码名字'.tr}:${state.pwdNameStr}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String addSpaces(String input) {
|
String addSpaces(String input) {
|
||||||
|
|||||||
@ -36,13 +36,13 @@ class _LockListGroupViewState extends State<LockListGroupView> {
|
|||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
// Container(
|
||||||
color: widget.backgroundColor ?? Colors.white,
|
// color: widget.backgroundColor ?? Colors.white,
|
||||||
height: 80.h,
|
// height: 80.h,
|
||||||
child: Row(
|
// child: Row(
|
||||||
children: _buildExpandRowList(),
|
// children: _buildExpandRowList(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
ClipRect(
|
ClipRect(
|
||||||
child: AnimatedAlign(
|
child: AnimatedAlign(
|
||||||
heightFactor: _isExpanded ? 1.0 : 0.0,
|
heightFactor: _isExpanded ? 1.0 : 0.0,
|
||||||
|
|||||||
@ -32,10 +32,12 @@ class LockListLogic extends BaseGetXController {
|
|||||||
final ShowTipView showTipView = ShowTipView();
|
final ShowTipView showTipView = ShowTipView();
|
||||||
|
|
||||||
List<GroupList> get groupDataListFiltered {
|
List<GroupList> get groupDataListFiltered {
|
||||||
final List<GroupList> list = groupDataList.map((GroupList e) => e.copy()).toList();
|
final List<GroupList> list =
|
||||||
|
groupDataList.map((GroupList e) => e.copy()).toList();
|
||||||
if (state.searchStr.value != '' && state.showSearch.value) {
|
if (state.searchStr.value != '' && state.showSearch.value) {
|
||||||
list.forEach((GroupList element) {
|
list.forEach((GroupList element) {
|
||||||
element.lockList?.removeWhere((LockListInfoItemEntity element) => !(element.lockAlias?.contains(state.searchStr.value) ?? true));
|
element.lockList?.removeWhere((LockListInfoItemEntity element) =>
|
||||||
|
!(element.lockAlias?.contains(state.searchStr.value) ?? true));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (list.length > 0) {
|
if (list.length > 0) {
|
||||||
@ -44,7 +46,8 @@ class LockListLogic extends BaseGetXController {
|
|||||||
final lockList = element.lockList;
|
final lockList = element.lockList;
|
||||||
if (lockList != null && lockList.length > 0) {
|
if (lockList != null && lockList.length > 0) {
|
||||||
lockList.forEach((element) {
|
lockList.forEach((element) {
|
||||||
if (element.network?.peerId != null && element.network?.peerId != '') {
|
if (element.network?.peerId != null &&
|
||||||
|
element.network?.peerId != '') {
|
||||||
StartChartManage().lockListPeerId.add(element);
|
StartChartManage().lockListPeerId.add(element);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -65,9 +68,11 @@ class LockListLogic extends BaseGetXController {
|
|||||||
late StreamSubscription _setLockListInfoGroupEntity;
|
late StreamSubscription _setLockListInfoGroupEntity;
|
||||||
|
|
||||||
void _initReplySubscription() {
|
void _initReplySubscription() {
|
||||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
_replySubscription =
|
||||||
|
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||||
// 恢复出厂设置
|
// 恢复出厂设置
|
||||||
if ((reply is FactoryDataResetReply)) {
|
if ((reply is FactoryDataResetReply) &&
|
||||||
|
(state.ifCurrentScreen.value == true)) {
|
||||||
_replyFactoryDataResetKey(reply);
|
_replyFactoryDataResetKey(reply);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -88,18 +93,19 @@ class LockListLogic extends BaseGetXController {
|
|||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
//无权限
|
//无权限
|
||||||
final List<int> tokenData = reply.data.sublist(2, 6);
|
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
||||||
final List<String> saveStrList = changeIntListToStringList(tokenData);
|
final List<int> getTokenList = changeStringListToIntList(token!);
|
||||||
Storage.setStringList(saveBlueToken, saveStrList);
|
|
||||||
IoSenderManage.senderFactoryDataReset(
|
IoSenderManage.senderFactoryDataReset(
|
||||||
lockID: BlueManage().connectDeviceName,
|
lockID: BlueManage().connectDeviceName,
|
||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
keyID: '1',
|
keyID: '1',
|
||||||
needAuthor: 1,
|
needAuthor: 1,
|
||||||
publicKey: state.publicKey,
|
publicKey:
|
||||||
privateKey: state.privateKey,
|
state.lockListInfoItemEntity.bluetooth!.publicKey!.cast<int>(),
|
||||||
token: tokenData,
|
privateKey:
|
||||||
);
|
state.lockListInfoItemEntity.bluetooth!.privateKey!.cast<int>(),
|
||||||
|
token: getTokenList);
|
||||||
break;
|
break;
|
||||||
case 0x07:
|
case 0x07:
|
||||||
//无权限
|
//无权限
|
||||||
@ -140,7 +146,8 @@ class LockListLogic extends BaseGetXController {
|
|||||||
keyInfo.keyType == XSConstantMacro.keyTypeLong ||
|
keyInfo.keyType == XSConstantMacro.keyTypeLong ||
|
||||||
keyInfo.keyType == XSConstantMacro.keyTypeLoop) {
|
keyInfo.keyType == XSConstantMacro.keyTypeLoop) {
|
||||||
// 当是正常使用跟待接收状态的时候
|
// 当是正常使用跟待接收状态的时候
|
||||||
if (keyInfo.keyStatus == XSConstantMacro.keyStatusNormalUse || keyInfo.keyStatus == XSConstantMacro.keyStatusWaitReceive) {
|
if (keyInfo.keyStatus == XSConstantMacro.keyStatusNormalUse ||
|
||||||
|
keyInfo.keyStatus == XSConstantMacro.keyStatusWaitReceive) {
|
||||||
return "${"余".tr}${DateTool().compareTimeGetDaysFromNow(keyInfo.endDate!)}${"天".tr}";
|
return "${"余".tr}${DateTool().compareTimeGetDaysFromNow(keyInfo.endDate!)}${"天".tr}";
|
||||||
} else {
|
} else {
|
||||||
return XSConstantMacro.getKeyStatusStr(keyInfo.keyStatus!);
|
return XSConstantMacro.getKeyStatusStr(keyInfo.keyStatus!);
|
||||||
@ -153,7 +160,11 @@ class LockListLogic extends BaseGetXController {
|
|||||||
|
|
||||||
//判断是否要显示提示
|
//判断是否要显示提示
|
||||||
bool getShowType(LockListInfoItemEntity keyInfo) {
|
bool getShowType(LockListInfoItemEntity keyInfo) {
|
||||||
final List<int> keyTypes = <int>[XSConstantMacro.keyTypeTime, XSConstantMacro.keyTypeOnce, XSConstantMacro.keyTypeLoop];
|
final List<int> keyTypes = <int>[
|
||||||
|
XSConstantMacro.keyTypeTime,
|
||||||
|
XSConstantMacro.keyTypeOnce,
|
||||||
|
XSConstantMacro.keyTypeLoop
|
||||||
|
];
|
||||||
final List<int> keyStatus = <int>[
|
final List<int> keyStatus = <int>[
|
||||||
XSConstantMacro.keyStatusWaitIneffective,
|
XSConstantMacro.keyStatusWaitIneffective,
|
||||||
XSConstantMacro.keyStatusFrozen,
|
XSConstantMacro.keyStatusFrozen,
|
||||||
@ -161,30 +172,36 @@ class LockListLogic extends BaseGetXController {
|
|||||||
];
|
];
|
||||||
|
|
||||||
//新增以上组合未包含--永久&&冻结状态 显示
|
//新增以上组合未包含--永久&&冻结状态 显示
|
||||||
final bool isLongFrozenStatus = keyInfo.keyType == XSConstantMacro.keyTypeLong && keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen;
|
final bool isLongFrozenStatus =
|
||||||
final DateTime endDate = DateTime.fromMillisecondsSinceEpoch(keyInfo.endDate ?? 0);
|
keyInfo.keyType == XSConstantMacro.keyTypeLong &&
|
||||||
|
keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen;
|
||||||
|
final DateTime endDate =
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(keyInfo.endDate ?? 0);
|
||||||
final DateTime now = DateTime.now();
|
final DateTime now = DateTime.now();
|
||||||
final bool isKeyType = keyTypes.contains(keyInfo.keyType);
|
final bool isKeyType = keyTypes.contains(keyInfo.keyType);
|
||||||
final bool isKeyStatus = keyStatus.contains(keyInfo.keyStatus);
|
final bool isKeyStatus = keyStatus.contains(keyInfo.keyStatus);
|
||||||
final Duration difference = endDate.difference(now);
|
final Duration difference = endDate.difference(now);
|
||||||
final bool isExpirationSoon = isKeyType && difference.inDays <= 15;
|
final bool isExpirationSoon = isKeyType && difference.inDays <= 15;
|
||||||
final bool isShow = isKeyType && isKeyStatus || isExpirationSoon || isLongFrozenStatus;
|
final bool isShow =
|
||||||
|
isKeyType && isKeyStatus || isExpirationSoon || isLongFrozenStatus;
|
||||||
return isShow;
|
return isShow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 以下为删除逻辑
|
/// 以下为删除逻辑
|
||||||
void deleyLockLogicOfRoles(LockListInfoItemEntity keyInfo) {
|
void deleyLockLogicOfRoles() {
|
||||||
if (state.lockListInfoItemEntity.value.isLockOwner == 1) {
|
if (state.lockListInfoItemEntity.isLockOwner == 1) {
|
||||||
// 超级管理员必须通过连接蓝牙删除
|
// 超级管理员必须通过连接蓝牙删除
|
||||||
showTipView.showIosTipWithContentDialog('删除锁后,所有信息都会一起删除,确定删除锁吗?'.tr, () {
|
showTipView.showIosTipWithContentDialog('删除锁后,所有信息都会一起删除,确定删除锁吗?'.tr, () {
|
||||||
// 删除锁
|
// 删除锁
|
||||||
AppLog.log('调用了删除锁');
|
AppLog.log('调用了删除锁');
|
||||||
showTipView.resetGetController();
|
showTipView.resetGetController();
|
||||||
showTipView.showTFViewAlertDialog(state.passwordTF, '请输入登录密码'.tr, '请输入登录密码'.tr, () => checkLoginPassword(keyInfo));
|
showTipView.showTFViewAlertDialog(
|
||||||
|
state.passwordTF, '请输入登录密码'.tr, '请输入登录密码'.tr, checkLoginPassword);
|
||||||
});
|
});
|
||||||
} else if (state.lockListInfoItemEntity.value.keyRight == 1) {
|
} else if (state.lockListInfoItemEntity.keyRight == 1) {
|
||||||
// 授权管理员弹框提示
|
// 授权管理员弹框提示
|
||||||
showTipView.showDeleteAdministratorIsHaveAllDataDialog('同时删除其发送的所有钥匙,钥匙删除后不能恢复'.tr, (bool a) {
|
showTipView.showDeleteAdministratorIsHaveAllDataDialog(
|
||||||
|
'同时删除其发送的所有钥匙,钥匙删除后不能恢复'.tr, (bool a) {
|
||||||
// 授权管理员删除
|
// 授权管理员删除
|
||||||
state.deleteAdministratorIsHaveAllData.value = a;
|
state.deleteAdministratorIsHaveAllData.value = a;
|
||||||
deletKeyData();
|
deletKeyData();
|
||||||
@ -196,20 +213,20 @@ class LockListLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询账户密码
|
// 查询账户密码
|
||||||
Future<void> checkLoginPassword(LockListInfoItemEntity keyInfo) async {
|
Future<void> checkLoginPassword() async {
|
||||||
final LockListInfoEntity entity = await ApiRepository.to.checkLoginPassword(
|
final LockListInfoEntity entity = await ApiRepository.to.checkLoginPassword(
|
||||||
password: state.passwordTF.text,
|
password: state.passwordTF.text,
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
Get.back();
|
Get.back();
|
||||||
factoryDataResetAction(keyInfo);
|
factoryDataResetAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当是锁拥有者的时候,删除锁
|
// 当是锁拥有者的时候,删除锁
|
||||||
Future<void> deletLockInfoData() async {
|
Future<void> deletLockInfoData() async {
|
||||||
final LockListInfoEntity entity = await ApiRepository.to.deletOwnerLockData(
|
final LockListInfoEntity entity = await ApiRepository.to.deletOwnerLockData(
|
||||||
lockId: state.lockListInfoItemEntity.value.lockId!,
|
lockId: state.lockListInfoItemEntity.lockId!,
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
BlueManage().connectDeviceMacAddress = '';
|
BlueManage().connectDeviceMacAddress = '';
|
||||||
@ -222,9 +239,10 @@ class LockListLogic extends BaseGetXController {
|
|||||||
// 普通用户或者授权管理员删除钥匙
|
// 普通用户或者授权管理员删除钥匙
|
||||||
Future<void> deletKeyData() async {
|
Future<void> deletKeyData() async {
|
||||||
final LockListInfoEntity entity = await ApiRepository.to.deletOwnerKeyData(
|
final LockListInfoEntity entity = await ApiRepository.to.deletOwnerKeyData(
|
||||||
lockId: state.lockListInfoItemEntity.value.lockId.toString(),
|
lockId: state.lockListInfoItemEntity.lockId.toString(),
|
||||||
keyId: state.lockListInfoItemEntity.value.keyId.toString(),
|
keyId: state.lockListInfoItemEntity.keyId.toString(),
|
||||||
includeUnderlings: state.deleteAdministratorIsHaveAllData.value == true ? 1 : 0);
|
includeUnderlings:
|
||||||
|
state.deleteAdministratorIsHaveAllData.value == true ? 1 : 0);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
BlueManage().connectDeviceMacAddress = '';
|
BlueManage().connectDeviceMacAddress = '';
|
||||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
@ -234,7 +252,7 @@ class LockListLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 恢复出厂设置
|
// 恢复出厂设置
|
||||||
Future<void> factoryDataResetAction(LockListInfoItemEntity keyInfo) async {
|
Future<void> factoryDataResetAction() async {
|
||||||
showEasyLoading();
|
showEasyLoading();
|
||||||
showBlueConnetctToastTimer(
|
showBlueConnetctToastTimer(
|
||||||
isShowBlueConnetctToast: false,
|
isShowBlueConnetctToast: false,
|
||||||
@ -242,23 +260,31 @@ class LockListLogic extends BaseGetXController {
|
|||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
showDeletAlertTipDialog();
|
showDeletAlertTipDialog();
|
||||||
});
|
});
|
||||||
BlueManage().blueSendData(state.lockListInfoItemEntity.value.lockName!, (BluetoothConnectionState connectionState) async {
|
BlueManage().blueSendData(state.lockListInfoItemEntity.lockName!,
|
||||||
|
(BluetoothConnectionState connectionState) async {
|
||||||
if (connectionState == BluetoothConnectionState.connected) {
|
if (connectionState == BluetoothConnectionState.connected) {
|
||||||
final List<int> publicKeyData = state.lockListInfoItemEntity.value.bluetooth!.publicKey!.cast<int>();
|
final List<int> publicKeyData =
|
||||||
final List<String> saveStrList = changeIntListToStringList(publicKeyData);
|
state.lockListInfoItemEntity.bluetooth!.publicKey!.cast<int>();
|
||||||
|
final List<String> saveStrList =
|
||||||
|
changeIntListToStringList(publicKeyData);
|
||||||
await Storage.setStringList(saveBluePublicKey, saveStrList);
|
await Storage.setStringList(saveBluePublicKey, saveStrList);
|
||||||
|
|
||||||
// 私钥
|
// 私钥
|
||||||
final List<int> privateKeyData = state.lockListInfoItemEntity.value.bluetooth!.privateKey!.cast<int>();
|
final List<int> privateKeyData =
|
||||||
final List<String> savePrivateKeyList = changeIntListToStringList(privateKeyData);
|
state.lockListInfoItemEntity.bluetooth!.privateKey!.cast<int>();
|
||||||
|
final List<String> savePrivateKeyList =
|
||||||
|
changeIntListToStringList(privateKeyData);
|
||||||
await Storage.setStringList(saveBluePrivateKey, savePrivateKeyList);
|
await Storage.setStringList(saveBluePrivateKey, savePrivateKeyList);
|
||||||
|
|
||||||
// signKey
|
// signKey
|
||||||
final List<int> signKeyData = state.lockListInfoItemEntity.value.bluetooth!.signKey!.cast<int>();
|
final List<int> signKeyData =
|
||||||
final List<String> saveSignKeyList = changeIntListToStringList(signKeyData);
|
state.lockListInfoItemEntity.bluetooth!.signKey!.cast<int>();
|
||||||
|
final List<String> saveSignKeyList =
|
||||||
|
changeIntListToStringList(signKeyData);
|
||||||
await Storage.setStringList(saveBlueSignKey, saveSignKeyList);
|
await Storage.setStringList(saveBlueSignKey, saveSignKeyList);
|
||||||
|
|
||||||
final List<String> saveTokenList = changeIntListToStringList(<int>[0, 0, 0, 0]);
|
final List<String> saveTokenList =
|
||||||
|
changeIntListToStringList(<int>[0, 0, 0, 0]);
|
||||||
await Storage.setStringList(saveBlueToken, saveTokenList);
|
await Storage.setStringList(saveBlueToken, saveTokenList);
|
||||||
|
|
||||||
IoSenderManage.senderFactoryDataReset(
|
IoSenderManage.senderFactoryDataReset(
|
||||||
@ -266,13 +292,11 @@ class LockListLogic extends BaseGetXController {
|
|||||||
userID: await Storage.getUid(),
|
userID: await Storage.getUid(),
|
||||||
keyID: '1',
|
keyID: '1',
|
||||||
needAuthor: 1,
|
needAuthor: 1,
|
||||||
publicKey: keyInfo.bluetooth?.publicKey ?? [],
|
publicKey:
|
||||||
privateKey: keyInfo.bluetooth?.privateKey ?? [],
|
state.lockListInfoItemEntity.bluetooth!.publicKey!.cast<int>(),
|
||||||
|
privateKey:
|
||||||
|
state.lockListInfoItemEntity.bluetooth!.privateKey!.cast<int>(),
|
||||||
token: <int>[0, 0, 0, 0]);
|
token: <int>[0, 0, 0, 0]);
|
||||||
state.publicKey.value = keyInfo.bluetooth?.publicKey ?? [];
|
|
||||||
state.privateKey.value = keyInfo.bluetooth?.privateKey ?? [];
|
|
||||||
state.publicKey.refresh();
|
|
||||||
state.privateKey.refresh();
|
|
||||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
cancelBlueConnetctToastTimer();
|
cancelBlueConnetctToastTimer();
|
||||||
@ -329,7 +353,9 @@ class LockListLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _initEventHandler() {
|
void _initEventHandler() {
|
||||||
_setLockListInfoGroupEntity = eventBus.on<SetLockListInfoGroupEntity>().listen((SetLockListInfoGroupEntity event) async {
|
_setLockListInfoGroupEntity = eventBus
|
||||||
|
.on<SetLockListInfoGroupEntity>()
|
||||||
|
.listen((SetLockListInfoGroupEntity event) async {
|
||||||
setLockListInfoGroupEntity(event.lockListInfoGroupEntity);
|
setLockListInfoGroupEntity(event.lockListInfoGroupEntity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:star_lock/app_settings/app_settings.dart';
|
import 'package:star_lock/flavors.dart';
|
||||||
import 'package:star_lock/main/lockMian/lockList/lockList_state.dart';
|
import 'package:star_lock/main/lockMian/lockList/lockList_state.dart';
|
||||||
|
|
||||||
import '../../../appRouters.dart';
|
import '../../../appRouters.dart';
|
||||||
@ -37,8 +38,47 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Obx(
|
return Obx(
|
||||||
() => Scaffold(
|
() => Scaffold(
|
||||||
body: ListView.separated(
|
body: SafeArea(
|
||||||
itemCount: logic.groupDataList.length,
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Image.asset('images/icon_main_drlock_1024.png', width: 68.w, height: 68.w),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
F.title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 28.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
//实现回调函数
|
||||||
|
Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
Routers.selectLockTypePage,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.add_circle_outline_rounded,
|
||||||
|
size: 48.sp,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.separated(
|
||||||
|
itemCount: logic.groupDataListFiltered.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final GroupList itemData = logic.groupDataListFiltered[index];
|
final GroupList itemData = logic.groupDataListFiltered[index];
|
||||||
return _buildLockExpandedList(context, index, itemData, key: ValueKey(itemData.groupId));
|
return _buildLockExpandedList(context, index, itemData, key: ValueKey(itemData.groupId));
|
||||||
@ -53,6 +93,10 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +135,8 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SlidableAction(
|
SlidableAction(
|
||||||
onPressed: (BuildContext context) {
|
onPressed: (BuildContext context) {
|
||||||
state.publicKey.value = keyInfo.bluetooth?.publicKey ?? [];
|
state.lockListInfoItemEntity = keyInfo;
|
||||||
state.privateKey.value = keyInfo.bluetooth?.privateKey ?? [];
|
logic.deleyLockLogicOfRoles();
|
||||||
state.lockListInfoItemEntity.value = keyInfo;
|
|
||||||
state.lockListInfoItemEntity.refresh();
|
|
||||||
AppLog.log('msg=================:${state.lockListInfoItemEntity.value}');
|
|
||||||
logic.deleyLockLogicOfRoles(keyInfo);
|
|
||||||
},
|
},
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
@ -106,7 +146,8 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: lockInfoListItem(keyInfo, isLast, () {
|
child: lockInfoListItem(keyInfo, isLast, () {
|
||||||
if ((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
|
if ((keyInfo.keyType == XSConstantMacro.keyTypeTime ||
|
||||||
|
keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
|
||||||
(keyInfo.keyStatus == XSConstantMacro.keyStatusWaitIneffective)) {
|
(keyInfo.keyStatus == XSConstantMacro.keyStatusWaitIneffective)) {
|
||||||
logic.showToast('您的钥匙未生效'.tr);
|
logic.showToast('您的钥匙未生效'.tr);
|
||||||
return;
|
return;
|
||||||
@ -118,7 +159,8 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
logic.showToast('您的钥匙已冻结'.tr);
|
logic.showToast('您的钥匙已冻结'.tr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
|
if ((keyInfo.keyType == XSConstantMacro.keyTypeTime ||
|
||||||
|
keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
|
||||||
(keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) {
|
(keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) {
|
||||||
logic.showToast('您的钥匙已过期'.tr);
|
logic.showToast('您的钥匙已过期'.tr);
|
||||||
return;
|
return;
|
||||||
@ -139,13 +181,16 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
onTap: action,
|
onTap: action,
|
||||||
child: Container(
|
child: Container(
|
||||||
// height: 122.h,
|
// height: 122.h,
|
||||||
margin: isLast ? EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w, bottom: 20.w) : EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w),
|
margin: isLast
|
||||||
|
? EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w, bottom: 20.w)
|
||||||
|
: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: (((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
|
color: (((keyInfo.keyType == XSConstantMacro.keyTypeTime || keyInfo.keyType == XSConstantMacro.keyTypeLoop) &&
|
||||||
(keyInfo.keyStatus == XSConstantMacro.keyStatusWaitIneffective ||
|
(keyInfo.keyStatus == XSConstantMacro.keyStatusWaitIneffective ||
|
||||||
keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen ||
|
keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen ||
|
||||||
keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) ||
|
keyInfo.keyStatus == XSConstantMacro.keyStatusExpired)) ||
|
||||||
(keyInfo.keyType == XSConstantMacro.keyTypeLong && keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen))
|
(keyInfo.keyType == XSConstantMacro.keyTypeLong &&
|
||||||
|
keyInfo.keyStatus == XSConstantMacro.keyStatusFrozen))
|
||||||
? AppColors.greyBackgroundColor
|
? AppColors.greyBackgroundColor
|
||||||
: Colors.white,
|
: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(20.w),
|
borderRadius: BorderRadius.circular(20.w),
|
||||||
@ -169,7 +214,9 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24.sp,
|
fontSize: 24.sp,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: keyInfo.passageMode == 1 ? AppColors.openPassageModeColor : AppColors.darkGrayTextColor),
|
color: keyInfo.passageMode == 1
|
||||||
|
? AppColors.openPassageModeColor
|
||||||
|
: AppColors.darkGrayTextColor),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -226,7 +273,9 @@ class _LockListPageState extends State<LockListPage> with RouteAware {
|
|||||||
padding: EdgeInsets.only(right: 5.w, left: 5.w),
|
padding: EdgeInsets.only(right: 5.w, left: 5.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(5.w),
|
borderRadius: BorderRadius.circular(5.w),
|
||||||
color: DateTool().compareTimeIsOvertime(keyInfo.endDate!) ? AppColors.listTimeYellowColor : AppColors.mainColor,
|
color: DateTool().compareTimeIsOvertime(keyInfo.endDate!)
|
||||||
|
? AppColors.listTimeYellowColor
|
||||||
|
: AppColors.mainColor,
|
||||||
),
|
),
|
||||||
child: Text(logic.getKeyEffective(keyInfo), style: TextStyle(fontSize: 18.sp, color: Colors.white)
|
child: Text(logic.getKeyEffective(keyInfo), style: TextStyle(fontSize: 18.sp, color: Colors.white)
|
||||||
// child: Text(logic.compareTimeIsOvertime(keyInfo.endDate!) ? "已过期" : "余${logic.compareTimeGetDaysFromNow(keyInfo.endDate!)}天", style: TextStyle(fontSize: 18.sp, color: Colors.white)
|
// child: Text(logic.compareTimeIsOvertime(keyInfo.endDate!) ? "已过期" : "余${logic.compareTimeGetDaysFromNow(keyInfo.endDate!)}天", style: TextStyle(fontSize: 18.sp, color: Colors.white)
|
||||||
|
|||||||
@ -7,14 +7,11 @@ import '../entity/lockListInfo_entity.dart';
|
|||||||
class LockListState{
|
class LockListState{
|
||||||
|
|
||||||
RxBool itemStatusIsEable = false.obs; // 列表里面item是否能点击
|
RxBool itemStatusIsEable = false.obs; // 列表里面item是否能点击
|
||||||
// 修改后
|
LockListInfoItemEntity lockListInfoItemEntity = LockListInfoItemEntity(); // 当前选中要删除的item
|
||||||
Rx<LockListInfoItemEntity> lockListInfoItemEntity = LockListInfoItemEntity().obs; // 当前选中要删除的item
|
|
||||||
TextEditingController passwordTF = TextEditingController();
|
TextEditingController passwordTF = TextEditingController();
|
||||||
RxBool deleteAdministratorIsHaveAllData = false.obs; // 删除管理员是否有所有数据
|
RxBool deleteAdministratorIsHaveAllData = false.obs; // 删除管理员是否有所有数据
|
||||||
RxBool ifCurrentScreen = true.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
RxBool ifCurrentScreen = true.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
||||||
RxBool showSearch = false.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
RxBool showSearch = false.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
||||||
RxString searchStr = ''.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
RxString searchStr = ''.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
||||||
RxList<int> publicKey=<int>[].obs;
|
|
||||||
RxList<int> privateKey=<int>[].obs;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -192,9 +192,8 @@ class _LockListXHJPageState extends State<LockListXHJPage> with RouteAware {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SlidableAction(
|
SlidableAction(
|
||||||
onPressed: (BuildContext context) {
|
onPressed: (BuildContext context) {
|
||||||
state.lockListInfoItemEntity.value = keyInfo;
|
state.lockListInfoItemEntity = keyInfo;
|
||||||
state.lockListInfoItemEntity.refresh();
|
logic.deleyLockLogicOfRoles();
|
||||||
logic.deleyLockLogicOfRoles(keyInfo);
|
|
||||||
},
|
},
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
|
|||||||
@ -23,8 +23,11 @@ import 'package:star_lock/tools/submitBtn.dart';
|
|||||||
import '../../../appRouters.dart';
|
import '../../../appRouters.dart';
|
||||||
import '../../../baseWidget.dart';
|
import '../../../baseWidget.dart';
|
||||||
import '../../../flavors.dart';
|
import '../../../flavors.dart';
|
||||||
|
import '../../../mine/addLock/selectLockType/selectLockType_logic.dart';
|
||||||
|
import '../../../mine/message/messageList/messageList_page.dart';
|
||||||
import '../../../mine/mine/starLockMine_page.dart';
|
import '../../../mine/mine/starLockMine_page.dart';
|
||||||
import '../../../tools/EasyRefreshTool.dart';
|
import '../../../tools/EasyRefreshTool.dart';
|
||||||
|
import '../../../tools/commonDataManage.dart';
|
||||||
import '../../../tools/eventBusEventManage.dart';
|
import '../../../tools/eventBusEventManage.dart';
|
||||||
import '../../../tools/storage.dart';
|
import '../../../tools/storage.dart';
|
||||||
import '../../../tools/titleAppBar.dart';
|
import '../../../tools/titleAppBar.dart';
|
||||||
@ -34,8 +37,7 @@ import '../lockList/lockList_page.dart';
|
|||||||
import 'lockMain_logic.dart';
|
import 'lockMain_logic.dart';
|
||||||
|
|
||||||
class StarLockMainPage extends StatefulWidget {
|
class StarLockMainPage extends StatefulWidget {
|
||||||
StarLockMainPage({Key? key, this.showAppBar = true, this.showDrawer = true})
|
StarLockMainPage({Key? key, this.showAppBar = true, this.showDrawer = true}) : super(key: key);
|
||||||
: super(key: key);
|
|
||||||
bool showAppBar;
|
bool showAppBar;
|
||||||
bool showDrawer;
|
bool showDrawer;
|
||||||
|
|
||||||
@ -48,16 +50,15 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
final LockMainLogic logic = Get.put(LockMainLogic());
|
final LockMainLogic logic = Get.put(LockMainLogic());
|
||||||
final LockMainState state = Get.find<LockMainLogic>().state;
|
final LockMainState state = Get.find<LockMainLogic>().state;
|
||||||
|
|
||||||
Future<void> getHttpData(
|
final SelectLockTypeLogic logicType = Get.put(SelectLockTypeLogic());
|
||||||
{bool clearScanDevices = false, bool isUnShowLoading = false}) async {
|
|
||||||
LockListInfoGroupEntity? lockListInfoGroupEntity =
|
Future<void> getHttpData({bool clearScanDevices = false, bool isUnShowLoading = false}) async {
|
||||||
await Storage.getLockMainListData();
|
LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
|
||||||
if (lockListInfoGroupEntity != null) {
|
if (lockListInfoGroupEntity != null) {
|
||||||
await logic.loadMainDataLogic(lockListInfoGroupEntity);
|
await logic.loadMainDataLogic(lockListInfoGroupEntity);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
lockListInfoGroupEntity =
|
lockListInfoGroupEntity = (await logic.getStarLockInfo(isUnShowLoading: isUnShowLoading)).data;
|
||||||
(await logic.getStarLockInfo(isUnShowLoading: isUnShowLoading)).data;
|
|
||||||
if (lockListInfoGroupEntity != null) {
|
if (lockListInfoGroupEntity != null) {
|
||||||
await logic.loadMainDataLogic(lockListInfoGroupEntity);
|
await logic.loadMainDataLogic(lockListInfoGroupEntity);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -89,7 +90,8 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetBuilder<LockMainLogic>(builder: (LockMainLogic logic) {
|
return GetBuilder<LockMainLogic>(builder: (LockMainLogic logic) {
|
||||||
Widget child = EasyRefreshTool(
|
Widget child = Obx(
|
||||||
|
() => EasyRefreshTool(
|
||||||
onRefresh: () {
|
onRefresh: () {
|
||||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
// 更新状态的代码
|
// 更新状态的代码
|
||||||
@ -98,37 +100,44 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
// child: getDataReturnUI(state.dataLength.value));
|
// child: getDataReturnUI(state.dataLength.value));
|
||||||
child: getDataReturnUI(state.dataLength.value));
|
child: getDataReturnUI(state.dataLength.value),
|
||||||
|
),
|
||||||
|
);
|
||||||
if (widget.showAppBar || widget.showDrawer) {
|
if (widget.showAppBar || widget.showDrawer) {
|
||||||
child = Scaffold(
|
child = Scaffold(
|
||||||
backgroundColor: const Color(0xFFF5F5F5),
|
backgroundColor: Colors.white,
|
||||||
appBar: widget.showAppBar
|
|
||||||
? TitleAppBar(
|
|
||||||
barTitle: F.navTitle,
|
|
||||||
haveBack: false,
|
|
||||||
haveOtherLeftWidget: true,
|
|
||||||
leftWidget: Builder(
|
|
||||||
builder: (BuildContext context) => IconButton(
|
|
||||||
icon: Image.asset(
|
|
||||||
'images/main/mainLeft_menu_icon.png',
|
|
||||||
color: Colors.white,
|
|
||||||
width: 44.w,
|
|
||||||
height: 44.w,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
Scaffold.of(context).openDrawer();
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
backgroundColor: AppColors.mainColor,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
drawer: widget.showDrawer
|
|
||||||
? Drawer(
|
|
||||||
width: 1.sw / 3 * 2,
|
|
||||||
child: const StarLockMinePage(),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
body: child,
|
body: child,
|
||||||
|
bottomNavigationBar: Obx(
|
||||||
|
() => BottomNavigationBar(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
items: <BottomNavigationBarItem>[
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: ImageIcon(
|
||||||
|
AssetImage(state.selectedIndex.value == 0
|
||||||
|
? 'images/icon_device_selected'
|
||||||
|
'.png'
|
||||||
|
: 'images/icon_device_not_selected.png'),
|
||||||
|
), // 使用本地图片
|
||||||
|
label: '设备',
|
||||||
|
),
|
||||||
|
const BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.notifications),
|
||||||
|
label: '消息',
|
||||||
|
),
|
||||||
|
const BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.person),
|
||||||
|
label: '我的',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onTap: (index) {
|
||||||
|
state.selectedIndex.value = index;
|
||||||
|
},
|
||||||
|
currentIndex: state.selectedIndex.value,
|
||||||
|
selectedItemColor: AppColors.mainColor,
|
||||||
|
unselectedItemColor: Colors.grey,
|
||||||
|
showUnselectedLabels: true, // 显示未选中项的标签
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
child = F.sw(
|
child = F.sw(
|
||||||
@ -149,41 +158,52 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
Widget getDataReturnUI(int type) {
|
Widget getDataReturnUI(int type) {
|
||||||
Widget returnWidget;
|
Widget returnWidget;
|
||||||
|
|
||||||
|
if (state.selectedIndex.value == 0) {
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
type = F.sw(skyCall: () => 1, xhjCall: () => 2);
|
type = F.sw(skyCall: () => 1, xhjCall: () => 2);
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
// 显示无数据模式
|
// 显示无数据模式
|
||||||
returnWidget = unHaveData();
|
returnWidget = MainBg(child: unHaveData());
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// 只有一条数据
|
// 只有一条数据
|
||||||
Storage.setBool(ifIsDemoModeOrNot, false);
|
Storage.setBool(ifIsDemoModeOrNot, false);
|
||||||
returnWidget = LockDetailPage(
|
returnWidget = MainBg(child: LockDetailPage(
|
||||||
isOnlyOneData: true,
|
isOnlyOneData: true,
|
||||||
lockListInfoItemEntity:
|
lockListInfoItemEntity: state.lockListInfoGroupEntity.value.groupList![0].lockList![0]));
|
||||||
state.lockListInfoGroupEntity.value.groupList![0].lockList![0]);
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// 有多条数据
|
// 有多条数据
|
||||||
Storage.setBool(ifIsDemoModeOrNot, false);
|
Storage.setBool(ifIsDemoModeOrNot, false);
|
||||||
returnWidget = F.sw(
|
returnWidget = F.sw(
|
||||||
skyCall: () => LockListPage(
|
skyCall: () => MainBg(child: LockListPage(lockListInfoGroupEntity: state.lockListInfoGroupEntity.value)),
|
||||||
lockListInfoGroupEntity: state.lockListInfoGroupEntity.value),
|
xhjCall: () => MainBg(child: LockListXHJPage(lockListInfoGroupEntity: state.lockListInfoGroupEntity.value)));
|
||||||
xhjCall: () => LockListXHJPage(
|
|
||||||
lockListInfoGroupEntity: state.lockListInfoGroupEntity.value));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
returnWidget = NoData();
|
returnWidget = MainBg(child: NoData());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (state.selectedIndex.value == 1) {
|
||||||
|
returnWidget = MainBg(child: MessageListPage());
|
||||||
|
} else {
|
||||||
|
returnWidget = MainBg(child: StarLockMinePage());
|
||||||
|
}
|
||||||
return returnWidget;
|
return returnWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
//鑫泓佳背景
|
//背景
|
||||||
Widget XHJBg({required Widget child}) {
|
Widget MainBg({required Widget child}) {
|
||||||
return Container();
|
return Container(
|
||||||
|
child: child,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('images/lockMain_bg.jpg'),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget unHaveData() {
|
Widget unHaveData() {
|
||||||
@ -192,6 +212,48 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
Column(
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Image.asset('images/icon_main_drlock_1024.png', width: 68.w, height: 68.w),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
F.title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 28.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
//实现回调函数
|
||||||
|
// Navigator.pushNamed(
|
||||||
|
// context,
|
||||||
|
// Routers.selectLockTypePage,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// 跳转到扫描设备页
|
||||||
|
CommonDataManage().seletLockType = 0;
|
||||||
|
logicType.getNearByLimits();
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.add_circle_outline_rounded,
|
||||||
|
size: 48.sp,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 160.h,
|
height: 160.h,
|
||||||
),
|
),
|
||||||
@ -211,10 +273,14 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
//实现回调函数
|
//实现回调函数
|
||||||
Navigator.pushNamed(
|
// Navigator.pushNamed(
|
||||||
context,
|
// context,
|
||||||
Routers.selectLockTypePage,
|
// Routers.selectLockTypePage,
|
||||||
);
|
// );
|
||||||
|
|
||||||
|
// 跳转到扫描设备页
|
||||||
|
CommonDataManage().seletLockType = 0;
|
||||||
|
logicType.getNearByLimits();
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
@ -288,13 +354,9 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
late StreamSubscription _teamEvent;
|
late StreamSubscription _teamEvent;
|
||||||
|
|
||||||
void _initLoadDataAction() {
|
void _initLoadDataAction() {
|
||||||
_teamEvent = eventBus
|
_teamEvent = eventBus.on<RefreshLockListInfoDataEvent>().listen((RefreshLockListInfoDataEvent event) {
|
||||||
.on<RefreshLockListInfoDataEvent>()
|
|
||||||
.listen((RefreshLockListInfoDataEvent event) {
|
|
||||||
logic.pageNo = 1;
|
logic.pageNo = 1;
|
||||||
getHttpData(
|
getHttpData(clearScanDevices: event.clearScanDevices, isUnShowLoading: event.isUnShowLoading);
|
||||||
clearScanDevices: event.clearScanDevices,
|
|
||||||
isUnShowLoading: event.isUnShowLoading);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,8 +366,7 @@ class _StarLockMainPageState extends State<StarLockMainPage>
|
|||||||
ByteData byteData = await rootBundle.load(assetPath);
|
ByteData byteData = await rootBundle.load(assetPath);
|
||||||
|
|
||||||
// 将 ByteData 转换为 Uint8List
|
// 将 ByteData 转换为 Uint8List
|
||||||
Uint8List uint8List =
|
Uint8List uint8List = Uint8List.sublistView(byteData); //byteData.buffer.asUint8List();
|
||||||
Uint8List.sublistView(byteData); //byteData.buffer.asUint8List();
|
|
||||||
|
|
||||||
// 返回字节数组
|
// 返回字节数组
|
||||||
return uint8List.toList();
|
return uint8List.toList();
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import '../entity/lockListInfo_entity.dart';
|
import '../entity/lockListInfo_entity.dart';
|
||||||
|
|
||||||
class LockMainState {
|
class LockMainState {
|
||||||
|
|
||||||
// 0是无数据 1是有一条数据 2是有很多条数据
|
// 0是无数据 1是有一条数据 2是有很多条数据
|
||||||
RxInt dataLength = 100.obs;
|
RxInt dataLength = 100.obs;
|
||||||
Rx<LockListInfoGroupEntity> lockListInfoGroupEntity = LockListInfoGroupEntity().obs;
|
Rx<LockListInfoGroupEntity> lockListInfoGroupEntity = LockListInfoGroupEntity().obs;
|
||||||
@ -13,5 +11,6 @@ class LockMainState {
|
|||||||
// 网络连接状态 0没有网络 1有网络
|
// 网络连接状态 0没有网络 1有网络
|
||||||
RxInt networkConnectionStatus = 0.obs;
|
RxInt networkConnectionStatus = 0.obs;
|
||||||
|
|
||||||
// late Timer timer;
|
RxInt selectedIndex = 0.obs;
|
||||||
|
// late Timer timer;
|
||||||
}
|
}
|
||||||
@ -31,7 +31,8 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
late StreamSubscription<Reply> _replySubscription;
|
late StreamSubscription<Reply> _replySubscription;
|
||||||
|
|
||||||
void _initReplySubscription() {
|
void _initReplySubscription() {
|
||||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) {
|
_replySubscription =
|
||||||
|
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) {
|
||||||
if (reply is AddUserReply && state.ifCurrentScreen.value == true) {
|
if (reply is AddUserReply && state.ifCurrentScreen.value == true) {
|
||||||
_replyAddUserKey(reply);
|
_replyAddUserKey(reply);
|
||||||
}
|
}
|
||||||
@ -65,11 +66,15 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
//无权限
|
//无权限
|
||||||
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
final List<String>? privateKey =
|
||||||
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
await Storage.getStringList(saveBluePrivateKey);
|
||||||
|
final List<int> getPrivateKeyList =
|
||||||
|
changeStringListToIntList(privateKey!);
|
||||||
|
|
||||||
final List<String>? publicKey = await Storage.getStringList(saveBluePublicKey);
|
final List<String>? publicKey =
|
||||||
final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
await Storage.getStringList(saveBluePublicKey);
|
||||||
|
final List<int> publicKeyDataList =
|
||||||
|
changeStringListToIntList(publicKey!);
|
||||||
|
|
||||||
IoSenderManage.senderAddUser(
|
IoSenderManage.senderAddUser(
|
||||||
lockID: BlueManage().connectDeviceName,
|
lockID: BlueManage().connectDeviceName,
|
||||||
@ -210,14 +215,19 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
showBlueConnetctToast();
|
showBlueConnetctToast();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState deviceConnectionState) async {
|
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||||
|
(BluetoothConnectionState deviceConnectionState) async {
|
||||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||||
// 私钥
|
// 私钥
|
||||||
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
final List<String>? privateKey =
|
||||||
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
await Storage.getStringList(saveBluePrivateKey);
|
||||||
|
final List<int> getPrivateKeyList =
|
||||||
|
changeStringListToIntList(privateKey!);
|
||||||
|
|
||||||
final List<String>? publicKey = await Storage.getStringList(saveBluePublicKey);
|
final List<String>? publicKey =
|
||||||
final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
await Storage.getStringList(saveBluePublicKey);
|
||||||
|
final List<int> publicKeyDataList =
|
||||||
|
changeStringListToIntList(publicKey!);
|
||||||
|
|
||||||
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
final List<String>? token = await Storage.getStringList(saveBlueToken);
|
||||||
List<int> getTokenList = <int>[0, 0, 0, 0];
|
List<int> getTokenList = <int>[0, 0, 0, 0];
|
||||||
@ -247,7 +257,8 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
privateKey: getPrivateKeyList,
|
privateKey: getPrivateKeyList,
|
||||||
token: getTokenList,
|
token: getTokenList,
|
||||||
isBeforeAddUser: true);
|
isBeforeAddUser: true);
|
||||||
} else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
|
} else if (deviceConnectionState ==
|
||||||
|
BluetoothConnectionState.disconnected) {
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
cancelBlueConnetctToastTimer();
|
cancelBlueConnetctToastTimer();
|
||||||
state.sureBtnState.value = 0;
|
state.sureBtnState.value = 0;
|
||||||
@ -365,14 +376,16 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
// positionMap['address'] = state.addressInfo['address'];
|
// positionMap['address'] = state.addressInfo['address'];
|
||||||
|
|
||||||
final Map<String, dynamic> bluetooth = <String, dynamic>{};
|
final Map<String, dynamic> bluetooth = <String, dynamic>{};
|
||||||
bluetooth['bluetoothDeviceId'] = state.lockInfo['mac'];
|
bluetooth['bluetoothDeviceId'] = BlueManage().connectDeviceMacAddress;
|
||||||
bluetooth['bluetoothDeviceName'] = BlueManage().connectDeviceName;
|
bluetooth['bluetoothDeviceName'] = BlueManage().connectDeviceName;
|
||||||
|
|
||||||
final List<String>? publicKey = await Storage.getStringList(saveBluePublicKey);
|
final List<String>? publicKey =
|
||||||
|
await Storage.getStringList(saveBluePublicKey);
|
||||||
final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
final List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||||
bluetooth['publicKey'] = publicKeyDataList;
|
bluetooth['publicKey'] = publicKeyDataList;
|
||||||
|
|
||||||
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
|
final List<String>? privateKey =
|
||||||
|
await Storage.getStringList(saveBluePrivateKey);
|
||||||
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||||
bluetooth['privateKey'] = getPrivateKeyList;
|
bluetooth['privateKey'] = getPrivateKeyList;
|
||||||
|
|
||||||
@ -397,7 +410,8 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
final String getMobile = (await Storage.getMobile())!;
|
final String getMobile = (await Storage.getMobile())!;
|
||||||
ApmHelper.instance.trackEvent('save_lock_result', {
|
ApmHelper.instance.trackEvent('save_lock_result', {
|
||||||
'lock_name': BlueManage().connectDeviceName,
|
'lock_name': BlueManage().connectDeviceName,
|
||||||
'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
'account':
|
||||||
|
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
||||||
'date': DateTool().getNowDateWithType(1),
|
'date': DateTool().getNowDateWithType(1),
|
||||||
'save_lock_result': '成功',
|
'save_lock_result': '成功',
|
||||||
});
|
});
|
||||||
@ -413,7 +427,8 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
final String getMobile = (await Storage.getMobile())!;
|
final String getMobile = (await Storage.getMobile())!;
|
||||||
ApmHelper.instance.trackEvent('save_lock_result', {
|
ApmHelper.instance.trackEvent('save_lock_result', {
|
||||||
'lock_name': BlueManage().connectDeviceName,
|
'lock_name': BlueManage().connectDeviceName,
|
||||||
'account': getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
'account':
|
||||||
|
getMobile.isNotEmpty ? getMobile : (await Storage.getEmail())!,
|
||||||
'date': DateTool().getNowDateWithType(1),
|
'date': DateTool().getNowDateWithType(1),
|
||||||
'save_lock_result': '${entity.errorCode}--${entity.errorMsg}',
|
'save_lock_result': '${entity.errorCode}--${entity.errorMsg}',
|
||||||
});
|
});
|
||||||
@ -474,18 +489,26 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
// BlueManage().disconnect();
|
// BlueManage().disconnect();
|
||||||
|
|
||||||
// 查询锁设置信息
|
// 查询锁设置信息
|
||||||
final LockSetInfoEntity entity = await ApiRepository.to.getLockSettingInfoData(
|
final LockSetInfoEntity entity =
|
||||||
|
await ApiRepository.to.getLockSettingInfoData(
|
||||||
lockId: state.lockId.toString(),
|
lockId: state.lockId.toString(),
|
||||||
);
|
);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
state.lockSetInfoData.value = entity.data!;
|
state.lockSetInfoData.value = entity.data!;
|
||||||
if (state.lockSetInfoData.value.lockFeature?.wifi == 1) {
|
if (state.lockSetInfoData.value.lockFeature?.wifi == 1) {
|
||||||
// 如果是wifi锁,需要配置WIFI
|
// 如果是wifi锁,需要配置WIFI
|
||||||
Get.toNamed(Routers.wifiListPage, arguments: {'lockSetInfoData': state.lockSetInfoData.value, 'pageName': 'saveLock'});
|
Get.toNamed(Routers.wifiListPage, arguments: {
|
||||||
|
'lockSetInfoData': state.lockSetInfoData.value,
|
||||||
|
'pageName': 'saveLock'
|
||||||
|
});
|
||||||
} else if (state.lockSetInfoData.value.lockFeature?.languageSpeech == 1) {
|
} else if (state.lockSetInfoData.value.lockFeature?.languageSpeech == 1) {
|
||||||
Get.toNamed(Routers.lockVoiceSettingPage, arguments: {'lockSetInfoData': state.lockSetInfoData.value, 'pageName': 'saveLock'});
|
Get.toNamed(Routers.lockVoiceSettingPage, arguments: {
|
||||||
|
'lockSetInfoData': state.lockSetInfoData.value,
|
||||||
|
'pageName': 'saveLock'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true, isUnShowLoading: true));
|
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||||
|
clearScanDevices: true, isUnShowLoading: true));
|
||||||
Future<void>.delayed(const Duration(seconds: 1), () {
|
Future<void>.delayed(const Duration(seconds: 1), () {
|
||||||
// Get.close(state.isFromMap == 1
|
// Get.close(state.isFromMap == 1
|
||||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
||||||
@ -495,12 +518,15 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
//刚刚配对完,需要对开锁页锁死 2 秒
|
//刚刚配对完,需要对开锁页锁死 2 秒
|
||||||
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
||||||
if (Get.isRegistered<LockDetailLogic>()) {
|
if (Get.isRegistered<LockDetailLogic>()) {
|
||||||
Get.find<LockDetailLogic>().functionBlocker.countdownProhibited(duration: const Duration(seconds: 2));
|
Get.find<LockDetailLogic>()
|
||||||
|
.functionBlocker
|
||||||
|
.countdownProhibited(duration: const Duration(seconds: 2));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eventBus.fire(RefreshLockListInfoDataEvent(clearScanDevices: true, isUnShowLoading: true));
|
eventBus.fire(RefreshLockListInfoDataEvent(
|
||||||
|
clearScanDevices: true, isUnShowLoading: true));
|
||||||
Future<void>.delayed(const Duration(seconds: 1), () {
|
Future<void>.delayed(const Duration(seconds: 1), () {
|
||||||
// Get.close(state.isFromMap == 1
|
// Get.close(state.isFromMap == 1
|
||||||
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
// ? (CommonDataManage().seletLockType == 0 ? 4 : 5)
|
||||||
@ -510,7 +536,9 @@ class SaveLockLogic extends BaseGetXController {
|
|||||||
//刚刚配对完,需要对开锁页锁死 2 秒
|
//刚刚配对完,需要对开锁页锁死 2 秒
|
||||||
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
Future<void>.delayed(const Duration(milliseconds: 200), () {
|
||||||
if (Get.isRegistered<LockDetailLogic>()) {
|
if (Get.isRegistered<LockDetailLogic>()) {
|
||||||
Get.find<LockDetailLogic>().functionBlocker.countdownProhibited(duration: const Duration(seconds: 2));
|
Get.find<LockDetailLogic>()
|
||||||
|
.functionBlocker
|
||||||
|
.countdownProhibited(duration: const Duration(seconds: 2));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
final GatewayConfigurationWifiState state = GatewayConfigurationWifiState();
|
final GatewayConfigurationWifiState state = GatewayConfigurationWifiState();
|
||||||
|
|
||||||
Future<void> gatewayDistributionNetwork() async {
|
Future<void> gatewayDistributionNetwork() async {
|
||||||
final LoginEntity entity = await ApiRepository.to.gatewayDistributionNetwork(
|
final LoginEntity entity = await ApiRepository.to
|
||||||
|
.gatewayDistributionNetwork(
|
||||||
gatewayName: state.gatewayNameTF.text,
|
gatewayName: state.gatewayNameTF.text,
|
||||||
gatewayMac: state.gatewayModel.mac,
|
gatewayMac: state.gatewayModel.mac,
|
||||||
serialNumber: state.gatewayModel.serialNum,
|
serialNumber: state.gatewayModel.serialNum,
|
||||||
@ -41,7 +42,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getGatewayConfiguration() async {
|
Future<void> getGatewayConfiguration() async {
|
||||||
final GetGatewayConfigurationEntity entity = await ApiRepository.to.getGatewayConfiguration(timeout: 60);
|
final GetGatewayConfigurationEntity entity =
|
||||||
|
await ApiRepository.to.getGatewayConfiguration(timeout: 60);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
String configStr = entity.data ?? '';
|
String configStr = entity.data ?? '';
|
||||||
|
|
||||||
@ -50,7 +52,6 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
try {
|
try {
|
||||||
Map<String, dynamic> config = jsonDecode(configStr);
|
Map<String, dynamic> config = jsonDecode(configStr);
|
||||||
config['timeZoneOffset'] = DateTime.now().timeZoneOffset.inSeconds;
|
config['timeZoneOffset'] = DateTime.now().timeZoneOffset.inSeconds;
|
||||||
AppLog.log('state.config:$config');
|
|
||||||
state.getGatewayConfigurationStr = jsonEncode(config);
|
state.getGatewayConfigurationStr = jsonEncode(config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
AppLog.log('处理网关配置时区信息失败: $e');
|
AppLog.log('处理网关配置时区信息失败: $e');
|
||||||
@ -67,9 +68,9 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 监听设备返回的数据
|
// 监听设备返回的数据
|
||||||
late StreamSubscription<Reply> _replySubscription;
|
late StreamSubscription<Reply> _replySubscription;
|
||||||
|
|
||||||
void _initReplySubscription() {
|
void _initReplySubscription() {
|
||||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
_replySubscription =
|
||||||
|
EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
|
||||||
// WIFI配网
|
// WIFI配网
|
||||||
// if(reply is GatewayConfiguringWifiReply) {
|
// if(reply is GatewayConfiguringWifiReply) {
|
||||||
// _replySenderConfiguringWifi(reply);
|
// _replySenderConfiguringWifi(reply);
|
||||||
@ -111,7 +112,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
cancelBlueConnetctToastTimer();
|
cancelBlueConnetctToastTimer();
|
||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
final int secretKeyJsonLength = (reply.data[3] << 8) + reply.data[4];
|
final int secretKeyJsonLength = (reply.data[3] << 8) + reply.data[4];
|
||||||
final List<int> secretKeyList = reply.data.sublist(5, 5 + secretKeyJsonLength);
|
final List<int> secretKeyList =
|
||||||
|
reply.data.sublist(5, 5 + secretKeyJsonLength);
|
||||||
state.gatewayJson = utf8String(secretKeyList);
|
state.gatewayJson = utf8String(secretKeyList);
|
||||||
|
|
||||||
gatewayDistributionNetwork();
|
gatewayDistributionNetwork();
|
||||||
@ -127,7 +129,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 点击配置wifi
|
// 点击配置wifi
|
||||||
Future<void> senderConfiguringWifiAction() async {
|
Future<void> senderConfiguringWifiAction() async {
|
||||||
AppLog.log('state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
|
AppLog.log(
|
||||||
|
'state.getGatewayConfigurationStr:${state.getGatewayConfigurationStr}');
|
||||||
if (state.wifiNameTF.text.isEmpty) {
|
if (state.wifiNameTF.text.isEmpty) {
|
||||||
showToast('请输入wifi名称'.tr);
|
showToast('请输入wifi名称'.tr);
|
||||||
return;
|
return;
|
||||||
@ -155,7 +158,8 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
dismissEasyLoading();
|
dismissEasyLoading();
|
||||||
state.sureBtnState.value = 0;
|
state.sureBtnState.value = 0;
|
||||||
});
|
});
|
||||||
BlueManage().blueSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
|
BlueManage().blueSendData(BlueManage().connectDeviceName,
|
||||||
|
(BluetoothConnectionState connectionState) async {
|
||||||
if (connectionState == BluetoothConnectionState.connected) {
|
if (connectionState == BluetoothConnectionState.connected) {
|
||||||
IoSenderManage.gatewayConfiguringWifiCommand(
|
IoSenderManage.gatewayConfiguringWifiCommand(
|
||||||
ssid: state.wifiNameTF.text,
|
ssid: state.wifiNameTF.text,
|
||||||
@ -174,7 +178,6 @@ class GatewayConfigurationWifiLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final NetworkInfo _networkInfo = NetworkInfo();
|
final NetworkInfo _networkInfo = NetworkInfo();
|
||||||
|
|
||||||
Future<String> getWifiName() async {
|
Future<String> getWifiName() async {
|
||||||
String ssid = '';
|
String ssid = '';
|
||||||
ssid = (await _networkInfo.getWifiName())!;
|
ssid = (await _networkInfo.getWifiName())!;
|
||||||
|
|||||||
@ -29,6 +29,38 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
final MessageListLogic logic = Get.put(MessageListLogic());
|
final MessageListLogic logic = Get.put(MessageListLogic());
|
||||||
final MessageListState state = Get.find<MessageListLogic>().state;
|
final MessageListState state = Get.find<MessageListLogic>().state;
|
||||||
|
|
||||||
|
// 修改 _showCheckboxes 状态变量为可观察状态
|
||||||
|
final RxBool _showCheckboxes = false.obs;
|
||||||
|
|
||||||
|
// 添加选中状态
|
||||||
|
final RxList<bool> _selectedItems = <bool>[].obs;
|
||||||
|
|
||||||
|
// 添加控制通知横幅显示的状态
|
||||||
|
bool showNotificationBanner = true;
|
||||||
|
|
||||||
|
// 添加设置状态变量
|
||||||
|
final RxBool _pushNotificationEnabled = false.obs;
|
||||||
|
|
||||||
|
// 删除方法
|
||||||
|
void deleteSelectedMessages() {
|
||||||
|
final List<MessageItemEntity> selectedMessages = [];
|
||||||
|
for (int i = 0; i < state.itemDataList.value.length; i++) {
|
||||||
|
if (_selectedItems[i]) {
|
||||||
|
selectedMessages.add(state.itemDataList.value[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用删除接口
|
||||||
|
//logic.deletMessageDataRequest(selectedMessages);
|
||||||
|
|
||||||
|
// 清空选中状态
|
||||||
|
_selectedItems.clear();
|
||||||
|
_selectedItems.addAll(
|
||||||
|
List.generate(state.itemDataList.value.length, (index) => false));
|
||||||
|
_showCheckboxes.value = false;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
void getHttpData() {
|
void getHttpData() {
|
||||||
logic.messageListDataRequest().then((MessageListEntity value) {
|
logic.messageListDataRequest().then((MessageListEntity value) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -39,9 +71,31 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
// 获取当前消息推送设置状态
|
||||||
|
_loadPushNotificationStatus();
|
||||||
|
|
||||||
getHttpData();
|
getHttpData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载消息推送状态
|
||||||
|
void _loadPushNotificationStatus() async {
|
||||||
|
final bool? enabled = await Storage.getBool('push_notification_enabled');
|
||||||
|
_pushNotificationEnabled.value = enabled ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//添加以时间分组的方法
|
||||||
|
Map<String, List<MessageItemEntity>> _groupMessagesByDate() {
|
||||||
|
Map<String, List<MessageItemEntity>> grouped = {};
|
||||||
|
state.itemDataList.forEach((item) {
|
||||||
|
String date = DateTool().dateToYMDString(item.createdAt!.toString());
|
||||||
|
if (!grouped.containsKey(date)) {
|
||||||
|
grouped[date] = [];
|
||||||
|
}
|
||||||
|
grouped[date]!.add(item);
|
||||||
|
});
|
||||||
|
return grouped;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@ -80,20 +134,228 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
}, child: Obx(() {
|
}, child: Obx(() {
|
||||||
return state.itemDataList.value.isEmpty
|
return state.itemDataList.value.isEmpty
|
||||||
? NoData()
|
? NoData()
|
||||||
: SlidableAutoCloseBehavior(
|
: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
height: showNotificationBanner ? 100 : 70,
|
||||||
|
child: Column(children: [
|
||||||
|
showNotificationBanner
|
||||||
|
? Container(
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 10, right: 10),
|
||||||
|
color: AppColors.messageTipsColor,
|
||||||
|
height: 30,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('开启消息通知开关,及时获取通知',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 20.sp)),
|
||||||
|
Row(children: [
|
||||||
|
!_pushNotificationEnabled.value
|
||||||
|
? GestureDetector(child: Text('去开启',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: 20.sp)),
|
||||||
|
onTap: (){
|
||||||
|
|
||||||
|
}) : SizedBox.shrink(),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
InkWell(
|
||||||
|
child: Image.asset(
|
||||||
|
'images/mine/icon_message_close.png',
|
||||||
|
width: 24.w,
|
||||||
|
height: 24.w),
|
||||||
|
onTap: () {
|
||||||
|
// 可以通过控制一个状态变量来隐藏整个通知栏
|
||||||
|
setState(() {
|
||||||
|
showNotificationBanner =
|
||||||
|
false;
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
]))
|
||||||
|
: SizedBox.shrink(),
|
||||||
|
Container(
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 15.w, right: 24.w, top: 20.h),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text('告警',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 30.sp)),
|
||||||
|
// 点击多选可以进行删除
|
||||||
|
// GestureDetector(
|
||||||
|
// onTap: () {
|
||||||
|
// // 没有多选删除的 api接口,无法使用
|
||||||
|
// // if (_showCheckboxes.value) {
|
||||||
|
// // deleteSelectedMessages();
|
||||||
|
// // } else {
|
||||||
|
// // setState(() {
|
||||||
|
// // _showCheckboxes.value =
|
||||||
|
// // !_showCheckboxes.value;
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
// },
|
||||||
|
// child: _showCheckboxes.value
|
||||||
|
// ? Text('删除',
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 24.sp,
|
||||||
|
// color: Colors.red))
|
||||||
|
// : Image.asset(
|
||||||
|
// 'images/mine/icon_message_checbox.png',
|
||||||
|
// width: 30.w,
|
||||||
|
// height: 30.h),
|
||||||
|
// )
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
]))),
|
||||||
|
Container(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: showNotificationBanner ? 80 : 50),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: state.itemDataList.value.length,
|
itemCount: _buildGroupedListItems().length,
|
||||||
itemBuilder: (BuildContext c, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final MessageItemEntity messageItemEntity =
|
var item = _buildGroupedListItems()[index];
|
||||||
state.itemDataList.value[index];
|
|
||||||
return Slidable(
|
if (item is String) {
|
||||||
key: ValueKey(messageItemEntity.id),
|
// 日期标题
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16.w, vertical: 10.h),
|
||||||
|
color: AppColors.mainBackgroundColor,
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: item.substring(8, 10),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 36.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: ' ',
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: item.substring(5, 7),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.grey, fontSize: 20.sp, fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (item is MessageItemEntity) {
|
||||||
|
// 消息项
|
||||||
|
return _messageListItem(item, () {
|
||||||
|
Get.toNamed(Routers.messageDetailPage,
|
||||||
|
arguments: <String, MessageItemEntity>{
|
||||||
|
'messageItemEntity': item
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建分组列表
|
||||||
|
List<dynamic> _buildGroupedListItems() {
|
||||||
|
List<dynamic> items = [];
|
||||||
|
Map<String, List<MessageItemEntity>> grouped = _groupMessagesByDate();
|
||||||
|
|
||||||
|
grouped.forEach((date, messages) {
|
||||||
|
items.add(date); // 添加日期标题
|
||||||
|
items.addAll(messages.map((message) => message)); // 添加该日期下的所有消息
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化选中状态
|
||||||
|
if (_selectedItems.length != state.itemDataList.value.length) {
|
||||||
|
_selectedItems.clear();
|
||||||
|
_selectedItems.addAll(
|
||||||
|
List.generate(state.itemDataList.value.length, (index) => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _messageListItem(
|
||||||
|
MessageItemEntity messageItemEntity, Function() action) {
|
||||||
|
final int index = state.itemDataList.value.indexOf(messageItemEntity);
|
||||||
|
|
||||||
|
// 查找当前消息在其所属日期分组中的位置
|
||||||
|
Map<String, List<MessageItemEntity>> grouped = _groupMessagesByDate();
|
||||||
|
bool isLastInGroupSimple = false;
|
||||||
|
|
||||||
|
// 确定当前消息属于哪个日期分组
|
||||||
|
for (var entry in grouped.entries) {
|
||||||
|
int messageIndex = entry.value.indexWhere((msg) => msg.id == messageItemEntity.id);
|
||||||
|
if (messageIndex != -1) {
|
||||||
|
// 如果是该分组的最后一条消息
|
||||||
|
isLastInGroupSimple = messageIndex == entry.value.length - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// 如果是多选模式,切换选中状态
|
||||||
|
if (_showCheckboxes.value) {
|
||||||
|
_selectedItems[index] = !_selectedItems[index];
|
||||||
|
setState(() {});
|
||||||
|
} else {
|
||||||
|
// 否则跳转到详情页
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.only(left: 10),
|
||||||
|
transform: Matrix4.translationValues(0, 20, 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
messageItemEntity.readAt! == 0
|
||||||
|
? 'images/mine/icon_message_unread.png'
|
||||||
|
: 'images/mine/icon_message_readed.png',
|
||||||
|
width: 18.w,
|
||||||
|
height: 18.h),
|
||||||
|
// 添加竖线,根据是否是分组最后一条消息来决定是否显示
|
||||||
|
if (!isLastInGroupSimple)
|
||||||
|
Container(
|
||||||
|
width: 0.5,
|
||||||
|
height: 190.h,
|
||||||
|
color: AppColors.placeholderTextColor,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
child: Slidable(
|
||||||
|
key: Key(messageItemEntity.id.toString()), // 为每个item添加唯一key
|
||||||
endActionPane: ActionPane(
|
endActionPane: ActionPane(
|
||||||
extentRatio: 0.2,
|
|
||||||
motion: const ScrollMotion(),
|
motion: const ScrollMotion(),
|
||||||
children: <Widget>[
|
children: [
|
||||||
SlidableAction(
|
SlidableAction(
|
||||||
onPressed: (BuildContext context) {
|
onPressed: (context) {
|
||||||
|
// 删除单条消息
|
||||||
logic.deletMessageDataRequest(
|
logic.deletMessageDataRequest(
|
||||||
messageItemEntity.id!, () {
|
messageItemEntity.id!, () {
|
||||||
logic.pageNo = 1;
|
logic.pageNo = 1;
|
||||||
@ -102,94 +364,124 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
},
|
},
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
label: '删除'.tr,
|
icon: Icons.delete,
|
||||||
padding: EdgeInsets.only(left: 5.w, right: 5.w),
|
label: '删除',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
), child: Container(
|
||||||
child: _messageListItem(messageItemEntity, () {
|
|
||||||
Get.toNamed(Routers.messageDetailPage,
|
|
||||||
arguments: <String, MessageItemEntity>{
|
|
||||||
'messageItemEntity': messageItemEntity
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _messageListItem(
|
|
||||||
MessageItemEntity messageItemEntity, Function() action) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: action,
|
|
||||||
child: Container(
|
|
||||||
height: 90.h,
|
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
margin: EdgeInsets.only(bottom: 2.h),
|
margin: EdgeInsets.all(20.h),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(10.w),
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
margin: EdgeInsets.only(left: 20.w, right: 20.w),
|
margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 8.h),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Row(
|
// SizedBox(height: 4.h),
|
||||||
|
// Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// Flexible(
|
||||||
|
// child: Text(
|
||||||
|
// // 调用请求标题
|
||||||
|
// '远程开门请求',
|
||||||
|
// maxLines: 1,
|
||||||
|
// overflow: TextOverflow.ellipsis,
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 22.sp,
|
||||||
|
// color: messageItemEntity.readAt! == 0
|
||||||
|
// ? AppColors.blackColor
|
||||||
|
// : AppColors.placeholderTextColor),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 4.h),
|
||||||
|
Wrap(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (messageItemEntity.readAt! == 0)
|
// if (messageItemEntity.readAt! == 0)
|
||||||
|
// Container(
|
||||||
|
// width: 10.w,
|
||||||
|
// height: 10.w,
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: Colors.red,
|
||||||
|
// borderRadius: BorderRadius.circular(5.w),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// else
|
||||||
|
// Container(),
|
||||||
|
// if (messageItemEntity.readAt! == 0)
|
||||||
|
// SizedBox(width: 5.w)
|
||||||
|
// else
|
||||||
|
// Container(),
|
||||||
Container(
|
Container(
|
||||||
width: 10.w,
|
margin: EdgeInsets.only(top: 4.h),
|
||||||
height: 10.w,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.red,
|
|
||||||
borderRadius: BorderRadius.circular(5.w),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Container(),
|
|
||||||
if (messageItemEntity.readAt! == 0)
|
|
||||||
SizedBox(width: 5.w)
|
|
||||||
else
|
|
||||||
Container(),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
child: Text(
|
||||||
messageItemEntity.data!,
|
DateTool().dateToHnString(messageItemEntity.createdAt!.toString()),
|
||||||
maxLines: 1,
|
style: TextStyle(
|
||||||
|
fontSize: 20.sp,
|
||||||
|
color: messageItemEntity.readAt! == 0
|
||||||
|
? AppColors.blackColor
|
||||||
|
: AppColors.placeholderTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
height: 10,
|
||||||
|
margin: EdgeInsets.only(left: 5.w, right: 5.w, top: 10.h),
|
||||||
|
color: messageItemEntity.readAt! == 0
|
||||||
|
? AppColors.blackColor
|
||||||
|
: AppColors.placeholderTextColor,
|
||||||
|
),
|
||||||
|
Container(transform: Matrix4.translationValues(0, -18, 0),
|
||||||
|
child: Text(' ${messageItemEntity.data!}',
|
||||||
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22.sp,
|
fontSize: 20.sp,
|
||||||
color: messageItemEntity.readAt! == 0
|
color: messageItemEntity.readAt! == 0
|
||||||
? AppColors.blackColor
|
? AppColors.blackColor
|
||||||
: AppColors.placeholderTextColor),
|
: AppColors.placeholderTextColor,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
)),
|
||||||
|
Container(transform: Matrix4.translationValues(0, -8, 0), child: GestureDetector(
|
||||||
|
child: Text('点击查看', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20.sp, color: AppColors.mainColor),),
|
||||||
|
),alignment: Alignment.centerRight,)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 10.h),
|
// SizedBox(height: 5.h),
|
||||||
Row(
|
// Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: <Widget>[
|
// children: <Widget>[
|
||||||
// Image.asset('images/mine/icon_mine_gatewaySignal_strong.png', width: 40.w, height: 40.w,),
|
// // Image.asset('images/mine/icon_mine_gatewaySignal_strong.png', width: 40.w, height: 40.w,),
|
||||||
// SizedBox(width: 10.w,),
|
// // SizedBox(width: 10.w,),
|
||||||
Text(
|
// Text(
|
||||||
DateTool().dateToYMDHNString(
|
// DateTool().dateToHnString(messageItemEntity
|
||||||
messageItemEntity.createdAt!.toString()),
|
// .createdAt!
|
||||||
style: TextStyle(
|
// .toString()),
|
||||||
fontSize: 18.sp,
|
// style: TextStyle(
|
||||||
color: messageItemEntity.readAt! == 0
|
// fontSize: 18.sp,
|
||||||
? AppColors.blackColor
|
// color: messageItemEntity.readAt! == 0
|
||||||
: AppColors.placeholderTextColor)),
|
// ? AppColors.blackColor
|
||||||
],
|
// : AppColors.placeholderTextColor)),
|
||||||
),
|
// ],
|
||||||
SizedBox(width: 20.h),
|
// ),
|
||||||
],
|
// SizedBox(width: 20.h),
|
||||||
),
|
]))))),
|
||||||
),
|
// 显示选中状态的复选框
|
||||||
),
|
if (_showCheckboxes.value)
|
||||||
);
|
Checkbox(
|
||||||
|
value: _selectedItems[index],
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
onChanged: (val) {
|
||||||
|
_selectedItems[index] = val!;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,22 +1,34 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
|
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
|
||||||
import 'package:star_lock/flavors.dart';
|
import 'package:star_lock/flavors.dart';
|
||||||
import 'package:star_lock/mine/mine/starLockMine_state.dart';
|
import 'package:star_lock/mine/mine/starLockMine_state.dart';
|
||||||
|
import 'package:star_lock/tools/storage.dart';
|
||||||
import 'package:star_lock/tools/wechat/customer_tool.dart';
|
import 'package:star_lock/tools/wechat/customer_tool.dart';
|
||||||
|
|
||||||
import '../../appRouters.dart';
|
import '../../appRouters.dart';
|
||||||
import '../../app_settings/app_colors.dart';
|
import '../../app_settings/app_colors.dart';
|
||||||
import '../../baseWidget.dart';
|
import '../../baseWidget.dart';
|
||||||
|
import '../../tools/commonItem.dart';
|
||||||
import '../../tools/customNetworkImage.dart';
|
import '../../tools/customNetworkImage.dart';
|
||||||
|
import '../../tools/showTipView.dart';
|
||||||
import '../../tools/submitBtn.dart';
|
import '../../tools/submitBtn.dart';
|
||||||
import '../../tools/wechat/wechatManageTool.dart';
|
import '../../tools/wechat/wechatManageTool.dart';
|
||||||
import '../../tools/wechat/wx_push_miniProgram/wx_push_miniProgram.dart';
|
import '../../tools/wechat/wx_push_miniProgram/wx_push_miniProgram.dart';
|
||||||
|
import '../../translations/app_dept.dart';
|
||||||
|
import '../../translations/current_locale_tool.dart';
|
||||||
|
import '../mineSet/mineSet/mineSet_logic.dart';
|
||||||
|
import '../mineSet/mineSet/mineSet_state.dart';
|
||||||
import 'starLockMine_logic.dart';
|
import 'starLockMine_logic.dart';
|
||||||
|
|
||||||
class StarLockMinePage extends StatefulWidget {
|
class StarLockMinePage extends StatefulWidget {
|
||||||
const StarLockMinePage({Key? key}) : super(key: key);
|
const StarLockMinePage({Key? key, this.showAppBar = true, this.showAbout = true}) : super(key: key);
|
||||||
|
final bool showAppBar;
|
||||||
|
final bool showAbout;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StarLockMinePage> createState() => StarLockMinePageState();
|
State<StarLockMinePage> createState() => StarLockMinePageState();
|
||||||
@ -27,103 +39,127 @@ GlobalKey<StarLockMinePageState> starLockMineKey = GlobalKey();
|
|||||||
class StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
class StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
||||||
final StarLockMineLogic logic = Get.put(StarLockMineLogic());
|
final StarLockMineLogic logic = Get.put(StarLockMineLogic());
|
||||||
final StarLockMineState state = Get.find<StarLockMineLogic>().state;
|
final StarLockMineState state = Get.find<StarLockMineLogic>().state;
|
||||||
|
late final MineSetState stateSet;
|
||||||
|
late final MineSetLogic logicSet;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
// 确保 MineSetLogic 存在
|
||||||
|
if (!Get.isRegistered<MineSetLogic>()) {
|
||||||
|
Get.put(MineSetLogic());
|
||||||
|
}
|
||||||
|
logicSet = Get.find<MineSetLogic>();
|
||||||
|
stateSet = logicSet.state;
|
||||||
|
logicSet.userSettingsInfoRequest();
|
||||||
|
|
||||||
logic.getUserInfoRequest();
|
logic.getUserInfoRequest();
|
||||||
|
|
||||||
|
// 初始化时检查推送权限状态
|
||||||
|
_checkNotificationPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFFFFFFFF),
|
body: SafeArea(
|
||||||
body: Column(
|
child: SingleChildScrollView(child: Container(
|
||||||
children: <Widget>[
|
margin: EdgeInsets.only(bottom: 20.h),
|
||||||
topWidget(),
|
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||||
bottomListWidget(),
|
|
||||||
SizedBox(
|
|
||||||
height: 80.h,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
WechatManageTool.getAppInfo(() {
|
|
||||||
WxPushWeChatMiniProgramTool.pushWeChatMiniProgram(
|
|
||||||
F.wechatAppInfo.wechatAppId, F.wechatAppInfo.universalLink);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 20.w, right: 20.w),
|
|
||||||
child: Image.asset(
|
|
||||||
'images/mine/icon_mine_wan_miniprogram.png',
|
|
||||||
// width: 400.w,
|
|
||||||
// height: 151.h,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget topWidget() {
|
|
||||||
return Container(
|
|
||||||
height: 380.h,
|
|
||||||
width: 1.sw,
|
|
||||||
color: AppColors.mainColor,
|
|
||||||
// color: Colors.red,
|
|
||||||
child: Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
Image.asset(
|
|
||||||
'images/mine/icon_mine_topBg.png',
|
|
||||||
width: 400.w,
|
|
||||||
height: 380.h,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 120.h,
|
height: 20.h,
|
||||||
),
|
),
|
||||||
|
topWidget(),
|
||||||
|
SizedBox(
|
||||||
|
height: 20.h,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 15.h),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
Get.toNamed(Routers.minePersonInfoPage);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.person,
|
||||||
|
size: 32.sp,
|
||||||
|
),
|
||||||
|
SizedBox(width: 15.w),
|
||||||
|
Text(
|
||||||
|
'个人信息'.tr,
|
||||||
|
style: TextStyle(fontSize: 28.sp),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
color: Colors.grey[400],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 20.h,
|
||||||
|
),
|
||||||
|
bottomListWidget(),
|
||||||
|
SizedBox(
|
||||||
|
height: 20.h,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10.r),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 15.h),
|
||||||
|
child: getListDataView(),
|
||||||
|
)])))));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget topWidget() {
|
||||||
|
return Row(
|
||||||
|
children: <Widget>[
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
Get.toNamed(Routers.minePersonInfoPage);
|
Get.toNamed(Routers.minePersonInfoPage);
|
||||||
},
|
},
|
||||||
child: Obx(() => SizedBox(
|
child: Obx(
|
||||||
width: 105.w,
|
() => SizedBox(
|
||||||
height: 105.w,
|
width: 68.w,
|
||||||
|
height: 68.w,
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(52.5.w),
|
borderRadius: BorderRadius.circular(52.5.w),
|
||||||
child: CustomNetworkImage(
|
child: CustomNetworkImage(
|
||||||
url: state.userHeadUrl.value,
|
url: state.userHeadUrl.value,
|
||||||
defaultUrl: 'images/controls_user.png',
|
defaultUrl: 'images/controls_user.png',
|
||||||
width: 105.w,
|
width: 68.w,
|
||||||
height: 105.h,
|
height: 68.h,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
height: 20.h,
|
|
||||||
),
|
),
|
||||||
Obx(() => GestureDetector(
|
),
|
||||||
|
SizedBox(width: 20.w),
|
||||||
|
Obx(
|
||||||
|
() => GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!state.isVip.value) {
|
if (!state.isVip.value) {
|
||||||
// if (CommonDataManage().currentKeyInfo.isLockOwner !=
|
Get.toNamed(Routers.advancedFeaturesWebPage, arguments: <String, int>{
|
||||||
// 1) {
|
|
||||||
// logic.showToast('请先添加锁');
|
|
||||||
// } else {
|
|
||||||
Get.toNamed(Routers.advancedFeaturesWebPage,
|
|
||||||
arguments: <String, int>{
|
|
||||||
'webBuyType': XSConstantMacro.webBuyTypeVip,
|
'webBuyType': XSConstantMacro.webBuyTypeVip,
|
||||||
});
|
});
|
||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
Get.toNamed(
|
Get.toNamed(Routers.valueAddedServicesHighFunctionPage);
|
||||||
Routers.valueAddedServicesHighFunctionPage);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -134,13 +170,12 @@ class StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
Text(
|
Text(
|
||||||
state.userNickName.value.isNotEmpty
|
state.userNickName.value.isNotEmpty
|
||||||
? state.userNickName.value
|
? state.userNickName.value
|
||||||
: (state.userMobile.value.isNotEmpty
|
: (state.userMobile.value.isNotEmpty ? state.userMobile.value : state.userEmail.value),
|
||||||
? state.userMobile.value
|
|
||||||
: state.userEmail.value),
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22.sp,
|
fontSize: 22.sp,
|
||||||
color: Colors.white,
|
color: Colors.black,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 5.w,
|
width: 5.w,
|
||||||
),
|
),
|
||||||
@ -159,67 +194,82 @@ class StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
|
),
|
||||||
|
// const Spacer(),
|
||||||
|
// Container(
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: Colors.white,
|
||||||
|
// borderRadius: BorderRadius.circular(10.r),
|
||||||
|
// ),
|
||||||
|
// padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 10.h),
|
||||||
|
// child: Row(
|
||||||
|
// children: [
|
||||||
|
// if (F.isSKY && Get.locale!.languageCode == 'zh')
|
||||||
|
// GestureDetector(
|
||||||
|
// onTap: () {
|
||||||
|
// Get.back();
|
||||||
|
// WechatManageTool.getAppInfo(CustomerTool.openCustomerService);
|
||||||
|
// },
|
||||||
|
// child: Image.asset(
|
||||||
|
// 'images/mine/icon_mine_main_supportStaff.png',
|
||||||
|
// width: 34.w,
|
||||||
|
// height: 34.w,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// width: 20.w,
|
||||||
|
// ),
|
||||||
|
// GestureDetector(
|
||||||
|
// onTap: () {
|
||||||
|
// Get.back();
|
||||||
|
// Get.toNamed(Routers.messageListPage);
|
||||||
|
// },
|
||||||
|
// child: Image.asset(
|
||||||
|
// 'images/mine/icon_mine_main_message.png',
|
||||||
|
// width: 36.w,
|
||||||
|
// height: 36.w,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget bottomListWidget() {
|
Widget bottomListWidget() {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(
|
width: double.infinity,
|
||||||
left: 60.w,
|
decoration: BoxDecoration(
|
||||||
top: 50.h,
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10.w),
|
||||||
),
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 20.w),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
mineItem('images/mine/icon_mine_main_addLock.png', '添加设备'.tr, () {
|
// mineItem('images/mine/icon_mine_main_set.png', '设置'.tr, () {
|
||||||
Get.back();
|
// Get.back();
|
||||||
Get.toNamed(Routers.selectLockTypePage);
|
// Get.toNamed(Routers.mineSetPage);
|
||||||
}),
|
|
||||||
// mineItem('images/mine/icon_mine_main_gateway.png',
|
|
||||||
// TranslationLoader.lanKeys!.gateway!.tr, () {
|
|
||||||
// Navigator.pushNamed(context, Routers.gatewayListPage);
|
|
||||||
// }),
|
// }),
|
||||||
mineItem('images/mine/icon_mine_main_message.png', '消息'.tr, () {
|
// SizedBox(height: 20.h),
|
||||||
Get.back();
|
mineItem('images/mine/icon_mine_main_vip.png', '增值服务'.tr, () async {
|
||||||
Get.toNamed(Routers.messageListPage);
|
final bool? isVip = await Storage.getBool(saveIsVip);
|
||||||
// Toast.show(msg: "功能暂未开放");
|
if (isVip == null || !isVip) {
|
||||||
}),
|
// vip状态是和账号绑定,这里判断用户打开的某个锁是不是LockOwner没意义
|
||||||
//删除“客服”行
|
// if (CommonDataManage().currentKeyInfo.isLockOwner != 1) {
|
||||||
// mineItem('images/mine/icon_mine_main_supportStaff.png',
|
// logic.showToast('请先添加锁'.tr);
|
||||||
// TranslationLoader.lanKeys!.supportStaff!.tr, () {
|
// } else {
|
||||||
// Navigator.pushNamed(context, Routers.supportStaffPage);
|
//刷新购买状态
|
||||||
// }),
|
Get.toNamed(Routers.advancedFeaturesWebPage, arguments: <String, int>{
|
||||||
mineItem('images/mine/icon_mine_main_set.png', '设置'.tr, () {
|
'webBuyType': XSConstantMacro.webBuyTypeVip,
|
||||||
Get.back();
|
})?.then((value) => logic.getUserInfoRequest());
|
||||||
Get.toNamed(Routers.mineSetPage);
|
// }
|
||||||
}),
|
} else {
|
||||||
//上架审核
|
Get.toNamed(Routers.valueAddedServicesHighFunctionPage);
|
||||||
// if (F.isLite)
|
}
|
||||||
// Container()
|
|
||||||
// else
|
|
||||||
mineItem('images/mine/icon_mine_main_vip.png', '增值服务'.tr, () {
|
|
||||||
Get.back();
|
|
||||||
Get.toNamed(Routers.valueAddedServicesPage);
|
|
||||||
}),
|
|
||||||
// if (F.isLite)
|
|
||||||
// Container()
|
|
||||||
// else
|
|
||||||
mineItem('images/mine/icon_mine_main_shoppingcart.png', '配件商城'.tr,
|
|
||||||
() {
|
|
||||||
Get.back();
|
|
||||||
Get.toNamed(Routers.lockMallPage);
|
|
||||||
}),
|
|
||||||
if (F.isSKY && Get.locale!.languageCode == 'zh')
|
|
||||||
mineItem('images/mine/icon_mine_main_supportStaff.png', '客服'.tr,
|
|
||||||
() {
|
|
||||||
Get.back();
|
|
||||||
WechatManageTool.getAppInfo(CustomerTool.openCustomerService);
|
|
||||||
}),
|
}),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
mineItem('images/mine/icon_mine_main_about.png', '关于'.tr, () {
|
mineItem('images/mine/icon_mine_main_about.png', '关于'.tr, () {
|
||||||
Get.back();
|
Get.back();
|
||||||
Get.toNamed(Routers.aboutPage);
|
Get.toNamed(Routers.aboutPage);
|
||||||
@ -229,52 +279,9 @@ class StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widget keyBottomWidget() {
|
Widget mineItem(String lockTypeIcon, String lockTypeTitle, Function() action) {
|
||||||
// return Column(
|
|
||||||
// children: <Widget>[
|
|
||||||
// SubmitBtn(
|
|
||||||
// btnName: '退出'.tr,
|
|
||||||
// borderRadius: 20.w,
|
|
||||||
// fontSize: 32.sp,
|
|
||||||
// margin: EdgeInsets.only(left: 60.w, right: 60.w),
|
|
||||||
// padding: EdgeInsets.only(top: 15.w, bottom: 15.w),
|
|
||||||
// onClick: () {}),
|
|
||||||
// Container(
|
|
||||||
// padding: EdgeInsets.only(right: 30.w),
|
|
||||||
// // color: Colors.red,
|
|
||||||
// child: Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
// children: <Widget>[
|
|
||||||
// TextButton(
|
|
||||||
// child: Text(
|
|
||||||
// '删除账号'.tr,
|
|
||||||
// style: TextStyle(
|
|
||||||
// color: AppColors.mainColor, fontWeight: FontWeight.w500),
|
|
||||||
// ),
|
|
||||||
// onPressed: () {},
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// SizedBox(
|
|
||||||
// height: 30.h,
|
|
||||||
// )
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
Widget mineItem(
|
|
||||||
String lockTypeIcon, String lockTypeTitle, Function() action) {
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: action,
|
onTap: action,
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Center(
|
|
||||||
child: Container(
|
|
||||||
// height: 80.h,
|
|
||||||
width: 330.w,
|
|
||||||
padding: EdgeInsets.all(20.h),
|
|
||||||
color: Colors.white,
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Image.asset(
|
Image.asset(
|
||||||
@ -285,15 +292,422 @@ class StarLockMinePageState extends State<StarLockMinePage> with BaseWidget {
|
|||||||
SizedBox(width: 15.w),
|
SizedBox(width: 15.w),
|
||||||
Text(
|
Text(
|
||||||
lockTypeTitle,
|
lockTypeTitle,
|
||||||
style: TextStyle(fontSize: 22.sp),
|
style: TextStyle(fontSize: 28.sp),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
color: Colors.grey[400],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Widget getListDataView() {
|
||||||
|
// 检测系统语言是否为中文
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
/* 2024-01-12 会议确定去掉“提示音、触摸开锁” by DaisyWu
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: TranslationLoader.lanKeys!.prompTone!.tr,
|
||||||
|
rightTitle: "",
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveRightWidget: true,
|
||||||
|
rightWidget: SizedBox(
|
||||||
|
width: 60.w,
|
||||||
|
height: 50.h,
|
||||||
|
child: Obx(() => _isPrompToneSwitch()))),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: TranslationLoader.lanKeys!.touchUnlock!.tr,
|
||||||
|
rightTitle: "",
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveRightWidget: true,
|
||||||
|
rightWidget: SizedBox(
|
||||||
|
width: 60.w,
|
||||||
|
height: 50.h,
|
||||||
|
child: Obx(() => _isTouchUnlockSwitch()))),
|
||||||
|
*/
|
||||||
|
F.sw(
|
||||||
|
skyCall: () => const SizedBox(),
|
||||||
|
xhjCall: () => CommonItem(
|
||||||
|
leftTitel: '个人信息'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.minePersonInfoPage);
|
||||||
|
})),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '消息推送'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveRightWidget: true,
|
||||||
|
isHaveLine: F.sw(
|
||||||
|
skyCall: () => F.appFlavor == Flavor.sky, xhjCall: () => true),
|
||||||
|
rightWidget: SizedBox(
|
||||||
|
width: 60.w,
|
||||||
|
height: 50.h,
|
||||||
|
child: Obx(_isPushNotificationSwitch)
|
||||||
|
)),
|
||||||
|
// if (F.appFlavor == Flavor.sky)
|
||||||
|
Visibility(
|
||||||
|
visible: stateSet.currentLanguageCode == 'zh_CN',
|
||||||
|
child: CommonItem(
|
||||||
|
leftTitel: '微信公众号推送'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveRightWidget: true,
|
||||||
|
rightWidget: SizedBox(
|
||||||
|
width: 60.w,
|
||||||
|
height: 50.h,
|
||||||
|
child: Obx(_isWechatPublicAccountPushSwitch),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10.h),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '锁用户管理'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.lockUserManageLisPage);
|
||||||
|
}),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '授权管理员'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.authorizedAdministratorListPage);
|
||||||
|
}),
|
||||||
|
//by DaisyWu 新增--批量授权
|
||||||
|
if (!F.isProductionEnv)
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '批量授权'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.authorityManagementPage);
|
||||||
|
// Toast.show(msg: "功能暂未开放");
|
||||||
|
}),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '网关'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.gatewayListPage);
|
||||||
|
}),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '锁分组'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.lockGroupListPage);
|
||||||
|
}),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '转移智能锁'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.transferSmartLockPage);
|
||||||
|
}),
|
||||||
|
//暂无网关屏蔽
|
||||||
|
// CommonItem(
|
||||||
|
// leftTitel: '转移网关'.tr,
|
||||||
|
// rightTitle: '',
|
||||||
|
// isHaveLine: true,
|
||||||
|
// isHaveDirection: true,
|
||||||
|
// action: () {
|
||||||
|
// Get.toNamed(Routers.selectGetewayListPage);
|
||||||
|
// }),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
|
||||||
|
// AppLog.log('state.currentLanguageName: ${state.currentLanguageName} state.currentLanguage.value: ${state.currentLanguage.value}');
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '多语言'.tr,
|
||||||
|
rightTitle: stateSet.currentLanguageName,
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () async {
|
||||||
|
// Get.toNamed(Routers.mineMultiLanguagePage);
|
||||||
|
await Get.toNamed(Routers.mineMultiLanguagePage)!.then((value) {
|
||||||
|
setState(() {
|
||||||
|
if (value.containsKey('currentLanguage')) {
|
||||||
|
stateSet.currentLanguage.value = value['currentLanguage'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
/* 2024-01-12 会议确定去掉“锁屏” by DaisyWu
|
||||||
|
Obx(() => CommonItem(
|
||||||
|
leftTitel: TranslationLoader.lanKeys!.lockScreen!.tr,
|
||||||
|
rightTitle: (state.lockScreen.value == 1
|
||||||
|
? TranslationLoader.lanKeys!.opened!.tr
|
||||||
|
: TranslationLoader.lanKeys!.closed!.tr),
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Navigator.pushNamed(context, Routers.lockScreenPage,
|
||||||
|
arguments: {'isOn': state.lockScreen.value}).then((value) {
|
||||||
|
logic.userSettingsInfoRequest();
|
||||||
|
});
|
||||||
|
})),
|
||||||
|
*/
|
||||||
|
Obx(() => CommonItem(
|
||||||
|
leftTitel: '隐藏无效开锁权限'.tr,
|
||||||
|
rightTitle:
|
||||||
|
(stateSet.hideExpiredAccessFlag.value == 1 ? '已开启'.tr : '已关闭'.tr),
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Navigator.pushNamed(
|
||||||
|
context, Routers.hideInvalidUnlockPermissionsPage,
|
||||||
|
arguments: <String, int>{
|
||||||
|
'isOn': stateSet.hideExpiredAccessFlag.value
|
||||||
|
}).then((Object? value) {
|
||||||
|
logicSet.userSettingsInfoRequest();
|
||||||
|
});
|
||||||
|
})),
|
||||||
|
otherItem(
|
||||||
|
leftTitle: 'APP开锁时需手机连网的锁'.tr,
|
||||||
|
isHaveLine: true,
|
||||||
|
action: () {
|
||||||
|
Navigator.pushNamed(
|
||||||
|
context, Routers.aPPUnlockNeedMobileNetworkingLockPage);
|
||||||
|
}),
|
||||||
|
if (!F.isSKY)
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '增值服务'.tr,
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.back();
|
||||||
|
Get.toNamed(Routers.valueAddedServicesPage);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: 'Amazon Alexa'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.amazonAlexaPage, arguments: <String, dynamic>{
|
||||||
|
'isAmazonAlexa': stateSet.isAmazonAlexa.value,
|
||||||
|
'amazonAlexaData': stateSet.amazonAlexaData.value
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: 'Google Home'.tr,
|
||||||
|
rightTitle: '',
|
||||||
|
isHaveLine: true,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.toNamed(Routers.googleHomePage, arguments: <String, dynamic>{
|
||||||
|
'isGoogleHome': stateSet.isGoogleHome.value,
|
||||||
|
'googleHomeData': stateSet.googleHomeData.value
|
||||||
|
})?.then((Object? value) {
|
||||||
|
logicSet.userSettingsInfoRequest();
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
// if (!F.isProductionEnv)
|
||||||
|
// CommonItem(
|
||||||
|
// leftTitel: '小米IOT平台'.tr,
|
||||||
|
// rightTitle: '',
|
||||||
|
// isHaveLine: widget.showAbout,
|
||||||
|
// isHaveDirection: true,
|
||||||
|
// action: () {
|
||||||
|
// logic.showToast('功能暂未开放'.tr);
|
||||||
|
// }),
|
||||||
|
if (!F.isSKY)
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '客服'.tr,
|
||||||
|
isHaveLine: widget.showAbout,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
WechatManageTool.getAppInfo(CustomerTool.openCustomerService);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (widget.showAbout)
|
||||||
|
CommonItem(
|
||||||
|
leftTitel: '关于'.tr,
|
||||||
|
isHaveLine: false,
|
||||||
|
isHaveDirection: true,
|
||||||
|
action: () {
|
||||||
|
Get.back();
|
||||||
|
Get.toNamed(Routers.aboutPage);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.valueAddedServices!.tr, rightTitle:"", isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
SizedBox(
|
||||||
|
height: F.sw(skyCall: () => 50.h, xhjCall: () => 0.0),
|
||||||
|
),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.about!.tr, rightTitle:"", isHaveLine: true, isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
// SizedBox(height: 10.h,),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.userAgreement!.tr, rightTitle:"", isHaveLine: true, isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.privacyPolicy!.tr, rightTitle:"", isHaveLine: true, isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.personalInformationCollectionList!.tr, rightTitle:"", isHaveLine: true, isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.applicationPermissionDescription!.tr, rightTitle:"", isHaveLine: true, isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
// CommonItem(leftTitel:TranslationLoader.lanKeys!.thirdPartyInformationSharingList!.tr, rightTitle:"", isHaveLine: true, isHaveDirection: true, action: (){
|
||||||
|
//
|
||||||
|
// }),
|
||||||
|
F.sw(skyCall: keyBottomWidget, xhjCall: () => const SizedBox())
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//微信公众号推送开关
|
||||||
|
CupertinoSwitch _isWechatPublicAccountPushSwitch() {
|
||||||
|
return CupertinoSwitch(
|
||||||
|
activeColor: CupertinoColors.activeBlue,
|
||||||
|
trackColor: CupertinoColors.systemGrey5,
|
||||||
|
thumbColor: CupertinoColors.white,
|
||||||
|
value: stateSet.isWechatPublicAccountPush.value,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
stateSet.isWechatPublicAccountPush.value =
|
||||||
|
!stateSet.isWechatPublicAccountPush.value;
|
||||||
|
logicSet.setMpWechatPushSwitchRequest(context);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CupertinoSwitch _isPushNotificationSwitch() {
|
||||||
|
return CupertinoSwitch(
|
||||||
|
activeColor: CupertinoColors.activeBlue,
|
||||||
|
trackColor: CupertinoColors.systemGrey5,
|
||||||
|
thumbColor: CupertinoColors.white,
|
||||||
|
value: stateSet.isPushNotification.value,
|
||||||
|
onChanged: (bool value) async {
|
||||||
|
// stateSet.isPushNotification.value = !stateSet.isPushNotification.value;
|
||||||
|
openAppSettings();
|
||||||
|
final PermissionStatus newStatus = await Permission.notification.status;
|
||||||
|
stateSet.isPushNotification.value = newStatus.isGranted;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _checkNotificationPermission() async {
|
||||||
|
final PermissionStatus status = await Permission.notification.status;
|
||||||
|
stateSet.isPushNotification.value = status.isGranted;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget otherItem(
|
||||||
|
{String? leftTitle,
|
||||||
|
bool? isHaveLine,
|
||||||
|
Function()? action,
|
||||||
|
double? allHeight}) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: action,
|
||||||
|
child: Container(
|
||||||
|
width: 1.sw,
|
||||||
|
padding:
|
||||||
|
EdgeInsets.only(left: 20.w, top: 15.h, bottom: 15.h, right: 10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
border: isHaveLine!
|
||||||
|
? Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: AppColors.greyLineColor, // 设置边框颜色
|
||||||
|
width: 2.0.h, // 设置边框宽度
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Text(leftTitle!, style: TextStyle(fontSize: 22.sp))),
|
||||||
|
SizedBox(width: 10.w),
|
||||||
|
if (CurrentLocaleTool.getCurrentLocaleString() ==
|
||||||
|
ExtensionLanguageType.fromLanguageType(LanguageType.hebrew)
|
||||||
|
.toString() ||
|
||||||
|
CurrentLocaleTool.getCurrentLocaleString() ==
|
||||||
|
ExtensionLanguageType.fromLanguageType(LanguageType.arabic)
|
||||||
|
.toString())
|
||||||
|
Image.asset(
|
||||||
|
'images/icon_left_grey.png',
|
||||||
|
width: 21.w,
|
||||||
|
height: 21.w,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Image.asset(
|
||||||
|
'images/icon_right_grey.png',
|
||||||
|
width: 12.w,
|
||||||
|
height: 21.w,
|
||||||
|
),
|
||||||
|
SizedBox(width: 5.w),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget keyBottomWidget() {
|
||||||
|
return Padding(
|
||||||
|
padding: F.sw(
|
||||||
|
skyCall: () => EdgeInsets.zero,
|
||||||
|
xhjCall: () => EdgeInsets.symmetric(horizontal: 15.w)),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
SubmitBtn(
|
||||||
|
btnName: '退出'.tr,
|
||||||
|
isDelete: true,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 15.w),
|
||||||
|
onClick: () {
|
||||||
|
//退出登录
|
||||||
|
ShowTipView().showIosTipWithContentDialog(
|
||||||
|
'确定要退出吗?'.tr, () async {
|
||||||
|
await logicSet.userLogoutRequest();
|
||||||
|
// showLoginOutAlertTipDialog();
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.only(left: 30.w, top: 30.h),
|
||||||
|
// color: Colors.red,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text(
|
||||||
|
'删除账号'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.darkGrayTextColor, fontSize: 18.sp),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
ShowTipView().showIosTipWithContentDialog(
|
||||||
|
'删除账号后,你的所有信息及相关记录都会从平台彻底删除,且不可恢复,是否删除?'.tr, () {
|
||||||
|
//安全验证
|
||||||
|
Get.toNamed(Routers.safeVerifyPage);
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(
|
||||||
Container(
|
height: 30.h,
|
||||||
height: 0.5.h,
|
|
||||||
color: Colors.grey,
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -14,7 +14,8 @@ import 'package:star_lock/talk/starChart/proto/talk_data_h264_frame.pb.dart';
|
|||||||
|
|
||||||
// class UdpTalkDataHandler extends ScpMessageBaseHandle
|
// class UdpTalkDataHandler extends ScpMessageBaseHandle
|
||||||
// implements ScpMessageHandler {
|
// implements ScpMessageHandler {
|
||||||
class UdpTalkDataHandler extends ScpMessageBaseHandle implements ScpMessageHandler {
|
class UdpTalkDataHandler extends ScpMessageBaseHandle
|
||||||
|
implements ScpMessageHandler {
|
||||||
// 单例实现
|
// 单例实现
|
||||||
static final UdpTalkDataHandler instance = UdpTalkDataHandler();
|
static final UdpTalkDataHandler instance = UdpTalkDataHandler();
|
||||||
|
|
||||||
@ -72,7 +73,10 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle implements ScpMessageHandl
|
|||||||
// _asyncLog(
|
// _asyncLog(
|
||||||
// '分包数据:messageId:$messageId [$spIndex/$spTotal] PayloadLength:$PayloadLength');
|
// '分包数据:messageId:$messageId [$spIndex/$spTotal] PayloadLength:$PayloadLength');
|
||||||
if (messageType == MessageTypeConstant.RealTimeData) {
|
if (messageType == MessageTypeConstant.RealTimeData) {
|
||||||
if (spTotal != null && spTotal > 1 && messageId != null && spIndex != null) {
|
if (spTotal != null &&
|
||||||
|
spTotal > 1 &&
|
||||||
|
messageId != null &&
|
||||||
|
spIndex != null) {
|
||||||
// 分包处理
|
// 分包处理
|
||||||
return handleFragmentedPayload(
|
return handleFragmentedPayload(
|
||||||
messageId: messageId,
|
messageId: messageId,
|
||||||
@ -125,11 +129,13 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle implements ScpMessageHandl
|
|||||||
talkDataH264Frame.mergeFromBuffer(talkData.content);
|
talkDataH264Frame.mergeFromBuffer(talkData.content);
|
||||||
// AppLog.log('处理H264帧: frameType=${talkDataH264Frame.frameType}, frameSeq=${talkDataH264Frame.frameSeq},MessageId:${scpMessage.MessageId}');
|
// AppLog.log('处理H264帧: frameType=${talkDataH264Frame.frameType}, frameSeq=${talkDataH264Frame.frameSeq},MessageId:${scpMessage.MessageId}');
|
||||||
frameHandler.handleFrame(talkDataH264Frame, talkData, scpMessage);
|
frameHandler.handleFrame(talkDataH264Frame, talkData, scpMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 处理图片数据
|
/// 处理图片数据
|
||||||
void _handleVideoImage(TalkData talkData) async {
|
void _handleVideoImage(TalkData talkData) async {
|
||||||
final List<Uint8List> processCompletePayload = await _processCompletePayload(Uint8List.fromList(talkData.content));
|
final List<Uint8List> processCompletePayload =
|
||||||
|
await _processCompletePayload(Uint8List.fromList(talkData.content));
|
||||||
processCompletePayload.forEach((element) {
|
processCompletePayload.forEach((element) {
|
||||||
talkData.content = element;
|
talkData.content = element;
|
||||||
talkDataRepository.addTalkData(
|
talkDataRepository.addTalkData(
|
||||||
@ -171,7 +177,8 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle implements ScpMessageHandl
|
|||||||
startIdx = i;
|
startIdx = i;
|
||||||
i++; // Skip the next byte
|
i++; // Skip the next byte
|
||||||
} else if (nextByte == 0xD9 && startIdx != -1) {
|
} else if (nextByte == 0xD9 && startIdx != -1) {
|
||||||
frames.add(Uint8List.view(payload.buffer, startIdx, i + 2 - startIdx));
|
frames
|
||||||
|
.add(Uint8List.view(payload.buffer, startIdx, i + 2 - startIdx));
|
||||||
startIdx = -1;
|
startIdx = -1;
|
||||||
i++; // Skip the next byte
|
i++; // Skip the next byte
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,18 +18,20 @@ import 'package:star_lock/tools/push/xs_jPhush.dart';
|
|||||||
import 'package:star_lock/tools/storage.dart';
|
import 'package:star_lock/tools/storage.dart';
|
||||||
import 'package:star_lock/translations/current_locale_tool.dart';
|
import 'package:star_lock/translations/current_locale_tool.dart';
|
||||||
|
|
||||||
class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHandler {
|
class UdpTalkRequestHandler extends ScpMessageBaseHandle
|
||||||
RxString currentLanguage = CurrentLocaleTool.getCurrentLocaleString().obs; // 当前选择语言
|
implements ScpMessageHandler {
|
||||||
|
RxString currentLanguage =
|
||||||
|
CurrentLocaleTool.getCurrentLocaleString().obs; // 当前选择语言
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void handleReq(ScpMessage scpMessage) async {
|
void handleReq(ScpMessage scpMessage) async {
|
||||||
// 判断是否登录账户
|
// 判断是否登录账户
|
||||||
final loginData = await Storage.getLoginData();
|
final loginData = await Storage.getLoginData();
|
||||||
// 如果登录账户不为空,且不是被动接听状态,且不是接听成功状态
|
// 如果登录账户不为空,且不是被动接听状态,且不是接听成功状态
|
||||||
if (loginData != null && (talkStatus.status != TalkStatus.passiveCallWaitingAnswer || talkStatus.status != TalkStatus.answeredSuccessfully)) {
|
if (loginData != null &&
|
||||||
|
(talkStatus.status != TalkStatus.passiveCallWaitingAnswer ||
|
||||||
|
talkStatus.status != TalkStatus.answeredSuccessfully)) {
|
||||||
// 收到对讲请求
|
// 收到对讲请求
|
||||||
AppLog.log('收到对讲请求ToPeerId:${scpMessage.ToPeerId}');
|
|
||||||
AppLog.log('收到对讲请求FromPeerId:${scpMessage.FromPeerId}');
|
|
||||||
final TalkReq talkReq = scpMessage.Payload;
|
final TalkReq talkReq = scpMessage.Payload;
|
||||||
startChartManage.FromPeerId = scpMessage.ToPeerId!;
|
startChartManage.FromPeerId = scpMessage.ToPeerId!;
|
||||||
startChartManage.ToPeerId = scpMessage.FromPeerId!;
|
startChartManage.ToPeerId = scpMessage.FromPeerId!;
|
||||||
@ -62,6 +64,8 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHa
|
|||||||
_handleResponseSendExpect(
|
_handleResponseSendExpect(
|
||||||
lockPeerID: scpMessage.FromPeerId!,
|
lockPeerID: scpMessage.FromPeerId!,
|
||||||
);
|
);
|
||||||
|
// 发送预期数据
|
||||||
|
startChartManage.startTalkExpectTimer();
|
||||||
// 停止发送对讲请求
|
// 停止发送对讲请求
|
||||||
startChartManage.stopCallRequestMessageTimer();
|
startChartManage.stopCallRequestMessageTimer();
|
||||||
// 收到应答后取消超时判断
|
// 收到应答后取消超时判断
|
||||||
@ -93,7 +97,8 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 收到来电请求时进行本地通知
|
// 收到来电请求时进行本地通知
|
||||||
Future<void> _showTalkRequestNotification({required String talkObjectName}) async {
|
Future<void> _showTalkRequestNotification(
|
||||||
|
{required String talkObjectName}) async {
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
final Map<String, dynamic> message = {
|
final Map<String, dynamic> message = {
|
||||||
'platform': 'all',
|
'platform': 'all',
|
||||||
@ -162,12 +167,14 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHa
|
|||||||
void _handleRequestSendExpect({
|
void _handleRequestSendExpect({
|
||||||
required String lockPeerID,
|
required String lockPeerID,
|
||||||
}) async {
|
}) async {
|
||||||
final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
|
final LockListInfoItemEntity currentKeyInfo =
|
||||||
|
CommonDataManage().currentKeyInfo;
|
||||||
|
|
||||||
var isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
|
var isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
|
||||||
var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
|
var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
|
||||||
|
|
||||||
final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
|
final LockListInfoGroupEntity? lockListInfoGroupEntity =
|
||||||
|
await Storage.getLockMainListData();
|
||||||
if (lockListInfoGroupEntity != null) {
|
if (lockListInfoGroupEntity != null) {
|
||||||
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
||||||
final lockList = element.lockList;
|
final lockList = element.lockList;
|
||||||
@ -188,15 +195,18 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHa
|
|||||||
if (isH264) {
|
if (isH264) {
|
||||||
// 锁支持H264,发送H264视频和G711音频期望
|
// 锁支持H264,发送H264视频和G711音频期望
|
||||||
startChartManage.sendOnlyH264VideoTalkExpectData();
|
startChartManage.sendOnlyH264VideoTalkExpectData();
|
||||||
print('app收到的对讲请求后,发送的预期数据=========锁支持H264,发送H264视频格式期望数据,peerID=${lockPeerID}');
|
print(
|
||||||
|
'app收到的对讲请求后,发送的预期数据=========锁支持H264,发送H264视频格式期望数据,peerID=${lockPeerID}');
|
||||||
} else if (isMJpeg) {
|
} else if (isMJpeg) {
|
||||||
// 锁只支持MJPEG,发送图像视频和G711音频期望
|
// 锁只支持MJPEG,发送图像视频和G711音频期望
|
||||||
startChartManage.sendOnlyImageVideoTalkExpectData();
|
startChartManage.sendOnlyImageVideoTalkExpectData();
|
||||||
print('app收到的对讲请求后,发送的预期数据=========锁不支持H264,支持MJPEG,发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
print(
|
||||||
|
'app收到的对讲请求后,发送的预期数据=========锁不支持H264,支持MJPEG,发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
||||||
} else {
|
} else {
|
||||||
// 默认使用图像视频
|
// 默认使用图像视频
|
||||||
startChartManage.sendOnlyImageVideoTalkExpectData();
|
startChartManage.sendOnlyImageVideoTalkExpectData();
|
||||||
print('app收到的对讲请求后,发送的预期数据=========锁不支持H264和MJPEG,默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
print(
|
||||||
|
'app收到的对讲请求后,发送的预期数据=========锁不支持H264和MJPEG,默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,12 +214,14 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHa
|
|||||||
void _handleResponseSendExpect({
|
void _handleResponseSendExpect({
|
||||||
required String lockPeerID,
|
required String lockPeerID,
|
||||||
}) async {
|
}) async {
|
||||||
final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
|
final LockListInfoItemEntity currentKeyInfo =
|
||||||
|
CommonDataManage().currentKeyInfo;
|
||||||
|
|
||||||
var isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
|
var isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
|
||||||
var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
|
var isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
|
||||||
|
|
||||||
final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
|
final LockListInfoGroupEntity? lockListInfoGroupEntity =
|
||||||
|
await Storage.getLockMainListData();
|
||||||
if (lockListInfoGroupEntity != null) {
|
if (lockListInfoGroupEntity != null) {
|
||||||
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
||||||
final lockList = element.lockList;
|
final lockList = element.lockList;
|
||||||
@ -230,15 +242,18 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle implements ScpMessageHa
|
|||||||
if (isH264) {
|
if (isH264) {
|
||||||
// 锁支持H264,发送H264视频和G711音频期望
|
// 锁支持H264,发送H264视频和G711音频期望
|
||||||
startChartManage.sendH264VideoAndG711AudioTalkExpectData();
|
startChartManage.sendH264VideoAndG711AudioTalkExpectData();
|
||||||
AppLog.log('app主动发对讲请求,收到回复后发送的预期数据=======锁支持H264,发送H264视频格式期望数据,peerID=${lockPeerID}');
|
AppLog.log(
|
||||||
|
'app主动发对讲请求,收到回复后发送的预期数据=======锁支持H264,发送H264视频格式期望数据,peerID=${lockPeerID}');
|
||||||
} else if (isMJpeg) {
|
} else if (isMJpeg) {
|
||||||
// 锁只支持MJPEG,发送图像视频和G711音频期望
|
// 锁只支持MJPEG,发送图像视频和G711音频期望
|
||||||
startChartManage.sendImageVideoAndG711AudioTalkExpectData();
|
startChartManage.sendImageVideoAndG711AudioTalkExpectData();
|
||||||
AppLog.log('app主动发对讲请求,收到回复后发送的预期数据=======锁不支持H264,支持MJPEG,发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
AppLog.log(
|
||||||
|
'app主动发对讲请求,收到回复后发送的预期数据=======锁不支持H264,支持MJPEG,发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
||||||
} else {
|
} else {
|
||||||
// 默认使用图像视频
|
// 默认使用图像视频
|
||||||
startChartManage.sendImageVideoAndG711AudioTalkExpectData();
|
startChartManage.sendImageVideoAndG711AudioTalkExpectData();
|
||||||
AppLog.log('app主动发对讲请求,收到回复后发送的预期数据=======锁不支持H264和MJPEG,默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
AppLog.log(
|
||||||
|
'app主动发对讲请求,收到回复后发送的预期数据=======锁不支持H264和MJPEG,默认发送MJPEG视频格式期望数据,peerID=${lockPeerID}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,9 +61,12 @@ class StartChartManage {
|
|||||||
|
|
||||||
// 单例对象
|
// 单例对象
|
||||||
static final StartChartManage _instance = StartChartManage._internal();
|
static final StartChartManage _instance = StartChartManage._internal();
|
||||||
final TalkeRequestOverTimeTimerManager talkeRequestOverTimeTimerManager = TalkeRequestOverTimeTimerManager();
|
final TalkeRequestOverTimeTimerManager talkeRequestOverTimeTimerManager =
|
||||||
final TalkePingOverTimeTimerManager talkePingOverTimeTimerManager = TalkePingOverTimeTimerManager();
|
TalkeRequestOverTimeTimerManager();
|
||||||
final TalkDataOverTimeTimerManager talkDataOverTimeTimerManager = TalkDataOverTimeTimerManager();
|
final TalkePingOverTimeTimerManager talkePingOverTimeTimerManager =
|
||||||
|
TalkePingOverTimeTimerManager();
|
||||||
|
final TalkDataOverTimeTimerManager talkDataOverTimeTimerManager =
|
||||||
|
TalkDataOverTimeTimerManager();
|
||||||
|
|
||||||
// 工厂构造函数,返回单例对象
|
// 工厂构造函数,返回单例对象
|
||||||
factory StartChartManage() {
|
factory StartChartManage() {
|
||||||
@ -168,7 +171,8 @@ class StartChartManage {
|
|||||||
FromPeerId = loginData?.starchart?.starchartId ?? '';
|
FromPeerId = loginData?.starchart?.starchartId ?? '';
|
||||||
} else {
|
} else {
|
||||||
_log(text: '开始注册客户端');
|
_log(text: '开始注册客户端');
|
||||||
final StarChartRegisterNodeEntity requestStarChartRegisterNode = await _requestStarChartRegisterNode();
|
final StarChartRegisterNodeEntity requestStarChartRegisterNode =
|
||||||
|
await _requestStarChartRegisterNode();
|
||||||
await _saveStarChartRegisterNodeToStorage(requestStarChartRegisterNode);
|
await _saveStarChartRegisterNodeToStorage(requestStarChartRegisterNode);
|
||||||
FromPeerId = requestStarChartRegisterNode.peer!.id ?? '';
|
FromPeerId = requestStarChartRegisterNode.peer!.id ?? '';
|
||||||
bindUserStarchart(requestStarChartRegisterNode);
|
bindUserStarchart(requestStarChartRegisterNode);
|
||||||
@ -176,14 +180,18 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//绑定星图配置
|
//绑定星图配置
|
||||||
Future<void> bindUserStarchart(StarChartRegisterNodeEntity requestStarChartRegisterNode) async {
|
Future<void> bindUserStarchart(
|
||||||
|
StarChartRegisterNodeEntity requestStarChartRegisterNode) async {
|
||||||
try {
|
try {
|
||||||
final LoginEntity entity = await ApiRepository.to.bindUserStarchart(
|
final LoginEntity entity = await ApiRepository.to.bindUserStarchart(
|
||||||
starchartId: requestStarChartRegisterNode.peer?.id ?? '',
|
starchartId: requestStarChartRegisterNode.peer?.id ?? '',
|
||||||
starchartPeerPublicKey: requestStarChartRegisterNode.peer?.publicKey ?? '',
|
starchartPeerPublicKey:
|
||||||
starchartPeerPrivateKey: requestStarChartRegisterNode.peer?.privateKey ?? '',
|
requestStarChartRegisterNode.peer?.publicKey ?? '',
|
||||||
|
starchartPeerPrivateKey:
|
||||||
|
requestStarChartRegisterNode.peer?.privateKey ?? '',
|
||||||
);
|
);
|
||||||
requestStarChartRegisterNode.peer?.id = entity.data?.starchart?.starchartId;
|
requestStarChartRegisterNode.peer?.id =
|
||||||
|
entity.data?.starchart?.starchartId;
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
AppLog.log('绑定成功');
|
AppLog.log('绑定成功');
|
||||||
} else {
|
} else {
|
||||||
@ -196,12 +204,14 @@ class StartChartManage {
|
|||||||
|
|
||||||
// 中继查询
|
// 中继查询
|
||||||
Future<void> _relayQuery() async {
|
Future<void> _relayQuery() async {
|
||||||
final RelayInfoEntity relayInfoEntity = await StartChartApi.to.relayQueryInfo();
|
final RelayInfoEntity relayInfoEntity =
|
||||||
|
await StartChartApi.to.relayQueryInfo();
|
||||||
_saveRelayInfoEntityToStorage(relayInfoEntity);
|
_saveRelayInfoEntityToStorage(relayInfoEntity);
|
||||||
if (relayInfoEntity.client_addr != null) {
|
if (relayInfoEntity.client_addr != null) {
|
||||||
localPublicHost = relayInfoEntity.client_addr!;
|
localPublicHost = relayInfoEntity.client_addr!;
|
||||||
}
|
}
|
||||||
if (relayInfoEntity.relay_list != null && relayInfoEntity.relay_list!.length > 0) {
|
if (relayInfoEntity.relay_list != null &&
|
||||||
|
relayInfoEntity.relay_list!.length > 0) {
|
||||||
for (int i = 0; i <= relayInfoEntity.relay_list!.length; i++) {
|
for (int i = 0; i <= relayInfoEntity.relay_list!.length; i++) {
|
||||||
final data = relayInfoEntity.relay_list?[i];
|
final data = relayInfoEntity.relay_list?[i];
|
||||||
if (data?.peerID != FromPeerId) {
|
if (data?.peerID != FromPeerId) {
|
||||||
@ -229,7 +239,8 @@ class StartChartManage {
|
|||||||
// 初始化udp
|
// 初始化udp
|
||||||
Future<void> _onlineRelayService() async {
|
Future<void> _onlineRelayService() async {
|
||||||
var addressIListenFrom = InternetAddress.anyIPv4;
|
var addressIListenFrom = InternetAddress.anyIPv4;
|
||||||
await RawDatagramSocket.bind(addressIListenFrom, localPort).then((RawDatagramSocket socket) {
|
await RawDatagramSocket.bind(addressIListenFrom, localPort)
|
||||||
|
.then((RawDatagramSocket socket) {
|
||||||
// 设置接收缓冲区大小 (SO_RCVBUF = 8)
|
// 设置接收缓冲区大小 (SO_RCVBUF = 8)
|
||||||
if (AppPlatform.isAndroid) {
|
if (AppPlatform.isAndroid) {
|
||||||
socket.setRawOption(
|
socket.setRawOption(
|
||||||
@ -280,15 +291,15 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送RbcuInfo 地址交换消息
|
// 发送RbcuInfo 地址交换消息
|
||||||
void _sendRbcuInfoMessage({required String ToPeerId, bool isResp = false}) async {
|
void _sendRbcuInfoMessage(
|
||||||
|
{required String ToPeerId, bool isResp = false}) async {
|
||||||
final uuid = _uuid.v1();
|
final uuid = _uuid.v1();
|
||||||
final int timestamp = DateTime
|
final int timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch;
|
|
||||||
final Int64 int64Timestamp = Int64(timestamp); // 使用构造函数
|
final Int64 int64Timestamp = Int64(timestamp); // 使用构造函数
|
||||||
|
|
||||||
// 获取本机所有ip地址和中继返回的外网地址
|
// 获取本机所有ip地址和中继返回的外网地址
|
||||||
final List<ListenAddrData> listenAddrDataList = await _makeListenAddrDataList();
|
final List<ListenAddrData> listenAddrDataList =
|
||||||
|
await _makeListenAddrDataList();
|
||||||
listenAddrDataList.insert(
|
listenAddrDataList.insert(
|
||||||
0, // 插入到头部
|
0, // 插入到头部
|
||||||
ListenAddrData(
|
ListenAddrData(
|
||||||
@ -298,13 +309,15 @@ class StartChartManage {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final address = listenAddrDataList
|
final address = listenAddrDataList
|
||||||
.where((element) => element.type == ListenAddrTypeConstant.local) // 过滤出本地地址
|
.where((element) =>
|
||||||
|
element.type == ListenAddrTypeConstant.local) // 过滤出本地地址
|
||||||
.map((e) => e.address) // 转换为 List<String?>
|
.map((e) => e.address) // 转换为 List<String?>
|
||||||
.where((addr) => addr != null) // 过滤掉 null 值
|
.where((addr) => addr != null) // 过滤掉 null 值
|
||||||
.map(
|
.map(
|
||||||
(addr) => addr!.replaceAll(IpConstant.udpUrl, ''),
|
(addr) => addr!.replaceAll(IpConstant.udpUrl, ''),
|
||||||
) // 去除 "udp://" 前缀
|
) // 去除 "udp://" 前缀
|
||||||
.cast<String>(); // 转换为 Iterable<String>// 将 Iterable<String?> 转换为 Iterable<String>
|
.cast<
|
||||||
|
String>(); // 转换为 Iterable<String>// 将 Iterable<String?> 转换为 Iterable<String>
|
||||||
_rbcuSessionId = uuid;
|
_rbcuSessionId = uuid;
|
||||||
final RbcuInfo rbcuInfo = RbcuInfo(
|
final RbcuInfo rbcuInfo = RbcuInfo(
|
||||||
sessionId: uuid,
|
sessionId: uuid,
|
||||||
@ -327,21 +340,28 @@ class StartChartManage {
|
|||||||
void _sendRbcuProbeMessage() async {
|
void _sendRbcuProbeMessage() async {
|
||||||
// 随机字符串数据
|
// 随机字符串数据
|
||||||
String generateRandomString(int length) {
|
String generateRandomString(int length) {
|
||||||
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
const chars =
|
||||||
|
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||||
final random = Random();
|
final random = Random();
|
||||||
return String.fromCharCodes(
|
return String.fromCharCodes(
|
||||||
List.generate(length, (index) => chars.codeUnitAt(random.nextInt(chars.length))),
|
List.generate(
|
||||||
|
length, (index) => chars.codeUnitAt(random.nextInt(chars.length))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rbcuInfo != null && rbcuInfo!.address != null && rbcuInfo!.address.length > 0) {
|
if (rbcuInfo != null &&
|
||||||
|
rbcuInfo!.address != null &&
|
||||||
|
rbcuInfo!.address.length > 0) {
|
||||||
rbcuInfo!.address.forEach((element) {
|
rbcuInfo!.address.forEach((element) {
|
||||||
// 拆分 element 字符串
|
// 拆分 element 字符串
|
||||||
final parts = element.split(':');
|
final parts = element.split(':');
|
||||||
final host = parts[0]; // IP 地址
|
final host = parts[0]; // IP 地址
|
||||||
final port = int.tryParse(parts[1]) ?? 0; // 端口号,如果解析失败则默认为 0
|
final port = int.tryParse(parts[1]) ?? 0; // 端口号,如果解析失败则默认为 0
|
||||||
|
|
||||||
final RbcuProbe rbcuProbe = RbcuProbe(sessionId: _rbcuSessionId, data: generateRandomString(100), targetAddress: element);
|
final RbcuProbe rbcuProbe = RbcuProbe(
|
||||||
|
sessionId: _rbcuSessionId,
|
||||||
|
data: generateRandomString(100),
|
||||||
|
targetAddress: element);
|
||||||
final rbcuProBeBuffer = rbcuProbe.writeToBuffer();
|
final rbcuProBeBuffer = rbcuProbe.writeToBuffer();
|
||||||
_sendNatMessage(message: rbcuProBeBuffer, host: host, port: port);
|
_sendNatMessage(message: rbcuProBeBuffer, host: host, port: port);
|
||||||
});
|
});
|
||||||
@ -358,7 +378,8 @@ class StartChartManage {
|
|||||||
// 启动定时任务
|
// 启动定时任务
|
||||||
void startSendingRbcuInfoMessages({required String ToPeerId}) {
|
void startSendingRbcuInfoMessages({required String ToPeerId}) {
|
||||||
// 每隔 1 秒执行一次 _sendRbcuInfoMessage
|
// 每隔 1 秒执行一次 _sendRbcuInfoMessage
|
||||||
rbcuInfoTimer ??= Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
rbcuInfoTimer ??=
|
||||||
|
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
||||||
// 发送RbcuInfo 地址交换消息
|
// 发送RbcuInfo 地址交换消息
|
||||||
_log(text: '发送RbcuInfo 地址交换消息');
|
_log(text: '发送RbcuInfo 地址交换消息');
|
||||||
_sendRbcuInfoMessage(ToPeerId: ToPeerId);
|
_sendRbcuInfoMessage(ToPeerId: ToPeerId);
|
||||||
@ -368,7 +389,8 @@ class StartChartManage {
|
|||||||
// 发送打洞包
|
// 发送打洞包
|
||||||
void startSendingRbcuProbeTMessages() {
|
void startSendingRbcuProbeTMessages() {
|
||||||
// 每隔 1 秒执行一次 _sendRbcuInfoMessage
|
// 每隔 1 秒执行一次 _sendRbcuInfoMessage
|
||||||
rbcuProbeTimer ??= Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
rbcuProbeTimer ??=
|
||||||
|
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
||||||
// 发送RbcuProbe
|
// 发送RbcuProbe
|
||||||
_sendRbcuProbeMessage();
|
_sendRbcuProbeMessage();
|
||||||
});
|
});
|
||||||
@ -376,7 +398,8 @@ class StartChartManage {
|
|||||||
|
|
||||||
// 发送打洞确认包
|
// 发送打洞确认包
|
||||||
void startSendingRbcuConfirmTMessages() {
|
void startSendingRbcuConfirmTMessages() {
|
||||||
rbcuConfirmTimer ??= Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
rbcuConfirmTimer ??=
|
||||||
|
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
|
||||||
// 发送RbcuProbe
|
// 发送RbcuProbe
|
||||||
_sendRbcuConfirmMessage();
|
_sendRbcuConfirmMessage();
|
||||||
});
|
});
|
||||||
@ -435,11 +458,11 @@ class StartChartManage {
|
|||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
|
final LockListInfoItemEntity currentKeyInfo =
|
||||||
|
CommonDataManage().currentKeyInfo;
|
||||||
final isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
|
final isH264 = currentKeyInfo.lockFeature?.isH264 == 1;
|
||||||
final isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
|
final isMJpeg = currentKeyInfo.lockFeature?.isMJpeg == 1;
|
||||||
AppLog.log('isH264:${isH264}');
|
|
||||||
AppLog.log('isMJpeg:${isMJpeg}');
|
|
||||||
// 优先使用H264,其次是MJPEG
|
// 优先使用H264,其次是MJPEG
|
||||||
if (isH264) {
|
if (isH264) {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
@ -460,7 +483,6 @@ class StartChartManage {
|
|||||||
seconds: _defaultIntervalTime,
|
seconds: _defaultIntervalTime,
|
||||||
),
|
),
|
||||||
(Timer timer) async {
|
(Timer timer) async {
|
||||||
AppLog.log('发送对讲请求:${ToPeerId}');
|
|
||||||
await sendCallRequestMessage(ToPeerId: ToPeerId);
|
await sendCallRequestMessage(ToPeerId: ToPeerId);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -504,7 +526,8 @@ class StartChartManage {
|
|||||||
List<int> packetTalkData = payload.sublist(start, end);
|
List<int> packetTalkData = payload.sublist(start, end);
|
||||||
|
|
||||||
// 分包数据不递增messageID
|
// 分包数据不递增messageID
|
||||||
final messageId = MessageCommand.getNextMessageId(toPeerId, increment: false);
|
final messageId =
|
||||||
|
MessageCommand.getNextMessageId(toPeerId, increment: false);
|
||||||
// 组装分包数据
|
// 组装分包数据
|
||||||
final message = MessageCommand.talkDataMessage(
|
final message = MessageCommand.talkDataMessage(
|
||||||
ToPeerId: toPeerId,
|
ToPeerId: toPeerId,
|
||||||
@ -539,7 +562,8 @@ class StartChartManage {
|
|||||||
final List<int> message = MessageCommand.heartbeatMessage(
|
final List<int> message = MessageCommand.heartbeatMessage(
|
||||||
FromPeerId: FromPeerId,
|
FromPeerId: FromPeerId,
|
||||||
ToPeerId: relayPeerId,
|
ToPeerId: relayPeerId,
|
||||||
MessageId: MessageCommand.getNextMessageId(relayPeerId, increment: true),
|
MessageId:
|
||||||
|
MessageCommand.getNextMessageId(relayPeerId, increment: true),
|
||||||
);
|
);
|
||||||
await _sendMessage(message: message);
|
await _sendMessage(message: message);
|
||||||
},
|
},
|
||||||
@ -548,7 +572,8 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送回声测试消息
|
// 发送回声测试消息
|
||||||
void sendEchoMessage({required List<int> payload, required String toPeerId}) async {
|
void sendEchoMessage(
|
||||||
|
{required List<int> payload, required String toPeerId}) async {
|
||||||
// 计算需要分多少个包发送
|
// 计算需要分多少个包发送
|
||||||
final int totalPackets = (payload.length / _maxPayloadSize).ceil();
|
final int totalPackets = (payload.length / _maxPayloadSize).ceil();
|
||||||
// 循环遍历
|
// 循环遍历
|
||||||
@ -562,7 +587,8 @@ class StartChartManage {
|
|||||||
List<int> packet = payload.sublist(start, end);
|
List<int> packet = payload.sublist(start, end);
|
||||||
|
|
||||||
// 分包数据不递增messageID
|
// 分包数据不递增messageID
|
||||||
final messageId = MessageCommand.getNextMessageId(toPeerId, increment: false);
|
final messageId =
|
||||||
|
MessageCommand.getNextMessageId(toPeerId, increment: false);
|
||||||
// 组装分包数据
|
// 组装分包数据
|
||||||
final message = MessageCommand.echoMessage(
|
final message = MessageCommand.echoMessage(
|
||||||
ToPeerId: toPeerId,
|
ToPeerId: toPeerId,
|
||||||
@ -580,14 +606,13 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送网关初始化消息
|
// 发送网关初始化消息
|
||||||
void sendGatewayResetMessage({required String ToPeerId, required int gatewayId}) async {
|
void sendGatewayResetMessage(
|
||||||
|
{required String ToPeerId, required int gatewayId}) async {
|
||||||
final message = MessageCommand.gatewayResetMessage(
|
final message = MessageCommand.gatewayResetMessage(
|
||||||
ToPeerId: ToPeerId,
|
ToPeerId: ToPeerId,
|
||||||
FromPeerId: FromPeerId,
|
FromPeerId: FromPeerId,
|
||||||
gatewayId: gatewayId,
|
gatewayId: gatewayId,
|
||||||
time: DateTime
|
time: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch ~/ 1000,
|
|
||||||
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
|
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
|
||||||
);
|
);
|
||||||
await _sendMessage(message: message);
|
await _sendMessage(message: message);
|
||||||
@ -703,7 +728,8 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送通话保持消息
|
// 发送通话保持消息
|
||||||
Future<void> sendTalkPingMessage({required String ToPeerId, required String FromPeerId}) async {
|
Future<void> sendTalkPingMessage(
|
||||||
|
{required String ToPeerId, required String FromPeerId}) async {
|
||||||
final message = MessageCommand.talkPingMessage(
|
final message = MessageCommand.talkPingMessage(
|
||||||
ToPeerId: ToPeerId,
|
ToPeerId: ToPeerId,
|
||||||
FromPeerId: FromPeerId,
|
FromPeerId: FromPeerId,
|
||||||
@ -799,9 +825,11 @@ class StartChartManage {
|
|||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
Future<void> _sendMessage({required List<int> message}) async {
|
Future<void> _sendMessage({required List<int> message}) async {
|
||||||
var result = await _udpSocket?.send(message, InternetAddress(remoteHost), remotePort);
|
var result = await _udpSocket?.send(
|
||||||
|
message, InternetAddress(remoteHost), remotePort);
|
||||||
if (result != message.length) {
|
if (result != message.length) {
|
||||||
throw StartChartMessageException('❌Udp send data error----> $result ${message.length}');
|
throw StartChartMessageException(
|
||||||
|
'❌Udp send data error----> $result ${message.length}');
|
||||||
// _udpSocket = null;
|
// _udpSocket = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,11 +846,15 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
Future<void> _sendNatMessage({required List<int> message, required String host, required int port}) async {
|
Future<void> _sendNatMessage(
|
||||||
|
{required List<int> message,
|
||||||
|
required String host,
|
||||||
|
required int port}) async {
|
||||||
_log(text: '发送nat消息');
|
_log(text: '发送nat消息');
|
||||||
var result = await _udpSocket?.send(message, InternetAddress(host), port);
|
var result = await _udpSocket?.send(message, InternetAddress(host), port);
|
||||||
if (result != message.length) {
|
if (result != message.length) {
|
||||||
throw StartChartMessageException('❌Udp send data error----> $result ${message.length}');
|
throw StartChartMessageException(
|
||||||
|
'❌Udp send data error----> $result ${message.length}');
|
||||||
// _udpSocket = null;
|
// _udpSocket = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -832,7 +864,8 @@ class StartChartManage {
|
|||||||
// 获取设备信息
|
// 获取设备信息
|
||||||
final Map<String, String> deviceInfo = await _getDeviceInfo();
|
final Map<String, String> deviceInfo = await _getDeviceInfo();
|
||||||
// 发送注册节点请求
|
// 发送注册节点请求
|
||||||
final StarChartRegisterNodeEntity response = await StartChartApi.to.starChartRegisterNode(
|
final StarChartRegisterNodeEntity response =
|
||||||
|
await StartChartApi.to.starChartRegisterNode(
|
||||||
product: _productName,
|
product: _productName,
|
||||||
model: '${deviceInfo['brand']}_${deviceInfo['model']}',
|
model: '${deviceInfo['brand']}_${deviceInfo['model']}',
|
||||||
name: '${deviceInfo['id']}',
|
name: '${deviceInfo['id']}',
|
||||||
@ -842,7 +875,8 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存星图注册节点信息至缓存
|
// 保存星图注册节点信息至缓存
|
||||||
Future<void> _saveStarChartRegisterNodeToStorage(StarChartRegisterNodeEntity starChartRegisterNodeEntity) async {
|
Future<void> _saveStarChartRegisterNodeToStorage(
|
||||||
|
StarChartRegisterNodeEntity starChartRegisterNodeEntity) async {
|
||||||
if (starChartRegisterNodeEntity != null) {
|
if (starChartRegisterNodeEntity != null) {
|
||||||
await Storage.saveStarChartRegisterNodeInfo(starChartRegisterNodeEntity);
|
await Storage.saveStarChartRegisterNodeInfo(starChartRegisterNodeEntity);
|
||||||
final LoginData? loginData = await Storage.getLoginData();
|
final LoginData? loginData = await Storage.getLoginData();
|
||||||
@ -852,7 +886,8 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存星图中继服务器信息至缓存
|
// 保存星图中继服务器信息至缓存
|
||||||
Future<void> _saveRelayInfoEntityToStorage(RelayInfoEntity relayInfoEntity) async {
|
Future<void> _saveRelayInfoEntityToStorage(
|
||||||
|
RelayInfoEntity relayInfoEntity) async {
|
||||||
if (relayInfoEntity != null) {
|
if (relayInfoEntity != null) {
|
||||||
await Storage.saveRelayInfo(relayInfoEntity);
|
await Storage.saveRelayInfo(relayInfoEntity);
|
||||||
}
|
}
|
||||||
@ -874,7 +909,8 @@ class StartChartManage {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 获取本机所有ip地址和中继返回的外网地址
|
// 获取本机所有ip地址和中继返回的外网地址
|
||||||
final List<ListenAddrData> listenAddrDataList = await _makeListenAddrDataList();
|
final List<ListenAddrData> listenAddrDataList =
|
||||||
|
await _makeListenAddrDataList();
|
||||||
|
|
||||||
//
|
//
|
||||||
final RelayServiceData relayServiceData = RelayServiceData(
|
final RelayServiceData relayServiceData = RelayServiceData(
|
||||||
@ -941,12 +977,11 @@ class StartChartManage {
|
|||||||
String ipAddress = address.address;
|
String ipAddress = address.address;
|
||||||
// 移除 IPv6 地址中的接口标识符(如果有)
|
// 移除 IPv6 地址中的接口标识符(如果有)
|
||||||
if (ipAddress.contains('%')) {
|
if (ipAddress.contains('%')) {
|
||||||
ipAddress = ipAddress
|
ipAddress = ipAddress.split('%').first;
|
||||||
.split('%')
|
|
||||||
.first;
|
|
||||||
}
|
}
|
||||||
// 确保 IP 地址不为空且不在排除列表中
|
// 确保 IP 地址不为空且不在排除列表中
|
||||||
if (ipAddress.isNotEmpty && !IpConstant.reportExcludeIp.contains(ipAddress)) {
|
if (ipAddress.isNotEmpty &&
|
||||||
|
!IpConstant.reportExcludeIp.contains(ipAddress)) {
|
||||||
ipAddresses.add(ipAddress);
|
ipAddresses.add(ipAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -963,7 +998,8 @@ class StartChartManage {
|
|||||||
|
|
||||||
/// 获取设备信息
|
/// 获取设备信息
|
||||||
Future<Map<String, String>> _getDeviceInfo() async {
|
Future<Map<String, String>> _getDeviceInfo() async {
|
||||||
final Map<String, String> deviceInfo = await DeviceInfoUtils.getDeviceInfo();
|
final Map<String, String> deviceInfo =
|
||||||
|
await DeviceInfoUtils.getDeviceInfo();
|
||||||
return deviceInfo;
|
return deviceInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -980,7 +1016,8 @@ class StartChartManage {
|
|||||||
if (host != null && port != null) {
|
if (host != null && port != null) {
|
||||||
try {
|
try {
|
||||||
// 尝试进行 DNS 解析
|
// 尝试进行 DNS 解析
|
||||||
final List<InternetAddress> addresses = await InternetAddress.lookup(host);
|
final List<InternetAddress> addresses =
|
||||||
|
await InternetAddress.lookup(host);
|
||||||
if (addresses.isEmpty) {
|
if (addresses.isEmpty) {
|
||||||
throw FormatException('DNS resolution failed for $host');
|
throw FormatException('DNS resolution failed for $host');
|
||||||
}
|
}
|
||||||
@ -1045,7 +1082,8 @@ class StartChartManage {
|
|||||||
final int payloadType = scpMessage.PayloadType ?? 0;
|
final int payloadType = scpMessage.PayloadType ?? 0;
|
||||||
final int messageType = scpMessage.MessageType ?? 0;
|
final int messageType = scpMessage.MessageType ?? 0;
|
||||||
try {
|
try {
|
||||||
final ScpMessageHandler handler = ScpMessageHandlerFactory.createHandler(payloadType);
|
final ScpMessageHandler handler =
|
||||||
|
ScpMessageHandlerFactory.createHandler(payloadType);
|
||||||
if (messageType == MessageTypeConstant.Req) {
|
if (messageType == MessageTypeConstant.Req) {
|
||||||
handler.handleReq(scpMessage);
|
handler.handleReq(scpMessage);
|
||||||
} else if (messageType == MessageTypeConstant.Resp) {
|
} else if (messageType == MessageTypeConstant.Resp) {
|
||||||
@ -1132,18 +1170,10 @@ class StartChartManage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 修改预期接收到的数据
|
/// 修改预期接收到的数据
|
||||||
void changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer({required TalkExpectReq talkExpect}) {
|
void changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(
|
||||||
|
{required TalkExpectReq talkExpect}) {
|
||||||
_defaultTalkExpect = talkExpect;
|
_defaultTalkExpect = talkExpect;
|
||||||
sendTalkExpectMessage(
|
reStartTalkExpectMessageTimer();
|
||||||
talkExpect: _defaultTalkExpect,
|
|
||||||
);
|
|
||||||
sendTalkExpectMessage(
|
|
||||||
talkExpect: _defaultTalkExpect,
|
|
||||||
);
|
|
||||||
sendTalkExpectMessage(
|
|
||||||
talkExpect: _defaultTalkExpect,
|
|
||||||
);
|
|
||||||
// reStartTalkExpectMessageTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reSetDefaultTalkExpect() {
|
void reSetDefaultTalkExpect() {
|
||||||
@ -1160,7 +1190,8 @@ class StartChartManage {
|
|||||||
videoType: [VideoTypeE.IMAGE],
|
videoType: [VideoTypeE.IMAGE],
|
||||||
audioType: [],
|
audioType: [],
|
||||||
);
|
);
|
||||||
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq);
|
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(
|
||||||
|
talkExpect: talkExpectReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 修改预期接收到的数据
|
/// 修改预期接收到的数据
|
||||||
@ -1169,17 +1200,20 @@ class StartChartManage {
|
|||||||
videoType: [VideoTypeE.H264],
|
videoType: [VideoTypeE.H264],
|
||||||
audioType: [],
|
audioType: [],
|
||||||
);
|
);
|
||||||
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq);
|
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(
|
||||||
|
talkExpect: talkExpectReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 修改预期接收到的数据
|
/// 修改预期接收到的数据
|
||||||
void sendImageVideoAndG711AudioTalkExpectData() {
|
void sendImageVideoAndG711AudioTalkExpectData() {
|
||||||
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: TalkConstant.ImageExpect);
|
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(
|
||||||
|
talkExpect: TalkConstant.ImageExpect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 修改预期接收到的数据
|
/// 修改预期接收到的数据
|
||||||
void sendH264VideoAndG711AudioTalkExpectData() {
|
void sendH264VideoAndG711AudioTalkExpectData() {
|
||||||
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: TalkConstant.H264Expect);
|
changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(
|
||||||
|
talkExpect: TalkConstant.H264Expect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 发送远程开锁
|
/// 发送远程开锁
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class _PermissionGuidancePageState extends State<PermissionGuidancePage> {
|
|||||||
|
|
||||||
final List<Map<String, String>> _stepsData = [
|
final List<Map<String, String>> _stepsData = [
|
||||||
{
|
{
|
||||||
'image': 'images/guide/1.png',
|
'image': 'images/guide/matter.png',
|
||||||
'text': '步骤1:打开应用信息,点击通知管理选项',
|
'text': '步骤1:打开应用信息,点击通知管理选项',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -26,7 +26,7 @@ class _PermissionGuidancePageState extends State<PermissionGuidancePage> {
|
|||||||
'text': '步骤2:下滑点击呼叫提醒的通知选项',
|
'text': '步骤2:下滑点击呼叫提醒的通知选项',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'image': 'images/guide/3.png',
|
'image': 'images/guide/tuya.png',
|
||||||
'text': '步骤3:选择在锁定屏幕上的选项设置',
|
'text': '步骤3:选择在锁定屏幕上的选项设置',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -104,6 +104,10 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
codecType: 'h264',
|
codecType: 'h264',
|
||||||
);
|
);
|
||||||
// 初始化解码器并获取textureId
|
// 初始化解码器并获取textureId
|
||||||
|
AppLog.log(
|
||||||
|
'StartChartManage().videoWidth:${StartChartManage().videoWidth}');
|
||||||
|
AppLog.log(
|
||||||
|
'StartChartManage().videoHeight:${StartChartManage().videoHeight}');
|
||||||
final textureId = await VideoDecodePlugin.initDecoder(config);
|
final textureId = await VideoDecodePlugin.initDecoder(config);
|
||||||
if (textureId != null) {
|
if (textureId != null) {
|
||||||
Future.microtask(() => state.textureId.value = textureId);
|
Future.microtask(() => state.textureId.value = textureId);
|
||||||
@ -168,11 +172,15 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
ScpMessage scpMessage,
|
ScpMessage scpMessage,
|
||||||
) {
|
) {
|
||||||
// 动态回绕阈值判断,frameSeq较小时阈值也小
|
// 动态回绕阈值判断,frameSeq较小时阈值也小
|
||||||
if (!_pendingStreamReset && _lastFrameSeq != null && frameType == TalkDataH264Frame_FrameTypeE.I && frameSeq < _lastFrameSeq!) {
|
if (!_pendingStreamReset &&
|
||||||
|
_lastFrameSeq != null &&
|
||||||
|
frameType == TalkDataH264Frame_FrameTypeE.I &&
|
||||||
|
frameSeq < _lastFrameSeq!) {
|
||||||
int dynamicThreshold = _getFrameSeqRolloverThreshold(_lastFrameSeq!);
|
int dynamicThreshold = _getFrameSeqRolloverThreshold(_lastFrameSeq!);
|
||||||
if ((_lastFrameSeq! - frameSeq) > dynamicThreshold) {
|
if ((_lastFrameSeq! - frameSeq) > dynamicThreshold) {
|
||||||
// 检测到新流I帧,frameSeq大幅回绕,进入loading并重置所有本地状态
|
// 检测到新流I帧,frameSeq大幅回绕,进入loading并重置所有本地状态
|
||||||
AppLog.log('检测到新流I帧,frameSeq大幅回绕,进入loading并重置: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq, 阈值=$dynamicThreshold');
|
AppLog.log(
|
||||||
|
'检测到新流I帧,frameSeq大幅回绕,进入loading并重置: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq, 阈值=$dynamicThreshold');
|
||||||
Future.microtask(() => state.isLoading.value = true);
|
Future.microtask(() => state.isLoading.value = true);
|
||||||
_pendingStreamReset = true;
|
_pendingStreamReset = true;
|
||||||
// 先暂停帧处理定时器,防止竞态
|
// 先暂停帧处理定时器,防止竞态
|
||||||
@ -189,7 +197,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
// 继续往下执行
|
// 继续往下执行
|
||||||
} else {
|
} else {
|
||||||
// 小幅度乱序,直接丢弃
|
// 小幅度乱序,直接丢弃
|
||||||
AppLog.log('检测到I帧乱序(未超过回绕阈值$dynamicThreshold),丢弃: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq');
|
AppLog.log(
|
||||||
|
'检测到I帧乱序(未超过回绕阈值$dynamicThreshold),丢弃: frameSeq=$frameSeq, lastFrameSeq=$_lastFrameSeq');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,7 +238,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 如果缓冲区超出最大大小,优先丢弃P/B帧
|
// 如果缓冲区超出最大大小,优先丢弃P/B帧
|
||||||
while (state.h264FrameBuffer.length >= state.maxFrameBufferSize) {
|
while (state.h264FrameBuffer.length >= state.maxFrameBufferSize) {
|
||||||
int pbIndex = state.h264FrameBuffer.indexWhere((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.P);
|
int pbIndex = state.h264FrameBuffer
|
||||||
|
.indexWhere((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.P);
|
||||||
if (pbIndex != -1) {
|
if (pbIndex != -1) {
|
||||||
state.h264FrameBuffer.removeAt(pbIndex);
|
state.h264FrameBuffer.removeAt(pbIndex);
|
||||||
} else {
|
} else {
|
||||||
@ -250,17 +260,15 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
final int intervalMs = (1000 / state.targetFps).round();
|
final int intervalMs = (1000 / state.targetFps).round();
|
||||||
|
|
||||||
// 创建新定时器
|
// 创建新定时器
|
||||||
state.frameProcessTimer = Timer.periodic(Duration(milliseconds: intervalMs), (timer) {
|
state.frameProcessTimer =
|
||||||
|
Timer.periodic(Duration(milliseconds: intervalMs), (timer) {
|
||||||
_processNextFrameFromBuffer();
|
_processNextFrameFromBuffer();
|
||||||
});
|
});
|
||||||
AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps,间隔: ${intervalMs}ms');
|
AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps,间隔: ${intervalMs}ms');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 从缓冲区处理下一帧
|
|
||||||
/// 从缓冲区处理下一帧
|
/// 从缓冲区处理下一帧
|
||||||
void _processNextFrameFromBuffer() async {
|
void _processNextFrameFromBuffer() async {
|
||||||
final startTime = DateTime.now().microsecondsSinceEpoch;
|
|
||||||
|
|
||||||
// 避免重复处理
|
// 避免重复处理
|
||||||
if (state.isProcessingFrame) {
|
if (state.isProcessingFrame) {
|
||||||
return;
|
return;
|
||||||
@ -271,19 +279,25 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
// 优先查找I帧,按frameSeq最小的I帧消费
|
// 优先查找I帧,按frameSeq最小的I帧消费
|
||||||
final iFrames = state.h264FrameBuffer.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I).toList();
|
final iFrames = state.h264FrameBuffer
|
||||||
iFrames.sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I)
|
||||||
|
.toList();
|
||||||
|
iFrames
|
||||||
|
.sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
||||||
|
|
||||||
if (iFrames.isNotEmpty) {
|
if (iFrames.isNotEmpty) {
|
||||||
|
// 有I帧,消费最小的I帧,并记录其frameSeq
|
||||||
final minIFrame = iFrames.first;
|
final minIFrame = iFrames.first;
|
||||||
final minIFrameSeq = minIFrame['frameSeq'];
|
final minIFrameSeq = minIFrame['frameSeq'];
|
||||||
final targetIndex = state.h264FrameBuffer.indexWhere(
|
final targetIndex = state.h264FrameBuffer.indexWhere(
|
||||||
(f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I && f['frameSeq'] == minIFrameSeq,
|
(f) =>
|
||||||
|
f['frameType'] == TalkDataH264Frame_FrameTypeE.I &&
|
||||||
|
f['frameSeq'] == minIFrameSeq,
|
||||||
);
|
);
|
||||||
state.isProcessingFrame = true;
|
state.isProcessingFrame = true;
|
||||||
final Map<String, dynamic>? frameMap = state.h264FrameBuffer.removeAt(targetIndex);
|
final Map<String, dynamic>? frameMap =
|
||||||
|
state.h264FrameBuffer.removeAt(targetIndex);
|
||||||
if (frameMap == null) {
|
if (frameMap == null) {
|
||||||
state.isProcessingFrame = false;
|
state.isProcessingFrame = false;
|
||||||
return;
|
return;
|
||||||
@ -293,7 +307,12 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
final int? frameSeq = frameMap['frameSeq'];
|
final int? frameSeq = frameMap['frameSeq'];
|
||||||
final int? frameSeqI = frameMap['frameSeqI'];
|
final int? frameSeqI = frameMap['frameSeqI'];
|
||||||
final int? pts = frameMap['pts'];
|
final int? pts = frameMap['pts'];
|
||||||
if (frameData == null || frameType == null || frameSeq == null || frameSeqI == null || pts == null) {
|
final ScpMessage? scpMessage = frameMap['scpMessage'];
|
||||||
|
if (frameData == null ||
|
||||||
|
frameType == null ||
|
||||||
|
frameSeq == null ||
|
||||||
|
frameSeqI == null ||
|
||||||
|
pts == null) {
|
||||||
state.isProcessingFrame = false;
|
state.isProcessingFrame = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -302,7 +321,11 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastDecodedIFrameSeq = minIFrameSeq;
|
lastDecodedIFrameSeq = minIFrameSeq;
|
||||||
|
// AppLog.log('送入解码器的P帧数据frameSeq:${frameSeq},frameSeqI:${frameSeqI},'
|
||||||
|
// 'frameType:${frameType},messageId:${scpMessage!.MessageId}');
|
||||||
|
// final spsData = NaluUtils.filterNalusByType(frameData, 7);
|
||||||
|
// final ppsData = NaluUtils.filterNalusByType(frameData, 8);
|
||||||
|
// AppLog.log('SPSDATA:${spsData},ppsData:${ppsData}');
|
||||||
await VideoDecodePlugin.sendFrame(
|
await VideoDecodePlugin.sendFrame(
|
||||||
frameData: frameData,
|
frameData: frameData,
|
||||||
frameType: 0,
|
frameType: 0,
|
||||||
@ -317,17 +340,24 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 没有I帧时,只消费refIFrameSeq等于lastDecodedIFrameSeq的P帧
|
// 没有I帧时,只消费refIFrameSeq等于lastDecodedIFrameSeq的P帧
|
||||||
if (lastDecodedIFrameSeq != null) {
|
if (lastDecodedIFrameSeq != null) {
|
||||||
final validPFrames =
|
final validPFrames = state.h264FrameBuffer
|
||||||
state.h264FrameBuffer.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.P && f['frameSeqI'] == lastDecodedIFrameSeq).toList();
|
.where((f) =>
|
||||||
|
f['frameType'] == TalkDataH264Frame_FrameTypeE.P &&
|
||||||
|
f['frameSeqI'] == lastDecodedIFrameSeq)
|
||||||
|
.toList();
|
||||||
if (validPFrames.isNotEmpty) {
|
if (validPFrames.isNotEmpty) {
|
||||||
validPFrames.sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
validPFrames.sort(
|
||||||
|
(a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
||||||
final minPFrame = validPFrames.first;
|
final minPFrame = validPFrames.first;
|
||||||
final targetIndex = state.h264FrameBuffer.indexWhere(
|
final targetIndex = state.h264FrameBuffer.indexWhere(
|
||||||
(f) =>
|
(f) =>
|
||||||
f['frameType'] == TalkDataH264Frame_FrameTypeE.P && f['frameSeq'] == minPFrame['frameSeq'] && f['frameSeqI'] == lastDecodedIFrameSeq,
|
f['frameType'] == TalkDataH264Frame_FrameTypeE.P &&
|
||||||
|
f['frameSeq'] == minPFrame['frameSeq'] &&
|
||||||
|
f['frameSeqI'] == lastDecodedIFrameSeq,
|
||||||
);
|
);
|
||||||
state.isProcessingFrame = true;
|
state.isProcessingFrame = true;
|
||||||
final Map<String, dynamic>? frameMap = state.h264FrameBuffer.removeAt(targetIndex);
|
final Map<String, dynamic>? frameMap =
|
||||||
|
state.h264FrameBuffer.removeAt(targetIndex);
|
||||||
if (frameMap == null) {
|
if (frameMap == null) {
|
||||||
state.isProcessingFrame = false;
|
state.isProcessingFrame = false;
|
||||||
return;
|
return;
|
||||||
@ -337,7 +367,12 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
final int? frameSeq = frameMap['frameSeq'];
|
final int? frameSeq = frameMap['frameSeq'];
|
||||||
final int? frameSeqI = frameMap['frameSeqI'];
|
final int? frameSeqI = frameMap['frameSeqI'];
|
||||||
final int? pts = frameMap['pts'];
|
final int? pts = frameMap['pts'];
|
||||||
if (frameData == null || frameType == null || frameSeq == null || frameSeqI == null || pts == null) {
|
final ScpMessage? scpMessage = frameMap['scpMessage'];
|
||||||
|
if (frameData == null ||
|
||||||
|
frameType == null ||
|
||||||
|
frameSeq == null ||
|
||||||
|
frameSeqI == null ||
|
||||||
|
pts == null) {
|
||||||
state.isProcessingFrame = false;
|
state.isProcessingFrame = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -345,6 +380,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
state.isProcessingFrame = false;
|
state.isProcessingFrame = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// AppLog.log('送入解码器的I帧数据frameSeq:${frameSeq},frameSeqI:${frameSeqI},'
|
||||||
|
// 'frameType:${frameType},messageId:${scpMessage!.MessageId}');
|
||||||
|
|
||||||
await VideoDecodePlugin.sendFrame(
|
await VideoDecodePlugin.sendFrame(
|
||||||
frameData: frameData,
|
frameData: frameData,
|
||||||
@ -359,16 +396,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 其他情况不消费,等待I帧到来
|
// 其他情况不消费,等待I帧到来
|
||||||
} finally {
|
|
||||||
final endTime = DateTime.now().microsecondsSinceEpoch;
|
|
||||||
final durationMs = (endTime - startTime) / 1000.0;
|
|
||||||
// 可选:只在耗时较长时打印(例如 > 5ms)
|
|
||||||
if (durationMs > 5) {
|
|
||||||
debugPrint('[_processNextFrameFromBuffer] 耗时: ${durationMs.toStringAsFixed(2)} ms');
|
|
||||||
// 或使用你的日志系统,如:
|
|
||||||
// AppLog.log('Frame processing took ${durationMs.toStringAsFixed(2)} ms');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 停止帧处理定时器
|
/// 停止帧处理定时器
|
||||||
@ -400,7 +427,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
AppLog.log("==== 启动新的数据流监听 ====");
|
AppLog.log("==== 启动新的数据流监听 ====");
|
||||||
_isListening = true;
|
_isListening = true;
|
||||||
|
|
||||||
_streamSubscription = state.talkDataRepository.talkDataStream.listen((TalkDataModel talkDataModel) async {
|
_streamSubscription = state.talkDataRepository.talkDataStream
|
||||||
|
.listen((TalkDataModel talkDataModel) async {
|
||||||
_processFrame(talkDataModel);
|
_processFrame(talkDataModel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -409,7 +437,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
void _playAudioFrames() {
|
void _playAudioFrames() {
|
||||||
// 如果缓冲区为空或未达到目标大小,不进行播放
|
// 如果缓冲区为空或未达到目标大小,不进行播放
|
||||||
// 音频缓冲区要求更小,以减少延迟
|
// 音频缓冲区要求更小,以减少延迟
|
||||||
if (state.audioBuffer.isEmpty || state.audioBuffer.length < audioBufferSize) {
|
if (state.audioBuffer.isEmpty ||
|
||||||
|
state.audioBuffer.length < audioBufferSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +446,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
TalkData? oldestFrame;
|
TalkData? oldestFrame;
|
||||||
int oldestIndex = -1;
|
int oldestIndex = -1;
|
||||||
for (int i = 0; i < state.audioBuffer.length; i++) {
|
for (int i = 0; i < state.audioBuffer.length; i++) {
|
||||||
if (oldestFrame == null || state.audioBuffer[i].durationMs < oldestFrame.durationMs) {
|
if (oldestFrame == null ||
|
||||||
|
state.audioBuffer[i].durationMs < oldestFrame.durationMs) {
|
||||||
oldestFrame = state.audioBuffer[i];
|
oldestFrame = state.audioBuffer[i];
|
||||||
oldestIndex = i;
|
oldestIndex = i;
|
||||||
}
|
}
|
||||||
@ -447,7 +477,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
break;
|
break;
|
||||||
case TalkStatus.answeredSuccessfully:
|
case TalkStatus.answeredSuccessfully:
|
||||||
state.oneMinuteTimeTimer?.cancel(); // 取消旧定时器
|
state.oneMinuteTimeTimer?.cancel(); // 取消旧定时器
|
||||||
state.oneMinuteTimeTimer ??= Timer.periodic(const Duration(seconds: 1), (Timer t) {
|
state.oneMinuteTimeTimer ??=
|
||||||
|
Timer.periodic(const Duration(seconds: 1), (Timer t) {
|
||||||
if (state.isLoading.isFalse) {
|
if (state.isLoading.isFalse) {
|
||||||
state.oneMinuteTime.value++;
|
state.oneMinuteTime.value++;
|
||||||
}
|
}
|
||||||
@ -462,7 +493,9 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
|
|
||||||
/// 播放音频数据
|
/// 播放音频数据
|
||||||
void _playAudioData(TalkData talkData) async {
|
void _playAudioData(TalkData talkData) async {
|
||||||
if (state.isOpenVoice.value && state.isLoading.isFalse && state.isRecordingAudio.value == false) {
|
if (state.isOpenVoice.value &&
|
||||||
|
state.isLoading.isFalse &&
|
||||||
|
state.isRecordingAudio.value == false) {
|
||||||
List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0表示A-law
|
List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0表示A-law
|
||||||
// 将 PCM 数据转换为 PcmArrayInt16
|
// 将 PCM 数据转换为 PcmArrayInt16
|
||||||
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData);
|
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData);
|
||||||
@ -637,9 +670,11 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
AppLog.log('截图失败: 未找到当前上下文');
|
AppLog.log('截图失败: 未找到当前上下文');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final RenderRepaintBoundary boundary = state.globalKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
|
final RenderRepaintBoundary boundary = state.globalKey.currentContext!
|
||||||
|
.findRenderObject()! as RenderRepaintBoundary;
|
||||||
final ui.Image image = await boundary.toImage();
|
final ui.Image image = await boundary.toImage();
|
||||||
final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
|
final ByteData? byteData =
|
||||||
|
await image.toByteData(format: ui.ImageByteFormat.png);
|
||||||
|
|
||||||
if (byteData == null) {
|
if (byteData == null) {
|
||||||
AppLog.log('截图失败: 图像数据为空');
|
AppLog.log('截图失败: 图像数据为空');
|
||||||
@ -667,13 +702,15 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 远程开锁
|
// 远程开锁
|
||||||
Future<void> remoteOpenLock() async {
|
Future<void> remoteOpenLock() async {
|
||||||
final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
|
final LockListInfoItemEntity currentKeyInfo =
|
||||||
|
CommonDataManage().currentKeyInfo;
|
||||||
|
|
||||||
var lockId = currentKeyInfo.lockId ?? 0;
|
var lockId = currentKeyInfo.lockId ?? 0;
|
||||||
var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0;
|
var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0;
|
||||||
|
|
||||||
final lockPeerId = StartChartManage().lockPeerId;
|
final lockPeerId = StartChartManage().lockPeerId;
|
||||||
final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
|
final LockListInfoGroupEntity? lockListInfoGroupEntity =
|
||||||
|
await Storage.getLockMainListData();
|
||||||
if (lockListInfoGroupEntity != null) {
|
if (lockListInfoGroupEntity != null) {
|
||||||
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
lockListInfoGroupEntity!.groupList?.forEach((element) {
|
||||||
final lockList = element.lockList;
|
final lockList = element.lockList;
|
||||||
@ -691,7 +728,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (remoteUnlock == 1) {
|
if (remoteUnlock == 1) {
|
||||||
final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
|
final LoginEntity entity = await ApiRepository.to
|
||||||
|
.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
|
||||||
if (entity.errorCode!.codeIsSuccessful) {
|
if (entity.errorCode!.codeIsSuccessful) {
|
||||||
showToast('已开锁'.tr);
|
showToast('已开锁'.tr);
|
||||||
StartChartManage().lockListPeerId = [];
|
StartChartManage().lockListPeerId = [];
|
||||||
@ -718,7 +756,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
state.startRecordingAudioTime.value = DateTime.now();
|
state.startRecordingAudioTime.value = DateTime.now();
|
||||||
|
|
||||||
// 增加录音帧监听器和错误监听器
|
// 增加录音帧监听器和错误监听器
|
||||||
state.voiceProcessor?.addFrameListeners(<VoiceProcessorFrameListener>[_onFrame]);
|
state.voiceProcessor
|
||||||
|
?.addFrameListeners(<VoiceProcessorFrameListener>[_onFrame]);
|
||||||
state.voiceProcessor?.addErrorListener(_onError);
|
state.voiceProcessor?.addErrorListener(_onError);
|
||||||
} else {
|
} else {
|
||||||
// state.errorMessage.value = 'Recording permission not granted';
|
// state.errorMessage.value = 'Recording permission not granted';
|
||||||
@ -738,7 +777,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
state.endRecordingAudioTime.value = DateTime.now();
|
state.endRecordingAudioTime.value = DateTime.now();
|
||||||
|
|
||||||
// 计算录音的持续时间
|
// 计算录音的持续时间
|
||||||
final Duration duration = state.endRecordingAudioTime.value.difference(state.startRecordingAudioTime.value);
|
final Duration duration = state.endRecordingAudioTime.value
|
||||||
|
.difference(state.startRecordingAudioTime.value);
|
||||||
|
|
||||||
state.recordingAudioTime.value = duration.inSeconds;
|
state.recordingAudioTime.value = duration.inSeconds;
|
||||||
} on PlatformException catch (ex) {
|
} on PlatformException catch (ex) {
|
||||||
@ -808,8 +848,10 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
_bufferedAudioFrames.addAll(encodedData);
|
_bufferedAudioFrames.addAll(encodedData);
|
||||||
|
|
||||||
// 启动定时发送器(仅启动一次)
|
// 启动定时发送器(仅启动一次)
|
||||||
if (_startProcessingAudioTimer == null && _bufferedAudioFrames.length > chunkSize) {
|
if (_startProcessingAudioTimer == null &&
|
||||||
_startProcessingAudioTimer = Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
|
_bufferedAudioFrames.length > chunkSize) {
|
||||||
|
_startProcessingAudioTimer =
|
||||||
|
Timer.periodic(Duration(milliseconds: intervalMs), _sendAudioChunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,7 +887,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 修改发送预期数据
|
/// 修改发送预期数据
|
||||||
StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq);
|
StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(
|
||||||
|
talkExpect: talkExpectReq);
|
||||||
|
|
||||||
// 不立即loading,继续解码旧流帧,等待frameSeq回绕检测
|
// 不立即loading,继续解码旧流帧,等待frameSeq回绕检测
|
||||||
// 仅重置frameSeq回绕检测标志
|
// 仅重置frameSeq回绕检测标志
|
||||||
|
|||||||
@ -29,12 +29,15 @@ class TalkViewNativeDecodePage extends StatefulWidget {
|
|||||||
const TalkViewNativeDecodePage({Key? key}) : super(key: key);
|
const TalkViewNativeDecodePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<TalkViewNativeDecodePage> createState() => _TalkViewNativeDecodePageState();
|
State<TalkViewNativeDecodePage> createState() =>
|
||||||
|
_TalkViewNativeDecodePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> with TickerProviderStateMixin {
|
class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic());
|
final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic());
|
||||||
final TalkViewNativeDecodeState state = Get.find<TalkViewNativeDecodeLogic>().state;
|
final TalkViewNativeDecodeState state =
|
||||||
|
Get.find<TalkViewNativeDecodeLogic>().state;
|
||||||
final startChartManage = StartChartManage();
|
final startChartManage = StartChartManage();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -66,39 +69,56 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
// 返回 false 表示禁止退出
|
// 返回 false 表示禁止退出
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
child: Container(
|
child: SizedBox(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
height: 1.sh,
|
height: 1.sh,
|
||||||
color: Colors.black.withOpacity(0.7),
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
// 悬浮帧率统计信息条
|
// 悬浮帧率统计信息条
|
||||||
Obx(
|
Obx(
|
||||||
() {
|
() {
|
||||||
|
final double screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
final double screenHeight = MediaQuery.of(context).size.height;
|
||||||
|
|
||||||
|
final double logicalWidth = MediaQuery.of(context).size.width;
|
||||||
|
final double logicalHeight = MediaQuery.of(context).size.height;
|
||||||
|
final double devicePixelRatio =
|
||||||
|
MediaQuery.of(context).devicePixelRatio;
|
||||||
|
|
||||||
|
// 计算物理像素值
|
||||||
|
final double physicalWidth = logicalWidth * devicePixelRatio;
|
||||||
|
final double physicalHeight = logicalHeight * devicePixelRatio;
|
||||||
|
|
||||||
|
// 旋转后的图片尺寸
|
||||||
|
const int rotatedImageWidth = 480; // 原始高度
|
||||||
|
const int rotatedImageHeight = 864; // 原始宽度
|
||||||
|
|
||||||
|
// 计算缩放比例
|
||||||
|
final double scaleWidth = physicalWidth / rotatedImageWidth;
|
||||||
|
final double scaleHeight = physicalHeight / rotatedImageHeight;
|
||||||
|
max(scaleWidth, scaleHeight); // 选择较大的缩放比例
|
||||||
// 防御性处理:只要loading中或textureId为null,优先渲染loading/占位
|
// 防御性处理:只要loading中或textureId为null,优先渲染loading/占位
|
||||||
if (state.isLoading.isTrue || state.textureId.value == null) {
|
if (state.isLoading.isTrue || state.textureId.value == null) {
|
||||||
return Image.asset(
|
return Image.asset(
|
||||||
'images/main/monitorBg.png',
|
'images/main/monitorBg.png',
|
||||||
width: 1.sw,
|
width: screenWidth,
|
||||||
height: 1.sh,
|
height: screenHeight,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Positioned(
|
return Positioned.fill(
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: PopScope(
|
child: PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
key: state.globalKey,
|
key: state.globalKey,
|
||||||
|
child: SizedBox.expand(
|
||||||
child: RotatedBox(
|
child: RotatedBox(
|
||||||
// 解码器不支持硬件旋转,使用RotatedBox
|
// 解码器不支持硬件旋转,使用RotatedBox
|
||||||
quarterTurns: startChartManage.rotateAngle ~/ 90,
|
quarterTurns: startChartManage.rotateAngle ~/ 90,
|
||||||
child: state.isFullScreen.isFalse
|
child: Platform.isIOS
|
||||||
? AspectRatio(
|
? Transform.scale(
|
||||||
aspectRatio: StartChartManage().videoWidth / StartChartManage().videoHeight,
|
scale: 1.008, // 轻微放大,消除iOS白边
|
||||||
child: Texture(
|
child: Texture(
|
||||||
textureId: state.textureId.value!,
|
textureId: state.textureId.value!,
|
||||||
filterQuality: FilterQuality.medium,
|
filterQuality: FilterQuality.medium,
|
||||||
@ -111,6 +131,7 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -130,14 +151,19 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() {
|
() {
|
||||||
final String sec = (state.oneMinuteTime.value % 60).toString().padLeft(2, '0');
|
final String sec = (state.oneMinuteTime.value % 60)
|
||||||
final String min = (state.oneMinuteTime.value ~/ 60).toString().padLeft(2, '0');
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
|
final String min = (state.oneMinuteTime.value ~/ 60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0');
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
'$min:$sec',
|
'$min:$sec',
|
||||||
style: TextStyle(fontSize: 26.sp, color: Colors.white),
|
style: TextStyle(
|
||||||
|
fontSize: 26.sp, color: Colors.white),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -151,7 +177,9 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
width: 1.sw - 30.w * 2,
|
width: 1.sw - 30.w * 2,
|
||||||
// height: 300.h,
|
// height: 300.h,
|
||||||
margin: EdgeInsets.all(30.w),
|
margin: EdgeInsets.all(30.w),
|
||||||
decoration: BoxDecoration(color: Colors.black.withOpacity(0.2), borderRadius: BorderRadius.circular(20.h)),
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black.withOpacity(0.2),
|
||||||
|
borderRadius: BorderRadius.circular(20.h)),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SizedBox(height: 20.h),
|
SizedBox(height: 20.h),
|
||||||
@ -163,7 +191,9 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() => state.isLoading.isTrue ? buildRotationTransition() : Container()),
|
Obx(() => state.isLoading.isTrue
|
||||||
|
? buildRotationTransition()
|
||||||
|
: Container()),
|
||||||
Obx(() => state.isLongPressing.value
|
Obx(() => state.isLongPressing.value
|
||||||
? Positioned(
|
? Positioned(
|
||||||
top: 80.h,
|
top: 80.h,
|
||||||
@ -183,7 +213,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
SizedBox(width: 10.w),
|
SizedBox(width: 10.w),
|
||||||
Text(
|
Text(
|
||||||
'正在说话...'.tr,
|
'正在说话...'.tr,
|
||||||
style: TextStyle(fontSize: 20.sp, color: Colors.white),
|
style: TextStyle(
|
||||||
|
fontSize: 20.sp, color: Colors.white),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -215,8 +246,10 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
width: 40.w,
|
width: 40.w,
|
||||||
height: 40.w,
|
height: 40.w,
|
||||||
image: state.isOpenVoice.value
|
image: state.isOpenVoice.value
|
||||||
? const AssetImage('images/main/icon_lockDetail_monitoringOpenVoice.png')
|
? const AssetImage(
|
||||||
: const AssetImage('images/main/icon_lockDetail_monitoringCloseVoice.png'))),
|
'images/main/icon_lockDetail_monitoringOpenVoice.png')
|
||||||
|
: const AssetImage(
|
||||||
|
'images/main/icon_lockDetail_monitoringCloseVoice.png'))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 50.w),
|
SizedBox(width: 50.w),
|
||||||
@ -231,7 +264,11 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
width: 50.w,
|
width: 50.w,
|
||||||
height: 50.w,
|
height: 50.w,
|
||||||
padding: EdgeInsets.all(5.w),
|
padding: EdgeInsets.all(5.w),
|
||||||
child: Image(width: 40.w, height: 40.w, image: const AssetImage('images/main/icon_lockDetail_monitoringScreenshot.png')),
|
child: Image(
|
||||||
|
width: 40.w,
|
||||||
|
height: 40.w,
|
||||||
|
image: const AssetImage(
|
||||||
|
'images/main/icon_lockDetail_monitoringScreenshot.png')),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 50.w),
|
SizedBox(width: 50.w),
|
||||||
@ -256,7 +293,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
width: 40.w,
|
width: 40.w,
|
||||||
height: 40.w,
|
height: 40.w,
|
||||||
fit: BoxFit.fill,
|
fit: BoxFit.fill,
|
||||||
image: const AssetImage('images/main/icon_lockDetail_monitoringScreenRecording.png'),
|
image: const AssetImage(
|
||||||
|
'images/main/icon_lockDetail_monitoringScreenRecording.png'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -292,8 +330,13 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
Text(
|
Text(
|
||||||
q,
|
q,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: state.currentQuality.value == q ? AppColors.mainColor : Colors.black,
|
color: state.currentQuality.value == q
|
||||||
fontWeight: state.currentQuality.value == q ? FontWeight.bold : FontWeight.normal,
|
? AppColors.mainColor
|
||||||
|
: Colors.black,
|
||||||
|
fontWeight:
|
||||||
|
state.currentQuality.value == q
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
fontSize: 28.sp,
|
fontSize: 28.sp,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -309,7 +352,8 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
child: Icon(Icons.high_quality_outlined, color: Colors.white, size: 38.w),
|
child: Icon(Icons.high_quality_outlined,
|
||||||
|
color: Colors.white, size: 38.w),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
@ -333,7 +377,9 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget bottomBottomBtnWidget() {
|
Widget bottomBottomBtnWidget() {
|
||||||
return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: <Widget>[
|
||||||
// 接听
|
// 接听
|
||||||
Obx(
|
Obx(
|
||||||
() => bottomBtnItemWidget(
|
() => bottomBtnItemWidget(
|
||||||
@ -353,14 +399,17 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
|
|||||||
state.isLongPressing.value = false;
|
state.isLongPressing.value = false;
|
||||||
},
|
},
|
||||||
onClick: () async {
|
onClick: () async {
|
||||||
if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) {
|
if (state.talkStatus.value ==
|
||||||
|
TalkStatus.passiveCallWaitingAnswer) {
|
||||||
// 接听
|
// 接听
|
||||||
logic.initiateAnswerCommand();
|
logic.initiateAnswerCommand();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomBtnItemWidget('images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red, onClick: () {
|
bottomBtnItemWidget(
|
||||||
|
'images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red,
|
||||||
|
onClick: () {
|
||||||
// 挂断
|
// 挂断
|
||||||
logic.udpHangUpAction();
|
logic.udpHangUpAction();
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -1,518 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:math';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/scheduler.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:star_lock/appRouters.dart';
|
|
||||||
import 'package:star_lock/flavors.dart';
|
|
||||||
import 'package:star_lock/talk/call/callTalk.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/constant/talk_status.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/handle/impl/debug_Info_model.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/handle/impl/udp_talk_data_handler.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/star_chart_manage.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_logic.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_state.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/views/talkView/talk_view_logic.dart';
|
|
||||||
import 'package:star_lock/talk/starChart/views/talkView/talk_view_state.dart';
|
|
||||||
import 'package:video_decode_plugin/video_decode_plugin.dart';
|
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
|
||||||
import '../../../../tools/showTFView.dart';
|
|
||||||
|
|
||||||
class TalkViewNativeDecodePageDebug extends StatefulWidget {
|
|
||||||
const TalkViewNativeDecodePageDebug({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<TalkViewNativeDecodePageDebug> createState() => _TalkViewNativeDecodePageDebugState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TalkViewNativeDecodePageDebugState extends State<TalkViewNativeDecodePageDebug> with TickerProviderStateMixin {
|
|
||||||
final TalkViewNativeDecodeLogic logic = Get.put(TalkViewNativeDecodeLogic());
|
|
||||||
final TalkViewNativeDecodeState state = Get.find<TalkViewNativeDecodeLogic>().state;
|
|
||||||
final startChartManage = StartChartManage();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
state.animationController = AnimationController(
|
|
||||||
vsync: this, // 确保使用的TickerProvider是当前Widget
|
|
||||||
duration: const Duration(seconds: 1),
|
|
||||||
);
|
|
||||||
|
|
||||||
state.animationController.repeat();
|
|
||||||
//动画开始、结束、向前移动或向后移动时会调用StatusListener
|
|
||||||
state.animationController.addStatusListener((AnimationStatus status) {
|
|
||||||
if (status == AnimationStatus.completed) {
|
|
||||||
state.animationController.reset();
|
|
||||||
state.animationController.forward();
|
|
||||||
} else if (status == AnimationStatus.dismissed) {
|
|
||||||
state.animationController.reset();
|
|
||||||
state.animationController.forward();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return WillPopScope(
|
|
||||||
onWillPop: () async {
|
|
||||||
// 返回 false 表示禁止退出
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 1.sw,
|
|
||||||
height: 1.sh,
|
|
||||||
color: Colors.black.withOpacity(0.7),
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
// 悬浮帧率统计信息条
|
|
||||||
Obx(
|
|
||||||
() {
|
|
||||||
final double screenWidth = MediaQuery.of(context).size.width;
|
|
||||||
final double screenHeight = MediaQuery.of(context).size.height;
|
|
||||||
|
|
||||||
// 防御性处理:只要loading中或textureId为null,优先渲染loading/占位
|
|
||||||
if (state.isLoading.isTrue || state.textureId.value == null) {
|
|
||||||
return Image.asset(
|
|
||||||
'images/main/monitorBg.png',
|
|
||||||
width: screenWidth,
|
|
||||||
height: screenHeight,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return PopScope(
|
|
||||||
canPop: false,
|
|
||||||
child: RepaintBoundary(
|
|
||||||
key: state.globalKey,
|
|
||||||
child: RotatedBox(
|
|
||||||
// 解码器不支持硬件旋转,使用RotatedBox
|
|
||||||
quarterTurns: startChartManage.rotateAngle ~/ 90,
|
|
||||||
child: Platform.isIOS
|
|
||||||
? Transform.scale(
|
|
||||||
scale: 1.008, // 轻微放大,消除iOS白边
|
|
||||||
child: Texture(
|
|
||||||
textureId: state.textureId.value!,
|
|
||||||
filterQuality: FilterQuality.medium,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: state.isFullScreen.isFalse
|
|
||||||
? AspectRatio(
|
|
||||||
aspectRatio: StartChartManage().videoWidth / StartChartManage().videoHeight,
|
|
||||||
child: Texture(
|
|
||||||
textureId: state.textureId.value!,
|
|
||||||
filterQuality: FilterQuality.medium,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Texture(
|
|
||||||
textureId: state.textureId.value!,
|
|
||||||
filterQuality: FilterQuality.medium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
state.isFullScreen.value = !state.isFullScreen.value;
|
|
||||||
},
|
|
||||||
child: Obx(
|
|
||||||
() => Text(state.isFullScreen.isTrue ? '退出全屏' : '全屏'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Obx(() => state.isLoading.isTrue
|
|
||||||
? Positioned(
|
|
||||||
bottom: 310.h,
|
|
||||||
child: Text(
|
|
||||||
'正在创建安全连接...'.tr,
|
|
||||||
style: TextStyle(color: Colors.black, fontSize: 26.sp),
|
|
||||||
))
|
|
||||||
: Container()),
|
|
||||||
Obx(() => state.isLoading.isFalse && state.oneMinuteTime.value > 0
|
|
||||||
? Positioned(
|
|
||||||
top: ScreenUtil().statusBarHeight + 75.h,
|
|
||||||
width: 1.sw,
|
|
||||||
child: Obx(
|
|
||||||
() {
|
|
||||||
final String sec = (state.oneMinuteTime.value % 60).toString().padLeft(2, '0');
|
|
||||||
final String min = (state.oneMinuteTime.value ~/ 60).toString().padLeft(2, '0');
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
'$min:$sec',
|
|
||||||
style: TextStyle(fontSize: 26.sp, color: Colors.white),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Container()),
|
|
||||||
Positioned(
|
|
||||||
bottom: 10.w,
|
|
||||||
child: Container(
|
|
||||||
width: 1.sw - 30.w * 2,
|
|
||||||
// height: 300.h,
|
|
||||||
margin: EdgeInsets.all(30.w),
|
|
||||||
decoration: BoxDecoration(color: Colors.black.withOpacity(0.2), borderRadius: BorderRadius.circular(20.h)),
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
SizedBox(height: 20.h),
|
|
||||||
bottomTopBtnWidget(),
|
|
||||||
SizedBox(height: 20.h),
|
|
||||||
bottomBottomBtnWidget(),
|
|
||||||
SizedBox(height: 20.h),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Obx(() => state.isLoading.isTrue ? buildRotationTransition() : Container()),
|
|
||||||
Obx(() => state.isLongPressing.value
|
|
||||||
? Positioned(
|
|
||||||
top: 80.h,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Center(
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.all(10.w),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.black.withOpacity(0.7),
|
|
||||||
borderRadius: BorderRadius.circular(10.w),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(Icons.mic, color: Colors.white, size: 24.w),
|
|
||||||
SizedBox(width: 10.w),
|
|
||||||
Text(
|
|
||||||
'正在说话...'.tr,
|
|
||||||
style: TextStyle(fontSize: 20.sp, color: Colors.white),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Container()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget bottomTopBtnWidget() {
|
|
||||||
return Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
|
||||||
// 打开关闭声音
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
|
||||||
// 打开关闭声音
|
|
||||||
logic.updateTalkExpect();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 50.w,
|
|
||||||
height: 50.w,
|
|
||||||
padding: EdgeInsets.all(5.w),
|
|
||||||
child: Obx(() => Image(
|
|
||||||
width: 40.w,
|
|
||||||
height: 40.w,
|
|
||||||
image: state.isOpenVoice.value
|
|
||||||
? const AssetImage('images/main/icon_lockDetail_monitoringOpenVoice.png')
|
|
||||||
: const AssetImage('images/main/icon_lockDetail_monitoringCloseVoice.png'))),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 50.w),
|
|
||||||
// 截图
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () async {
|
|
||||||
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
|
||||||
await logic.captureAndSavePng();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 50.w,
|
|
||||||
height: 50.w,
|
|
||||||
padding: EdgeInsets.all(5.w),
|
|
||||||
child: Image(width: 40.w, height: 40.w, image: const AssetImage('images/main/icon_lockDetail_monitoringScreenshot.png')),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 50.w),
|
|
||||||
// 录制
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () async {
|
|
||||||
logic.showToast('功能暂未开放'.tr);
|
|
||||||
// if (
|
|
||||||
// state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
|
||||||
// if (state.isRecordingScreen.value) {
|
|
||||||
// await logic.stopRecording();
|
|
||||||
// } else {
|
|
||||||
// await logic.startRecording();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 50.w,
|
|
||||||
height: 50.w,
|
|
||||||
padding: EdgeInsets.all(5.w),
|
|
||||||
child: Image(
|
|
||||||
width: 40.w,
|
|
||||||
height: 40.w,
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
image: const AssetImage('images/main/icon_lockDetail_monitoringScreenRecording.png'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 50.w),
|
|
||||||
// 清晰度切换按钮
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () async {
|
|
||||||
// 弹出底部弹出层,选择清晰度
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20.w)),
|
|
||||||
),
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
final List<String> qualities = ['高清', '标清'];
|
|
||||||
return SafeArea(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: qualities.map((q) {
|
|
||||||
return Obx(() => InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
logic.onQualityChanged(q);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 18.w),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
q,
|
|
||||||
style: TextStyle(
|
|
||||||
color: state.currentQuality.value == q ? AppColors.mainColor : Colors.black,
|
|
||||||
fontWeight: state.currentQuality.value == q ? FontWeight.bold : FontWeight.normal,
|
|
||||||
fontSize: 28.sp,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
child: Icon(Icons.high_quality_outlined, color: Colors.white, size: 38.w),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: state.currentLanguage == 'zh_CN' && Platform.isAndroid,
|
|
||||||
child: SizedBox(width: 38.w),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: state.currentLanguage == 'zh_CN' && Platform.isAndroid,
|
|
||||||
child: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.notification_add_sharp,
|
|
||||||
size: 32.w,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
Get.toNamed(Routers.permissionGuidancePage);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget bottomBottomBtnWidget() {
|
|
||||||
return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
|
|
||||||
// 接听
|
|
||||||
Obx(
|
|
||||||
() => bottomBtnItemWidget(
|
|
||||||
getAnswerBtnImg(),
|
|
||||||
getAnswerBtnName(),
|
|
||||||
Colors.white,
|
|
||||||
longPress: () async {
|
|
||||||
if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
|
|
||||||
// 启动录音
|
|
||||||
logic.startProcessingAudio();
|
|
||||||
state.isLongPressing.value = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
longPressUp: () async {
|
|
||||||
// 停止录音
|
|
||||||
logic.stopProcessingAudio();
|
|
||||||
state.isLongPressing.value = false;
|
|
||||||
},
|
|
||||||
onClick: () async {
|
|
||||||
if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) {
|
|
||||||
// 接听
|
|
||||||
logic.initiateAnswerCommand();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
bottomBtnItemWidget('images/main/icon_lockDetail_hangUp.png', '挂断'.tr, Colors.red, onClick: () {
|
|
||||||
// 挂断
|
|
||||||
logic.udpHangUpAction();
|
|
||||||
}),
|
|
||||||
bottomBtnItemWidget(
|
|
||||||
'images/main/icon_lockDetail_monitoringUnlock.png',
|
|
||||||
'开锁'.tr,
|
|
||||||
AppColors.mainColor,
|
|
||||||
onClick: () {
|
|
||||||
// if (state.talkStatus.value == TalkStatus.answeredSuccessfully &&
|
|
||||||
// state.listData.value.length > 0) {
|
|
||||||
// logic.udpOpenDoorAction();
|
|
||||||
// }
|
|
||||||
// if (UDPManage().remoteUnlock == 1) {
|
|
||||||
// logic.udpOpenDoorAction();
|
|
||||||
// showDeletPasswordAlertDialog(context);
|
|
||||||
// } else {
|
|
||||||
// logic.showToast('请在锁设置中开启远程开锁'.tr);
|
|
||||||
// }
|
|
||||||
logic.remoteOpenLock();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
String getAnswerBtnImg() {
|
|
||||||
switch (state.talkStatus.value) {
|
|
||||||
case TalkStatus.passiveCallWaitingAnswer:
|
|
||||||
return 'images/main/icon_lockDetail_monitoringAnswerCalls.png';
|
|
||||||
case TalkStatus.answeredSuccessfully:
|
|
||||||
case TalkStatus.proactivelyCallWaitingAnswer:
|
|
||||||
return 'images/main/icon_lockDetail_monitoringUnTalkback.png';
|
|
||||||
default:
|
|
||||||
return 'images/main/icon_lockDetail_monitoringAnswerCalls.png';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String getAnswerBtnName() {
|
|
||||||
switch (state.talkStatus.value) {
|
|
||||||
case TalkStatus.passiveCallWaitingAnswer:
|
|
||||||
return '接听'.tr;
|
|
||||||
case TalkStatus.proactivelyCallWaitingAnswer:
|
|
||||||
case TalkStatus.answeredSuccessfully:
|
|
||||||
return '长按说话'.tr;
|
|
||||||
default:
|
|
||||||
return '接听'.tr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget bottomBtnItemWidget(
|
|
||||||
String iconUrl,
|
|
||||||
String name,
|
|
||||||
Color backgroundColor, {
|
|
||||||
required Function() onClick,
|
|
||||||
Function()? longPress,
|
|
||||||
Function()? longPressUp,
|
|
||||||
}) {
|
|
||||||
double wh = 80.w;
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: onClick,
|
|
||||||
onLongPress: longPress,
|
|
||||||
onLongPressUp: longPressUp,
|
|
||||||
child: SizedBox(
|
|
||||||
height: 160.w,
|
|
||||||
width: 140.w,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
width: wh,
|
|
||||||
height: wh,
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minWidth: wh,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: backgroundColor,
|
|
||||||
borderRadius: BorderRadius.circular((wh + 10.w * 2) / 2),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.all(20.w),
|
|
||||||
child: Image.asset(iconUrl, fit: BoxFit.fitWidth),
|
|
||||||
),
|
|
||||||
SizedBox(height: 20.w),
|
|
||||||
Text(
|
|
||||||
name,
|
|
||||||
style: TextStyle(fontSize: 20.sp, color: Colors.white),
|
|
||||||
textAlign: TextAlign.center, // 当文本超出指定行数时,使用省略号表示
|
|
||||||
maxLines: 2, // 设置最大行数为1
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据丢包率返回对应的颜色
|
|
||||||
Color _getPacketLossColor(double lossRate) {
|
|
||||||
if (lossRate < 1.0) {
|
|
||||||
return Colors.green; // 丢包率低于1%显示绿色
|
|
||||||
} else if (lossRate < 5.0) {
|
|
||||||
return Colors.yellow; // 丢包率1%-5%显示黄色
|
|
||||||
} else if (lossRate < 10.0) {
|
|
||||||
return Colors.orange; // 丢包率5%-10%显示橙色
|
|
||||||
} else {
|
|
||||||
return Colors.red; // 丢包率高于10%显示红色
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//旋转动画
|
|
||||||
Widget buildRotationTransition() {
|
|
||||||
return Positioned(
|
|
||||||
left: ScreenUtil().screenWidth / 2 - 220.w / 2,
|
|
||||||
top: ScreenUtil().screenHeight / 2 - 220.w / 2 - 150.h,
|
|
||||||
child: GestureDetector(
|
|
||||||
child: RotationTransition(
|
|
||||||
//设置动画的旋转中心
|
|
||||||
alignment: Alignment.center,
|
|
||||||
//动画控制器
|
|
||||||
turns: state.animationController,
|
|
||||||
//将要执行动画的子view
|
|
||||||
child: AnimatedOpacity(
|
|
||||||
opacity: 0.5,
|
|
||||||
duration: const Duration(seconds: 2),
|
|
||||||
child: Image.asset(
|
|
||||||
'images/main/realTime_connecting.png',
|
|
||||||
width: 220.w,
|
|
||||||
height: 220.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
state.animationController.forward();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
state.animationController.dispose();
|
|
||||||
CallTalk().finishAVData();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -37,7 +37,8 @@ class TalkViewNativeDecodeState {
|
|||||||
Future<String?> userMobileIP = NetworkInfo().getWifiIP();
|
Future<String?> userMobileIP = NetworkInfo().getWifiIP();
|
||||||
Future<String?> userUid = Storage.getUid();
|
Future<String?> userUid = Storage.getUid();
|
||||||
|
|
||||||
RxInt udpStatus = 0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话
|
RxInt udpStatus =
|
||||||
|
0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话
|
||||||
TextEditingController passwordTF = TextEditingController();
|
TextEditingController passwordTF = TextEditingController();
|
||||||
|
|
||||||
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
||||||
@ -62,12 +63,13 @@ class TalkViewNativeDecodeState {
|
|||||||
RxBool isPlaying = false.obs; // 是否开始播放
|
RxBool isPlaying = false.obs; // 是否开始播放
|
||||||
Rx<TalkStatus> talkStatus = TalkStatus.none.obs; //星图对讲状态
|
Rx<TalkStatus> talkStatus = TalkStatus.none.obs; //星图对讲状态
|
||||||
// 获取 startChartTalkStatus 的唯一实例
|
// 获取 startChartTalkStatus 的唯一实例
|
||||||
final StartChartTalkStatus startChartTalkStatus = StartChartTalkStatus.instance;
|
final StartChartTalkStatus startChartTalkStatus =
|
||||||
|
StartChartTalkStatus.instance;
|
||||||
|
|
||||||
// 通话数据流的单例流数据处理类
|
// 通话数据流的单例流数据处理类
|
||||||
final TalkDataRepository talkDataRepository = TalkDataRepository.instance;
|
final TalkDataRepository talkDataRepository = TalkDataRepository.instance;
|
||||||
|
|
||||||
RxBool isOpenVoice = false.obs; // 是否打开声音
|
RxBool isOpenVoice = true.obs; // 是否打开声音
|
||||||
RxBool isRecordingScreen = false.obs; // 是否录屏中
|
RxBool isRecordingScreen = false.obs; // 是否录屏中
|
||||||
RxBool isRecordingAudio = false.obs; // 是否录音中
|
RxBool isRecordingAudio = false.obs; // 是否录音中
|
||||||
Rx<DateTime> startRecordingAudioTime = DateTime.now().obs; // 开始录音时间
|
Rx<DateTime> startRecordingAudioTime = DateTime.now().obs; // 开始录音时间
|
||||||
@ -79,7 +81,6 @@ class TalkViewNativeDecodeState {
|
|||||||
RxBool isLongPressing = false.obs; // 旋转角度(以弧度为单位)
|
RxBool isLongPressing = false.obs; // 旋转角度(以弧度为单位)
|
||||||
// 视频解码器纹理ID
|
// 视频解码器纹理ID
|
||||||
Rx<int?> textureId = Rx<int?>(null);
|
Rx<int?> textureId = Rx<int?>(null);
|
||||||
|
|
||||||
// FPS监测相关变量
|
// FPS监测相关变量
|
||||||
|
|
||||||
RxInt lastFpsUpdateTime = 0.obs; // 上次FPS更新时间
|
RxInt lastFpsUpdateTime = 0.obs; // 上次FPS更新时间
|
||||||
@ -109,8 +110,8 @@ class TalkViewNativeDecodeState {
|
|||||||
|
|
||||||
// H264帧缓冲区相关
|
// H264帧缓冲区相关
|
||||||
final List<Map<String, dynamic>> h264FrameBuffer = <Map<String, dynamic>>[]; // H264帧缓冲区,存储帧数据和类型
|
final List<Map<String, dynamic>> h264FrameBuffer = <Map<String, dynamic>>[]; // H264帧缓冲区,存储帧数据和类型
|
||||||
final int maxFrameBufferSize = 25; // 最大缓冲区大小
|
final int maxFrameBufferSize = 50; // 最大缓冲区大小
|
||||||
final int targetFps = 25; // 目标解码帧率,只是为了快速填充native的缓冲区
|
final int targetFps = 60; // 目标解码帧率,只是为了快速填充native的缓冲区
|
||||||
Timer? frameProcessTimer; // 帧处理定时器
|
Timer? frameProcessTimer; // 帧处理定时器
|
||||||
bool isProcessingFrame = false; // 是否正在处理帧
|
bool isProcessingFrame = false; // 是否正在处理帧
|
||||||
int lastProcessedTimestamp = 0; // 上次处理帧的时间戳
|
int lastProcessedTimestamp = 0; // 上次处理帧的时间戳
|
||||||
@ -121,8 +122,6 @@ class TalkViewNativeDecodeState {
|
|||||||
// 当前清晰度选项,初始为'高清'
|
// 当前清晰度选项,初始为'高清'
|
||||||
RxString currentQuality = '高清'.obs; // 可选:高清、标清、流畅
|
RxString currentQuality = '高清'.obs; // 可选:高清、标清、流畅
|
||||||
|
|
||||||
RxString currentLanguage = CurrentLocaleTool.getCurrentLocaleString().obs; // 当前选择语言
|
RxString currentLanguage =
|
||||||
|
CurrentLocaleTool.getCurrentLocaleString().obs; // 当前选择语言
|
||||||
// 是否拉伸至全屏
|
|
||||||
RxBool isFullScreen = false.obs;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,7 +67,7 @@ class CommonItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
leftTitel!,
|
leftTitel!,
|
||||||
style: leftTitleStyle ?? TextStyle(fontSize: 22.sp),
|
style: leftTitleStyle ?? TextStyle(fontSize: 28.sp),
|
||||||
overflow: TextOverflow.ellipsis, // 超出部分显示省略号
|
overflow: TextOverflow.ellipsis, // 超出部分显示省略号
|
||||||
maxLines: 3, // 最多显示2行
|
maxLines: 3, // 最多显示2行
|
||||||
),
|
),
|
||||||
|
|||||||
@ -194,6 +194,45 @@ class DateTool {
|
|||||||
return appointmentDate;
|
return appointmentDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 将时间戳传化为月
|
||||||
|
String dateToMMString(String? timestamp) {
|
||||||
|
timestamp ??= '0';
|
||||||
|
int time = int.parse(timestamp);
|
||||||
|
if (timestamp.length == 10) {
|
||||||
|
time = time * 1000;
|
||||||
|
}
|
||||||
|
final DateTime nowDate = DateTime.fromMillisecondsSinceEpoch(time);
|
||||||
|
final String appointmentDate =
|
||||||
|
formatDate(nowDate, <String>[mm]);
|
||||||
|
return appointmentDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 将时间戳传化为日
|
||||||
|
String dateToDDString(String? timestamp) {
|
||||||
|
timestamp ??= '0';
|
||||||
|
int time = int.parse(timestamp);
|
||||||
|
if (timestamp.length == 10) {
|
||||||
|
time = time * 1000;
|
||||||
|
}
|
||||||
|
final DateTime nowDate = DateTime.fromMillisecondsSinceEpoch(time);
|
||||||
|
final String appointmentDate =
|
||||||
|
formatDate(nowDate, <String>[dd]);
|
||||||
|
return appointmentDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 将时间戳传化为时分
|
||||||
|
String dateToHnString(String? timestamp) {
|
||||||
|
timestamp ??= '0';
|
||||||
|
int time = int.parse(timestamp);
|
||||||
|
if (timestamp.length == 10) {
|
||||||
|
time = time * 1000;
|
||||||
|
}
|
||||||
|
final DateTime nowDate = DateTime.fromMillisecondsSinceEpoch(time);
|
||||||
|
final String appointmentDate =
|
||||||
|
formatDate(nowDate, <String>[HH, ':', nn]);
|
||||||
|
return appointmentDate;
|
||||||
|
}
|
||||||
|
|
||||||
/// 将时间戳传化为年月日 (年-月-日 时:分)
|
/// 将时间戳传化为年月日 (年-月-日 时:分)
|
||||||
String dateIntToYMDHNString(int? time) {
|
String dateIntToYMDHNString(int? time) {
|
||||||
time ??= 0;
|
time ??= 0;
|
||||||
|
|||||||
@ -261,7 +261,7 @@ dependencies:
|
|||||||
|
|
||||||
jverify: 3.0.0
|
jverify: 3.0.0
|
||||||
#<cn>
|
#<cn>
|
||||||
umeng_common_sdk: 1.2.8
|
# umeng_common_sdk: 1.2.8
|
||||||
#</cn>
|
#</cn>
|
||||||
#<com>
|
#<com>
|
||||||
firebase_analytics: 11.3.0
|
firebase_analytics: 11.3.0
|
||||||
@ -322,8 +322,8 @@ flutter:
|
|||||||
assets:
|
assets:
|
||||||
- images/
|
- images/
|
||||||
- images/tabbar/
|
- images/tabbar/
|
||||||
- images/other/
|
|
||||||
- images/guide/
|
- images/guide/
|
||||||
|
- images/other/
|
||||||
- images/main/
|
- images/main/
|
||||||
- images/main/addFingerprint/
|
- images/main/addFingerprint/
|
||||||
- images/mine/
|
- images/mine/
|
||||||
|
|||||||