Merge branch 'master' of https://gitee.com/starlock-cn/app-starlock
This commit is contained in:
commit
95769e6ca8
@ -164,7 +164,7 @@ class _LockDetailPageState extends State<LockDetailPage>
|
|||||||
Stack(children: [
|
Stack(children: [
|
||||||
Container(
|
Container(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
height: 1.sh - ScreenUtil().statusBarHeight * 2,
|
height: 1.sh - ScreenUtil().statusBarHeight,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import 'package:permission_handler/permission_handler.dart';
|
|||||||
import 'package:star_lock/talk/call/callTalk.dart';
|
import 'package:star_lock/talk/call/callTalk.dart';
|
||||||
import 'package:star_lock/talk/udp/udp_talkClass.dart';
|
import 'package:star_lock/talk/udp/udp_talkClass.dart';
|
||||||
|
|
||||||
import '../../../../talk/call/g711.dart';
|
|
||||||
import '../../../../talk/udp/udp_manage.dart';
|
import '../../../../talk/udp/udp_manage.dart';
|
||||||
import '../../../../talk/udp/udp_senderManage.dart';
|
import '../../../../talk/udp/udp_senderManage.dart';
|
||||||
import '../../../../tools/baseGetXController.dart';
|
import '../../../../tools/baseGetXController.dart';
|
||||||
@ -113,19 +112,6 @@ class LockMonitoringLogic extends BaseGetXController {
|
|||||||
udpHangUpAction();
|
udpHangUpAction();
|
||||||
state.hangUpSeconds++;
|
state.hangUpSeconds++;
|
||||||
|
|
||||||
// //如果已经挂断成功,则取消定时器
|
|
||||||
// if (UDPTalkClass().isEndCall == true) {
|
|
||||||
// print('{$clickIndex}已经挂断成功');
|
|
||||||
// state.hangUpTimer.cancel();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (UDPTalkClass().status == 6) {
|
|
||||||
// print('{$clickIndex}被叫中,已经挂断成功');
|
|
||||||
// state.hangUpTimer.cancel();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 检查条件,如果达到6秒且未得到应答,则认为失败
|
// 检查条件,如果达到6秒且未得到应答,则认为失败
|
||||||
if (state.hangUpSeconds >= 6) {
|
if (state.hangUpSeconds >= 6) {
|
||||||
state.hangUpTimer.cancel(); // 取消定时器
|
state.hangUpTimer.cancel(); // 取消定时器
|
||||||
@ -177,87 +163,77 @@ class LockMonitoringLogic extends BaseGetXController {
|
|||||||
Get.back();
|
Get.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _readG711Data() async {
|
//开始录音
|
||||||
String filePath = 'assets/s10-g711.bin';
|
Future<void> startProcessing() async {
|
||||||
List<int> audioData = await G711().readAssetFile(filePath);
|
state.isButtonDisabled.value = true;
|
||||||
// Get.log('发送读取711文件数据为:$audioData');// 数据为:$audioData
|
|
||||||
// return;
|
|
||||||
// print('发送读取711文件数据长度为:${audioData.length}');// 数据为:$audioData
|
|
||||||
if (audioData.isNotEmpty) {
|
|
||||||
// 在这里处理你的音频数据
|
|
||||||
// pcmBytes = G711().convertList(audioData);
|
|
||||||
// print('发送转换pcmBytes数据长度为:${pcmBytes.length}');
|
|
||||||
|
|
||||||
int start = 0;
|
state.voiceProcessor?.addFrameListener(_onFrame);
|
||||||
int length = 320;
|
state.voiceProcessor?.addErrorListener(_onError);
|
||||||
while (start < audioData.length) {
|
try {
|
||||||
// await Future.delayed(const Duration(milliseconds: 50));
|
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
|
||||||
|
await state.voiceProcessor?.start(state.frameLength, state.sampleRate);
|
||||||
int end = (start + length > audioData.length)
|
bool? isRecording = await state.voiceProcessor?.isRecording();
|
||||||
? audioData.length
|
state.isProcessing.value = isRecording!;
|
||||||
: start + length;
|
} else {
|
||||||
List<int> sublist = audioData.sublist(start, end);
|
state.errorMessage.value = "Recording permission not granted";
|
||||||
sendRecordData({
|
|
||||||
"bytes": sublist,
|
|
||||||
// "udpSendDataFrameNumber": 0,
|
|
||||||
"lockID": UDPManage().lockId,
|
|
||||||
"lockIP": UDPManage().host,
|
|
||||||
"userMobile": await state.userUid,
|
|
||||||
"userMobileIP": await state.userMobileIP,
|
|
||||||
});
|
|
||||||
print(sublist);
|
|
||||||
start += length;
|
|
||||||
}
|
}
|
||||||
print('G711数据发送完成');
|
} on PlatformException catch (ex) {
|
||||||
} else {
|
state.errorMessage.value = "Failed to start recorder: $ex";
|
||||||
print('Failed to read audio data.');
|
} finally {
|
||||||
|
state.isButtonDisabled.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> startProcessing() async {
|
double _calculateVolumeLevel(List<int> frame) {
|
||||||
frameListener(List<int> frame) async {
|
double rms = 0.0;
|
||||||
for (int i = 0; i < frame.length; i++) {
|
for (int sample in frame) {
|
||||||
frame[i] = linearToULaw(frame[i]);
|
rms += pow(sample, 2);
|
||||||
}
|
|
||||||
await Future.delayed(const Duration(milliseconds: 50));
|
|
||||||
sendRecordData({
|
|
||||||
"bytes": frame,
|
|
||||||
// "udpSendDataFrameNumber": 0,
|
|
||||||
"lockID": UDPManage().lockId,
|
|
||||||
"lockIP": UDPManage().host,
|
|
||||||
"userMobile": await state.userUid,
|
|
||||||
"userMobileIP": await state.userMobileIP,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
rms = sqrt(rms / frame.length);
|
||||||
|
|
||||||
errorListener(VoiceProcessorException error) {
|
double dbfs = 20 * log(rms / 32767.0) / log(10);
|
||||||
print("VoiceProcessorException: $error");
|
double normalizedValue = (dbfs + state.dbOffset) / state.dbOffset;
|
||||||
|
return normalizedValue.clamp(0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onFrame(List<int> frame) async {
|
||||||
|
double volumeLevel = _calculateVolumeLevel(frame);
|
||||||
|
if (state.volumeHistory.value.length == state.volumeHistoryCapacity) {
|
||||||
|
state.volumeHistory.value.removeAt(0);
|
||||||
}
|
}
|
||||||
|
state.volumeHistory.value.add(volumeLevel);
|
||||||
|
|
||||||
;
|
state.smoothedVolumeValue.value =
|
||||||
state.voiceProcessor?.addFrameListener(frameListener);
|
state.volumeHistory.value.reduce((a, b) => a + b) /
|
||||||
state.voiceProcessor?.addErrorListener(errorListener);
|
state.volumeHistory.value.length;
|
||||||
|
|
||||||
try {
|
List<int> pcmBytes = listLinearToULaw(frame);
|
||||||
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
await state.voiceProcessor?.start(320, 8000);
|
sendRecordData({
|
||||||
bool? isRecording = await state.voiceProcessor?.isRecording();
|
"bytes": pcmBytes,
|
||||||
} else {}
|
// "udpSendDataFrameNumber": 0,
|
||||||
} on PlatformException catch (ex) {
|
"lockID": UDPManage().lockId,
|
||||||
Get.log("PlatformException: $ex");
|
"lockIP": UDPManage().host,
|
||||||
} finally {}
|
"userMobile": await state.userUid,
|
||||||
|
"userMobileIP": await state.userMobileIP,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onError(VoiceProcessorException error) {
|
||||||
|
state.errorMessage.value = error.message!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> stopProcessing() async {
|
Future<void> stopProcessing() async {
|
||||||
|
state.isButtonDisabled.value = true;
|
||||||
try {
|
try {
|
||||||
await state.voiceProcessor?.stop();
|
await state.voiceProcessor?.stop();
|
||||||
} on PlatformException catch (ex) {
|
} on PlatformException catch (ex) {
|
||||||
Get.log("PlatformException: $ex");
|
state.errorMessage.value = "Failed to stop recorder: $ex";
|
||||||
} finally {}
|
} finally {
|
||||||
}
|
bool? isRecording = await state.voiceProcessor?.isRecording();
|
||||||
|
state.isProcessing.value = isRecording!;
|
||||||
void onError(Object e) {
|
state.isButtonDisabled.value = false;
|
||||||
print(e);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRecordData(Map<String, dynamic> args) async {
|
sendRecordData(Map<String, dynamic> args) async {
|
||||||
@ -360,6 +336,15 @@ class LockMonitoringLogic extends BaseGetXController {
|
|||||||
// UDPManage().sendData(topBytes);
|
// UDPManage().sendData(topBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<int> listLinearToULaw(List<int> pcmList) {
|
||||||
|
List<int> uLawList = [];
|
||||||
|
for (int pcmVal in pcmList) {
|
||||||
|
int uLawVal = linearToULaw(pcmVal);
|
||||||
|
uLawList.add(uLawVal);
|
||||||
|
}
|
||||||
|
return uLawList;
|
||||||
|
}
|
||||||
|
|
||||||
// 拿到的音频转化成pcm
|
// 拿到的音频转化成pcm
|
||||||
int linearToULaw(int pcmVal) {
|
int linearToULaw(int pcmVal) {
|
||||||
int mask;
|
int mask;
|
||||||
@ -404,18 +389,6 @@ class LockMonitoringLogic extends BaseGetXController {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
double _calculateVolumeLevel(List<int> frame) {
|
|
||||||
double rms = 0.0;
|
|
||||||
for (int sample in frame) {
|
|
||||||
rms += pow(sample, 2);
|
|
||||||
}
|
|
||||||
rms = sqrt(rms / frame.length);
|
|
||||||
|
|
||||||
double dbfs = 20 * log(rms / 32767.0) / log(10);
|
|
||||||
double normalizedValue = (dbfs + 50) / 50;
|
|
||||||
return normalizedValue.clamp(0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> getPermissionStatus() async {
|
Future<bool> getPermissionStatus() async {
|
||||||
Permission permission = Permission.microphone;
|
Permission permission = Permission.microphone;
|
||||||
//granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示
|
//granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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:image_gallery_saver/image_gallery_saver.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:star_lock/talk/call/callTalk.dart';
|
import 'package:star_lock/talk/call/callTalk.dart';
|
||||||
|
|
||||||
import '../../../../app_settings/app_colors.dart';
|
import '../../../../app_settings/app_colors.dart';
|
||||||
@ -36,85 +41,88 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
child: Container(
|
child: RepaintBoundary(
|
||||||
width: 1.sw,
|
key: state.globalKey,
|
||||||
height: 1.sh,
|
child: Container(
|
||||||
color: Colors.white,
|
width: 1.sw,
|
||||||
child: Stack(
|
height: 1.sh,
|
||||||
children: [
|
color: Colors.white,
|
||||||
Obx(() {
|
child: Stack(
|
||||||
if (state.listPhotoData.value.isEmpty ||
|
children: [
|
||||||
state.listPhotoData.value.length < 10) {
|
Obx(() {
|
||||||
return Container(color: Colors.transparent);
|
if (state.listPhotoData.value.isEmpty ||
|
||||||
} else {
|
state.listPhotoData.value.length < 10) {
|
||||||
return Image.memory(
|
return Container(color: Colors.transparent);
|
||||||
state.listPhotoData.value,
|
} else {
|
||||||
gaplessPlayback: true,
|
return Image.memory(
|
||||||
width: 1.sw,
|
state.listPhotoData.value,
|
||||||
height: 1.sh,
|
gaplessPlayback: true,
|
||||||
fit: BoxFit.cover,
|
width: 1.sw,
|
||||||
errorBuilder: (context, error, stackTrace) {
|
height: 1.sh,
|
||||||
return Container(color: Colors.transparent);
|
fit: BoxFit.cover,
|
||||||
},
|
errorBuilder: (context, error, stackTrace) {
|
||||||
);
|
return Container(color: Colors.transparent);
|
||||||
}
|
},
|
||||||
}),
|
);
|
||||||
Positioned(
|
}
|
||||||
top: ScreenUtil().statusBarHeight + 30.h,
|
|
||||||
width: 1.sw,
|
|
||||||
child: Obx(() {
|
|
||||||
var sec = (state.oneMinuteTime.value % 60)
|
|
||||||
.toString()
|
|
||||||
.padLeft(2, '0');
|
|
||||||
var min = (state.oneMinuteTime.value ~/ 60)
|
|
||||||
.toString()
|
|
||||||
.padLeft(2, '0');
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text("$min:$sec",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 26.sp, color: Colors.white)),
|
|
||||||
// SizedBox(width: 30.w),
|
|
||||||
// GestureDetector(
|
|
||||||
// onTap: () {
|
|
||||||
// Get.back();
|
|
||||||
// },
|
|
||||||
// child: Container(
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: Colors.white,
|
|
||||||
// borderRadius: BorderRadius.circular(25.h)),
|
|
||||||
// padding: EdgeInsets.all(10.w),
|
|
||||||
// child: Image(
|
|
||||||
// width: 40.w,
|
|
||||||
// height: 40.w,
|
|
||||||
// image: const AssetImage("images/icon_left_black.png"),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
]);
|
|
||||||
}),
|
}),
|
||||||
),
|
Positioned(
|
||||||
Positioned(
|
top: ScreenUtil().statusBarHeight + 30.h,
|
||||||
bottom: 10.w,
|
width: 1.sw,
|
||||||
child: Container(
|
child: Obx(() {
|
||||||
width: 1.sw - 30.w * 2,
|
var sec = (state.oneMinuteTime.value % 60)
|
||||||
// height: 300.h,
|
.toString()
|
||||||
margin: EdgeInsets.all(30.w),
|
.padLeft(2, '0');
|
||||||
decoration: BoxDecoration(
|
var min = (state.oneMinuteTime.value ~/ 60)
|
||||||
color: const Color(0xC83C3F41),
|
.toString()
|
||||||
borderRadius: BorderRadius.circular(20.h)),
|
.padLeft(2, '0');
|
||||||
child: Column(
|
return Row(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
SizedBox(height: 20.h),
|
children: [
|
||||||
bottomTopBtnWidget(),
|
Text("$min:$sec",
|
||||||
SizedBox(height: 20.h),
|
style: TextStyle(
|
||||||
bottomBottomBtnWidget(),
|
fontSize: 26.sp, color: Colors.white)),
|
||||||
SizedBox(height: 20.h),
|
// SizedBox(width: 30.w),
|
||||||
],
|
// GestureDetector(
|
||||||
),
|
// onTap: () {
|
||||||
))
|
// Get.back();
|
||||||
],
|
// },
|
||||||
|
// child: Container(
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: Colors.white,
|
||||||
|
// borderRadius: BorderRadius.circular(25.h)),
|
||||||
|
// padding: EdgeInsets.all(10.w),
|
||||||
|
// child: Image(
|
||||||
|
// width: 40.w,
|
||||||
|
// height: 40.w,
|
||||||
|
// image: const AssetImage("images/icon_left_black.png"),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
]);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 10.w,
|
||||||
|
child: Container(
|
||||||
|
width: 1.sw - 30.w * 2,
|
||||||
|
// height: 300.h,
|
||||||
|
margin: EdgeInsets.all(30.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xC83C3F41),
|
||||||
|
borderRadius: BorderRadius.circular(20.h)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
bottomTopBtnWidget(),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
bottomBottomBtnWidget(),
|
||||||
|
SizedBox(height: 20.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -144,6 +152,7 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
|||||||
// 截图
|
// 截图
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
captureAndSavePng();
|
||||||
// Get.toNamed(Routers.monitoringRealTimeScreenPage);
|
// Get.toNamed(Routers.monitoringRealTimeScreenPage);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -198,13 +207,16 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
|||||||
state.udpStatus.value = 9;
|
state.udpStatus.value = 9;
|
||||||
}
|
}
|
||||||
// logic.readG711Data();
|
// logic.readG711Data();
|
||||||
logic.startProcessing();
|
if (state.isProcessing.value == false) {
|
||||||
|
logic.startProcessing();
|
||||||
|
}
|
||||||
}, longPressUp: () async {
|
}, longPressUp: () async {
|
||||||
// 长按结束
|
// 长按结束
|
||||||
print("onLongPressUp");
|
print("onLongPressUp");
|
||||||
if (state.udpStatus.value == 9) {
|
if (state.udpStatus.value == 9) {
|
||||||
state.udpStatus.value = 8;
|
state.udpStatus.value = 8;
|
||||||
}
|
}
|
||||||
|
logic.stopProcessing();
|
||||||
})),
|
})),
|
||||||
bottomBtnItemWidget(
|
bottomBtnItemWidget(
|
||||||
"images/main/icon_lockDetail_hangUp.png", "挂断", Colors.red, () async {
|
"images/main/icon_lockDetail_hangUp.png", "挂断", Colors.red, () async {
|
||||||
@ -337,8 +349,44 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> captureAndSavePng() async {
|
||||||
|
try {
|
||||||
|
if (state.globalKey.currentContext == null) {
|
||||||
|
print('截图失败: 未找到当前上下文');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RenderRepaintBoundary boundary = state.globalKey.currentContext!
|
||||||
|
.findRenderObject() as RenderRepaintBoundary;
|
||||||
|
ui.Image image = await boundary.toImage();
|
||||||
|
ByteData? byteData =
|
||||||
|
await image.toByteData(format: ui.ImageByteFormat.png);
|
||||||
|
if (byteData == null) {
|
||||||
|
print('截图失败: 图像数据为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Uint8List pngBytes = byteData.buffer.asUint8List();
|
||||||
|
|
||||||
|
// 获取应用程序的文档目录
|
||||||
|
final directory = await getApplicationDocumentsDirectory();
|
||||||
|
final imagePath = '${directory.path}/screenshot.png';
|
||||||
|
|
||||||
|
// 将截图保存为文件
|
||||||
|
File imgFile = File(imagePath);
|
||||||
|
await imgFile.writeAsBytes(pngBytes);
|
||||||
|
|
||||||
|
// 将截图保存到相册
|
||||||
|
await ImageGallerySaver.saveFile(imagePath);
|
||||||
|
|
||||||
|
print('截图保存路径: $imagePath');
|
||||||
|
logic.showToast('截图已保存到相册');
|
||||||
|
} catch (e) {
|
||||||
|
print('截图失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
logic.stopProcessing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,19 @@ class LockMonitoringState {
|
|||||||
var listPhotoData = Uint8List(0).obs; //得到的视频流字节数据
|
var listPhotoData = Uint8List(0).obs; //得到的视频流字节数据
|
||||||
var listAudioData = <int>[].obs; //得到的音频流字节数据
|
var listAudioData = <int>[].obs; //得到的音频流字节数据
|
||||||
|
|
||||||
|
//录音相关
|
||||||
late final VoiceProcessor? voiceProcessor;
|
late final VoiceProcessor? voiceProcessor;
|
||||||
|
var isProcessing = false.obs; //是否正在处理音频数据
|
||||||
|
var isButtonDisabled = false.obs; //是否禁用按钮
|
||||||
|
final int frameLength = 320; //音视频帧长度为320
|
||||||
|
final int sampleRate = 8000; //音频采样率为8000
|
||||||
|
final int volumeHistoryCapacity = 5; //音量历史记录的容量
|
||||||
|
final double dbOffset = 50.0; //用于音量计算的偏移量
|
||||||
|
var volumeHistory = <double>[].obs; //用于存储音量历史记录的列表
|
||||||
|
var smoothedVolumeValue = 0.0.obs; //存储平滑后的音量值
|
||||||
|
var errorMessage = ''.obs;
|
||||||
|
|
||||||
|
GlobalKey globalKey = GlobalKey();
|
||||||
|
|
||||||
late Timer oneMinuteTimeTimer =
|
late Timer oneMinuteTimeTimer =
|
||||||
Timer(const Duration(seconds: 1), () {}); // 定时器超过60秒关闭当前界面
|
Timer(const Duration(seconds: 1), () {}); // 定时器超过60秒关闭当前界面
|
||||||
|
|||||||
@ -99,6 +99,7 @@ class CommandUDPReciverManager {
|
|||||||
EasyLoading.showToast("开门成功", duration: 2000.milliseconds);
|
EasyLoading.showToast("开门成功", duration: 2000.milliseconds);
|
||||||
} else {
|
} else {
|
||||||
print("开门失败");
|
print("开门失败");
|
||||||
|
EasyLoading.showToast("开门失败", duration: 2000.milliseconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user