优化了tcp实时更新对UI线程的压力和对用弹窗的重复弹窗的影响。
更换了路径规划的的经纬度的字段名和取操作的名字更换。
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '13.0'
|
# platform :ios, '13.0'
|
||||||
source 'https://github.com/volcengine/volcengine-specs.git'
|
source 'https://github.com/volcengine/volcengine-specs.git'error: Classes can only extend other classes. (extends_non_class at [maibu_satabot_v2] lib\features\v2\device_list\domain\entities\video_stream_entity.dart:2)error: Classes can only extend other classes. (extends_non_class at [maibu_satabot_v2] lib\features\v2\device_list\domain\entities\video_stream_entity.dart:2)you
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,11 @@ class AuthCubit extends Cubit<AuthState> {
|
|||||||
|
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
// 🔥 冷启动时重新初始化 TCP 连接
|
// 🔥 冷启动时重新初始化 TCP 连接
|
||||||
await tcp.initializeTcp(host: TCPConsts.TCP_IP, port: TCPConsts.TCP_PORT);
|
await tcp.initializeTcp(
|
||||||
|
host: TCPConsts.TCP_IP,
|
||||||
|
port: TCPConsts.TCP_PORT,
|
||||||
|
);
|
||||||
|
|
||||||
// 2. 同步全局 App 状态
|
// 2. 同步全局 App 状态
|
||||||
appCubit.setAuth(user);
|
appCubit.setAuth(user);
|
||||||
// 3. 进入已登录状态
|
// 3. 进入已登录状态
|
||||||
|
|||||||
@@ -21,9 +21,15 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
|||||||
// 🔥 保存订阅引用,用于管理生命周期
|
// 🔥 保存订阅引用,用于管理生命周期
|
||||||
StreamSubscription? _tcpSubscription;
|
StreamSubscription? _tcpSubscription;
|
||||||
|
|
||||||
DeviceStatusBloc(this._dispatcher, {TcpClient? client})
|
// 🔥 节流相关:500ms节流控制0x02数据推送频率
|
||||||
: tcpClient = client ?? GetIt.I<TcpClient>(),
|
Timer? _throttleTimer;
|
||||||
super(DeviceStatusInitial()) {
|
static const _throttleDuration = Duration(milliseconds: 500);
|
||||||
|
RunningStatusEntity? _cachedStatus;
|
||||||
|
GPSEntity? _cachedGps;
|
||||||
|
|
||||||
|
DeviceStatusBloc(this._dispatcher, {TcpClient? client})
|
||||||
|
: tcpClient = client ?? GetIt.I<TcpClient>(),
|
||||||
|
super(DeviceStatusInitial()) {
|
||||||
// 🔥 核心改动:直接在构造函数中建立TCP监听,类似RemoteControlCubit
|
// 🔥 核心改动:直接在构造函数中建立TCP监听,类似RemoteControlCubit
|
||||||
_initDirectTcpListener();
|
_initDirectTcpListener();
|
||||||
|
|
||||||
@@ -69,97 +75,110 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
|||||||
// 🔥 关键修复:直接监听 tcpClient.packetStream,不经过 dispatcher 的 filtered stream
|
// 🔥 关键修复:直接监听 tcpClient.packetStream,不经过 dispatcher 的 filtered stream
|
||||||
// 这样即使没有其他监听者,TCP流也不会暂停
|
// 这样即使没有其他监听者,TCP流也不会暂停
|
||||||
_tcpSubscription = tcpClient.packetStream
|
_tcpSubscription = tcpClient.packetStream
|
||||||
.where((p) => p.command == 0x02)
|
.where((p) => p.command == 0x02)
|
||||||
.map((p) {
|
.map((p) {
|
||||||
try {
|
try {
|
||||||
final result = utf8.decode(p.payload, allowMalformed: true);
|
final result = utf8.decode(p.payload, allowMalformed: true);
|
||||||
// debugPrint('✅ [DeviceStatusBloc] 收到0x02数据: $result');
|
// debugPrint('✅ [DeviceStatusBloc] 收到0x02数据: $result');
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// debugPrint('❌ [DeviceStatusBloc] 解码失败: $e');
|
// debugPrint('❌ [DeviceStatusBloc] 解码失败: $e');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.listen(
|
.listen(
|
||||||
(message) {
|
(message) {
|
||||||
//debugPrint('📩 [DeviceStatusBloc] 直接收到0x02数据,长度:${message.length}');
|
//debugPrint('📩 [DeviceStatusBloc] 直接收到0x02数据,长度:${message.length}');
|
||||||
|
|
||||||
if (message.isEmpty) {
|
if (message.isEmpty) {
|
||||||
//debugPrint('⚠️ [DeviceStatusBloc] 消息为空,跳过');
|
//debugPrint('⚠️ [DeviceStatusBloc] 消息为空,跳过');
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 🔥 直接解析,不经过事件转换
|
|
||||||
final fields = message.trim().split(',');
|
|
||||||
|
|
||||||
if (fields.length < 18) {
|
|
||||||
//debugPrint('⚠️ [DeviceStatusBloc] 字段不足:${fields.length},期望≥18');
|
|
||||||
if (!isClosed) {
|
|
||||||
emit(DeviceStatusError('字段不足,期望≥18,实际:${fields.length}'));
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final status = RunningStatusEntity.fromFields(fields);
|
try {
|
||||||
final gps = GPSEntity(status.latitude, status.longitude);
|
// 🔥 直接解析,不经过事件转换
|
||||||
|
final fields = message.trim().split(',');
|
||||||
|
|
||||||
//debugPrint('✅ [DeviceStatusBloc] 直接解析成功,更新状态:Lat=${gps.latitude}, Lng=${gps.longitude}');
|
if (fields.length < 18) {
|
||||||
// _logger.log('✅ [DeviceStatusBloc] 直接解析成功,更新状态');
|
//debugPrint('⚠️ [DeviceStatusBloc] 字段不足:${fields.length},期望≥18');
|
||||||
|
// 🔥 错误不节流,立即emit以便UI显示错误
|
||||||
// 🔥 关键修复:BLoC有Equatable去重机制,必须创建新对象才能触发UI更新
|
if (!isClosed) {
|
||||||
if (!isClosed) {
|
emit(DeviceStatusError('字段不足,期望≥18,实际:${fields.length}'));
|
||||||
// 创建全新的status和gps对象,绕过Equatable去重
|
}
|
||||||
final newStatus = RunningStatusEntity(
|
return;
|
||||||
voltage: status.voltage,
|
}
|
||||||
leftTargetSpeed: status.leftTargetSpeed,
|
|
||||||
rightTargetSpeed: status.rightTargetSpeed,
|
final status = RunningStatusEntity.fromFields(fields);
|
||||||
leftMeasureSpeed: status.leftMeasureSpeed,
|
final gps = GPSEntity(status.latitude, status.longitude);
|
||||||
rightMeasureSpeed: status.rightMeasureSpeed,
|
|
||||||
leftCurrent: status.leftCurrent,
|
// 🔥 缓存最新数据用于节流发射
|
||||||
rightCurrent: status.rightCurrent,
|
_cachedStatus = RunningStatusEntity(
|
||||||
leftMotorTemp: status.leftMotorTemp,
|
voltage: status.voltage,
|
||||||
rightMotorTemp: status.rightMotorTemp,
|
leftTargetSpeed: status.leftTargetSpeed,
|
||||||
chipTemp: status.chipTemp,
|
rightTargetSpeed: status.rightTargetSpeed,
|
||||||
yaw: status.yaw,
|
leftMeasureSpeed: status.leftMeasureSpeed,
|
||||||
pitch: status.pitch,
|
rightMeasureSpeed: status.rightMeasureSpeed,
|
||||||
roll: status.roll,
|
leftCurrent: status.leftCurrent,
|
||||||
satelliteCnt: status.satelliteCnt,
|
rightCurrent: status.rightCurrent,
|
||||||
qual: status.qual,
|
leftMotorTemp: status.leftMotorTemp,
|
||||||
headingStatus: status.headingStatus,
|
rightMotorTemp: status.rightMotorTemp,
|
||||||
latitude: status.latitude,
|
chipTemp: status.chipTemp,
|
||||||
longitude: status.longitude,
|
yaw: status.yaw,
|
||||||
timestamp: status.timestamp,
|
pitch: status.pitch,
|
||||||
knifeCuttingSpeed: status.knifeCuttingSpeed,
|
roll: status.roll,
|
||||||
controlMode: status.controlMode,
|
satelliteCnt: status.satelliteCnt,
|
||||||
battery: status.battery,
|
qual: status.qual,
|
||||||
workingArea: status.workingArea,
|
headingStatus: status.headingStatus,
|
||||||
obstacleFlag: status.obstacleFlag,
|
latitude: status.latitude,
|
||||||
);
|
longitude: status.longitude,
|
||||||
final newGps = GPSEntity(status.latitude, status.longitude);
|
timestamp: status.timestamp,
|
||||||
// debugPrint('📤 [DeviceStatusBloc] emit DeviceStatusUpdated - 电压:${status.voltage}, 电量:${status.battery}, 模式:${status.controlMode}');
|
knifeCuttingSpeed: status.knifeCuttingSpeed,
|
||||||
emit(DeviceStatusUpdated(newStatus, newGps));
|
controlMode: status.controlMode,
|
||||||
}
|
battery: status.battery,
|
||||||
} catch (e, stack) {
|
workingArea: status.workingArea,
|
||||||
//debugPrint('❌ [DeviceStatusBloc] 直接解析异常:$e\n$stack');
|
obstacleFlag: status.obstacleFlag,
|
||||||
// _logger.log('❌ [DeviceStatusBloc] 直接解析异常:$e');
|
);
|
||||||
if (!isClosed) {
|
_cachedGps = GPSEntity(status.latitude, status.longitude);
|
||||||
emit(DeviceStatusError('解析失败:$e'));
|
|
||||||
}
|
// 🔥 节流:取消之前的timer,重新计时500ms
|
||||||
}
|
_throttleTimer?.cancel();
|
||||||
},
|
_throttleTimer = Timer(_throttleDuration, () {
|
||||||
onDone: () => debugPrint('⚠️ [DeviceStatusBloc] TCP流已结束(onDone)'),
|
_emitCachedStatus();
|
||||||
onError: (e) => debugPrint('❌ [DeviceStatusBloc] TCP流错误:$e'),
|
});
|
||||||
);
|
} catch (e, stack) {
|
||||||
|
//debugPrint('❌ [DeviceStatusBloc] 直接解析异常:$e\n$stack');
|
||||||
|
// _logger.log('❌ [DeviceStatusBloc] 直接解析异常:$e');
|
||||||
|
// 🔥 解析错误不节流,立即emit以便UI显示错误
|
||||||
|
if (!isClosed) {
|
||||||
|
emit(DeviceStatusError('解析失败:$e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDone: () => debugPrint('⚠️ [DeviceStatusBloc] TCP流已结束(onDone)'),
|
||||||
|
onError: (e) => debugPrint('❌ [DeviceStatusBloc] TCP流错误:$e'),
|
||||||
|
);
|
||||||
|
|
||||||
debugPrint('✅ [DeviceStatusBloc] 直接TCP监听器已建立完成');
|
debugPrint('✅ [DeviceStatusBloc] 直接TCP监听器已建立完成');
|
||||||
_logger.log('✅ [DeviceStatusBloc] 直接TCP监听器已建立完成');
|
_logger.log('✅ [DeviceStatusBloc] 直接TCP监听器已建立完成');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔥 节流发射:500ms到期后发射缓存的最新数据
|
||||||
|
void _emitCachedStatus() {
|
||||||
|
if (_cachedStatus != null && _cachedGps != null && !isClosed) {
|
||||||
|
// debugPrint('📤 [DeviceStatusBloc] 🔥节流发射 - 电压:${_cachedStatus!.voltage}, 电量:${_cachedStatus!.battery}');
|
||||||
|
emit(DeviceStatusUpdated(_cachedStatus!, _cachedGps!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 🔥 重置时仅清空状态
|
// 🔥 重置时仅清空状态
|
||||||
Future<void> _handleReset(DeviceStatusReset event, Emitter<DeviceStatusState> emit) async {
|
Future<void> _handleReset(
|
||||||
|
DeviceStatusReset event,
|
||||||
|
Emitter<DeviceStatusState> emit,
|
||||||
|
) async {
|
||||||
debugPrint('🔄 [DeviceStatusBloc] 收到重置事件:清空状态 - 当前状态:${state.runtimeType}');
|
debugPrint('🔄 [DeviceStatusBloc] 收到重置事件:清空状态 - 当前状态:${state.runtimeType}');
|
||||||
_logger.log('🔄 [DeviceStatusBloc] 收到重置事件:清空状态 - 当前状态:${state.runtimeType}');
|
_logger.log(
|
||||||
|
'🔄 [DeviceStatusBloc] 收到重置事件:清空状态 - 当前状态:${state.runtimeType}',
|
||||||
|
);
|
||||||
|
|
||||||
// 只 emit 初始状态,让 UI 清除旧设备的数据
|
// 只 emit 初始状态,让 UI 清除旧设备的数据
|
||||||
emit(DeviceStatusInitial());
|
emit(DeviceStatusInitial());
|
||||||
@@ -167,11 +186,11 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleDeviceStatusLoaded(
|
Future<void> _handleDeviceStatusLoaded(
|
||||||
DeviceStatusLoaded event,
|
DeviceStatusLoaded event,
|
||||||
Emitter<DeviceStatusState> emit,
|
Emitter<DeviceStatusState> emit,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
// debugPrint('🔍 开始解析数据:${event.jsonString}');
|
// debugPrint('🔍 开始解析数据:${event.jsonString}');
|
||||||
_logger.log('🔍 开始解析数据:${event.jsonString}');
|
_logger.log('🔍 开始解析数据:${event.jsonString}');
|
||||||
final fields = event.jsonString.trim().split(',');
|
final fields = event.jsonString.trim().split(',');
|
||||||
|
|
||||||
@@ -195,13 +214,13 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handlePushMessageReceived(
|
Future<void> _handlePushMessageReceived(
|
||||||
PushMessageReceived event,
|
PushMessageReceived event,
|
||||||
Emitter<DeviceStatusState> emit,
|
Emitter<DeviceStatusState> emit,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final eventStr = event.jsonData['event'] ?? '';
|
final eventStr = event.jsonData['event'] ?? '';
|
||||||
final deviceId = event.jsonData['deviceId'] ?? '未知';
|
final deviceId = event.jsonData['deviceId'] ?? '未知';
|
||||||
// debugPrint('收到推送事件:$eventStr, 设备:$deviceId');
|
// debugPrint('收到推送事件:$eventStr, 设备:$deviceId');
|
||||||
_logger.log('收到推送事件:$eventStr, 设备:$deviceId');
|
_logger.log('收到推送事件:$eventStr, 设备:$deviceId');
|
||||||
// 这里可以根据需要 emit 新状态
|
// 这里可以根据需要 emit 新状态
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -214,6 +233,11 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
|||||||
debugPrint('🚫 [DeviceStatusBloc] 页面退出,仅取消TCP订阅(不关闭BLoC)');
|
debugPrint('🚫 [DeviceStatusBloc] 页面退出,仅取消TCP订阅(不关闭BLoC)');
|
||||||
_logger.log('🚫 [DeviceStatusBloc] 页面退出,仅取消TCP订阅(不关闭BLoC)');
|
_logger.log('🚫 [DeviceStatusBloc] 页面退出,仅取消TCP订阅(不关闭BLoC)');
|
||||||
//_tcpSubscription?.cancel();
|
//_tcpSubscription?.cancel();
|
||||||
|
// 🔥 清理节流timer和缓存
|
||||||
|
_throttleTimer?.cancel();
|
||||||
|
_throttleTimer = null;
|
||||||
|
_cachedStatus = null;
|
||||||
|
_cachedGps = null;
|
||||||
// 🔥 关键修复:不调用 super.close(),保持 BLoC 活跃
|
// 🔥 关键修复:不调用 super.close(),保持 BLoC 活跃
|
||||||
return Future.value();
|
return Future.value();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import '../../../remote_control/domain/repositories/remote_control_repository.da
|
|||||||
import 'permission_request_event.dart';
|
import 'permission_request_event.dart';
|
||||||
import 'permission_request_state.dart';
|
import 'permission_request_state.dart';
|
||||||
|
|
||||||
class PermissionRequestBloc extends Bloc<PermissionRequestEvent, PermissionRequestState> {
|
class PermissionRequestBloc
|
||||||
|
extends Bloc<PermissionRequestEvent, PermissionRequestState> {
|
||||||
final NetMessageDispatcher _dispatcher;
|
final NetMessageDispatcher _dispatcher;
|
||||||
final RemoteControlRepository _repository;
|
final RemoteControlRepository _repository;
|
||||||
final ILoggerService _logger = GetIt.I<ILoggerService>();
|
final ILoggerService _logger = GetIt.I<ILoggerService>();
|
||||||
@@ -18,9 +19,11 @@ class PermissionRequestBloc extends Bloc<PermissionRequestEvent, PermissionReque
|
|||||||
// 🔥 保存订阅引用,用于管理生命周期
|
// 🔥 保存订阅引用,用于管理生命周期
|
||||||
StreamSubscription? _permissionSubscription;
|
StreamSubscription? _permissionSubscription;
|
||||||
|
|
||||||
PermissionRequestBloc(this._dispatcher, this._repository) : super(const PermissionRequestInitial()) {
|
PermissionRequestBloc(this._dispatcher, this._repository)
|
||||||
|
: super(const PermissionRequestInitial()) {
|
||||||
// 🔥 核心:直接在构造函数中建立 0x12 监听(通过 NetMessageDispatcher)
|
// 🔥 核心:直接在构造函数中建立 0x12 监听(通过 NetMessageDispatcher)
|
||||||
_initPermissionListener();
|
// 🔥 注意:RemoteControlCubit 已经在处理 0x12 权限请求,这里不再重复监听
|
||||||
|
// _initPermissionListener();
|
||||||
|
|
||||||
// 事件处理
|
// 事件处理
|
||||||
on<PermissionRequestReceived>(_handleRequestReceived);
|
on<PermissionRequestReceived>(_handleRequestReceived);
|
||||||
@@ -28,100 +31,53 @@ class PermissionRequestBloc extends Bloc<PermissionRequestEvent, PermissionReque
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 通过 NetMessageDispatcher 监听 TCP 0x12 指令,解析权限请求
|
// 🔥 通过 NetMessageDispatcher 监听 TCP 0x12 指令,解析权限请求
|
||||||
|
// 🔥 已禁用:RemoteControlCubit 统一处理权限请求,避免重复弹窗
|
||||||
void _initPermissionListener() {
|
void _initPermissionListener() {
|
||||||
debugPrint('🔗 [PermissionRequestBloc] 初始化 0x12 权限监听器(通过 NetMessageDispatcher)');
|
debugPrint(
|
||||||
_logger.logWithLevel('🔗 [PermissionRequestBloc] 初始化 0x12 权限监听器', shouldLog: true);
|
'🔗 [PermissionRequestBloc] 初始化 0x12 权限监听器(通过 NetMessageDispatcher)',
|
||||||
|
);
|
||||||
|
_logger.logWithLevel(
|
||||||
|
'🔗 [PermissionRequestBloc] 初始化 0x12 权限监听器',
|
||||||
|
shouldLog: true,
|
||||||
|
);
|
||||||
|
|
||||||
_permissionSubscription = _dispatcher.onCommand(0x12).listen((packet) {
|
// 🔥 已禁用:权限请求统一由 RemoteControlCubit 处理,避免重复弹窗
|
||||||
|
// _permissionSubscription = _dispatcher.onCommand(0x12).listen((packet) {
|
||||||
debugPrint('🔍 [PermissionRequestBloc] ✅✅✅ 0x12 包被监听到了!');
|
// ...
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ✅✅✅ 0x12 包被监听到了!', shouldLog: true);
|
// });
|
||||||
|
|
||||||
try {
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ✅ 收到 0x12 原始包', shouldLog: true);
|
|
||||||
|
|
||||||
// 🔥 关键:手动去掉最后 2 个 CRC 字节
|
|
||||||
String jsonString;
|
|
||||||
if (packet.payload.length > 2) {
|
|
||||||
jsonString = utf8.decode(packet.payload.sublist(0, packet.payload.length - 2));
|
|
||||||
} else {
|
|
||||||
jsonString = utf8.decode(packet.payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('>>> [PermissionRequestBloc] 收到 0x12: $jsonString');
|
debugPrint(
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 收到 0x12: $jsonString', shouldLog: true);
|
'🔍 [PermissionRequestBloc] ⚠️ 权限监听已禁用,统一由 RemoteControlCubit 处理',
|
||||||
|
);
|
||||||
final jsonMap = jsonDecode(jsonString);
|
_logger.logWithLevel(
|
||||||
final requestType = jsonMap['request'];
|
'>>> [PermissionRequestBloc] ⚠️ 权限监听已禁用,统一由 RemoteControlCubit 处理',
|
||||||
final platform = jsonMap['platform'];
|
shouldLog: true,
|
||||||
final respondData = jsonMap['respond'];
|
);
|
||||||
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 解析结果: requestType=$requestType, platform=$platform', shouldLog: true);
|
|
||||||
|
|
||||||
// 情况 1: 响应格式(忽略)
|
|
||||||
if (respondData != null && respondData is Map) {
|
|
||||||
debugPrint('>>> [PermissionRequestBloc] 📊 收到响应格式,忽略');
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 📊 收到响应格式,忽略', shouldLog: true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 情况 2: 请求格式 - switch_control
|
|
||||||
if (requestType == 'switch_control') {
|
|
||||||
// 🔥 关键判断:只有当是其他平台(web)请求时才弹窗
|
|
||||||
if (platform != null && platform.toString().toLowerCase() != 'app') {
|
|
||||||
debugPrint('>>> [PermissionRequestBloc] 🚨 $platform 端请求控制权');
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 🚨 $platform 端请求控制权', shouldLog: true);
|
|
||||||
|
|
||||||
if (!isClosed) {
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 📤 准备 add PermissionRequestReceived 事件', shouldLog: true);
|
|
||||||
add(PermissionRequestReceived(
|
|
||||||
platform: platform.toString(),
|
|
||||||
requestType: requestType,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ⚠️ Bloc 已关闭,无法添加事件', shouldLog: true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debugPrint('>>> [PermissionRequestBloc] ℹ️ APP 自己的请求回显,忽略');
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ℹ️ APP 自己的请求回显,忽略', shouldLog: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 情况 3: 异地登录通知
|
|
||||||
else if (requestType == 'have_logged_in') {
|
|
||||||
debugPrint('>>> [PermissionRequestBloc] ⚠️ 检测到异地登录');
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ⚠️ 检测到异地登录', shouldLog: true);
|
|
||||||
|
|
||||||
if (!isClosed) {
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] 📤 准备 add PermissionRequestReceived 事件(异地登录)', shouldLog: true);
|
|
||||||
add(PermissionRequestReceived(
|
|
||||||
platform: 'unknown',
|
|
||||||
requestType: requestType,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('>>> [PermissionRequestBloc] ❌ 解析失败:$e');
|
|
||||||
_logger.logWithLevel('>>> [PermissionRequestBloc] ❌ 解析失败:$e', shouldLog: true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
debugPrint('✅ [PermissionRequestBloc] 0x12 监听器已建立完成');
|
|
||||||
_logger.logWithLevel('✅ [PermissionRequestBloc] 0x12 监听器已建立完成', shouldLog: true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleRequestReceived(
|
Future<void> _handleRequestReceived(
|
||||||
PermissionRequestReceived event,
|
PermissionRequestReceived event,
|
||||||
Emitter<PermissionRequestState> emit,
|
Emitter<PermissionRequestState> emit,
|
||||||
) async {
|
) async {
|
||||||
debugPrint('📤 [PermissionRequestBloc] emit DialogVisible - platform=${event.platform}');
|
debugPrint(
|
||||||
_logger.logWithLevel('📤 [PermissionRequestBloc] emit DialogVisible - platform=${event.platform}', shouldLog: true);
|
'📤 [PermissionRequestBloc] emit DialogVisible - platform=${event.platform}',
|
||||||
|
);
|
||||||
emit(PermissionRequestDialogVisible(
|
_logger.logWithLevel(
|
||||||
platform: event.platform,
|
'📤 [PermissionRequestBloc] emit DialogVisible - platform=${event.platform}',
|
||||||
requestType: event.requestType,
|
shouldLog: true,
|
||||||
));
|
);
|
||||||
|
|
||||||
_logger.logWithLevel('📤 [PermissionRequestBloc] ✅ 已 emit DialogVisible 状态', shouldLog: true);
|
emit(
|
||||||
|
PermissionRequestDialogVisible(
|
||||||
|
platform: event.platform,
|
||||||
|
requestType: event.requestType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
_logger.logWithLevel(
|
||||||
|
'📤 [PermissionRequestBloc] ✅ 已 emit DialogVisible 状态',
|
||||||
|
shouldLog: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleDialogDismissed(
|
Future<void> _handleDialogDismissed(
|
||||||
@@ -130,13 +86,15 @@ class PermissionRequestBloc extends Bloc<PermissionRequestEvent, PermissionReque
|
|||||||
) async {
|
) async {
|
||||||
debugPrint('📤 [PermissionRequestBloc] emit DialogHidden');
|
debugPrint('📤 [PermissionRequestBloc] emit DialogHidden');
|
||||||
_logger.logWithLevel('📤 [PermissionRequestBloc] emit DialogHidden');
|
_logger.logWithLevel('📤 [PermissionRequestBloc] emit DialogHidden');
|
||||||
|
|
||||||
// 🔥 发送响应到机器人(和远程遥控页面一样)
|
// 🔥 发送响应到机器人(和远程遥控页面一样)
|
||||||
if (event.deviceId.isNotEmpty) {
|
if (event.deviceId.isNotEmpty) {
|
||||||
debugPrint('📤 [PermissionRequestBloc] 发送权限响应: agree=${event.agree}, deviceId=${event.deviceId}');
|
debugPrint(
|
||||||
|
'📤 [PermissionRequestBloc] 发送权限响应: agree=${event.agree}, deviceId=${event.deviceId}',
|
||||||
|
);
|
||||||
_repository.respondPermission(event.agree, event.deviceId);
|
_repository.respondPermission(event.agree, event.deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(const PermissionRequestDialogHidden());
|
emit(const PermissionRequestDialogHidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,11 +105,14 @@ class PermissionRequestBloc extends Bloc<PermissionRequestEvent, PermissionReque
|
|||||||
_permissionSubscription?.cancel();
|
_permissionSubscription?.cancel();
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 🔥 公开方法:重新初始化监听器(TCP 重连后调用)
|
/// 🔥 公开方法:重新初始化监听器(TCP 重连后调用)
|
||||||
void reinitListener() {
|
void reinitListener() {
|
||||||
debugPrint('🔄 [PermissionRequestBloc] 重新初始化监听器');
|
debugPrint('🔄 [PermissionRequestBloc] 重新初始化监听器');
|
||||||
_logger.logWithLevel('🔄 [PermissionRequestBloc] 重新初始化监听器', shouldLog: true);
|
_logger.logWithLevel(
|
||||||
|
'🔄 [PermissionRequestBloc] 重新初始化监听器',
|
||||||
|
shouldLog: true,
|
||||||
|
);
|
||||||
_permissionSubscription?.cancel();
|
_permissionSubscription?.cancel();
|
||||||
_initPermissionListener();
|
_initPermissionListener();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1472,13 +1472,13 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
|||||||
List<LatLng> newOuterPoints = [];
|
List<LatLng> newOuterPoints = [];
|
||||||
for (var item in pathList) {
|
for (var item in pathList) {
|
||||||
double? lat = safeToDouble(item['lat']);
|
double? lat = safeToDouble(item['lat']);
|
||||||
double? lon = safeToDouble(item['lon']);
|
double? lon = safeToDouble(item['lng'] ?? item['lon']);
|
||||||
if (lat != null && lon != null) {
|
if (lat != null && lon != null) {
|
||||||
newPathPoints.add(convertWGS84ToGCJ02(lat, lon));
|
newPathPoints.add(convertWGS84ToGCJ02(lat, lon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var item in outerList) {
|
for (var item in outerList) {
|
||||||
double? lng = safeToDouble(item['lng']);
|
double? lng = safeToDouble(item['lng'] ?? item['lon']);
|
||||||
double? lat = safeToDouble(item['lat']);
|
double? lat = safeToDouble(item['lat']);
|
||||||
if (lng != null && lat != null) {
|
if (lng != null && lat != null) {
|
||||||
newOuterPoints.add(convertWGS84ToGCJ02(lat, lng));
|
newOuterPoints.add(convertWGS84ToGCJ02(lat, lng));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:dart_ping/dart_ping.dart';
|
import 'package:dart_ping/dart_ping.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
@@ -39,13 +40,12 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
int _currentOriginX = 0;
|
int _currentOriginX = 0;
|
||||||
int _currentOriginY = 0;
|
int _currentOriginY = 0;
|
||||||
|
|
||||||
// 🔥 权限请求冷却期机制 - 防止Web端持续发送请求导致弹窗不断显示
|
// 🔥 权限请求处理标志位 - 防止竞态条件,避免重复显示弹窗
|
||||||
DateTime? _lastPermissionResponseTime; // 记录上次响应权限请求的时间
|
|
||||||
static const _coolDownDuration = Duration(seconds: 5); // 冷却期5秒
|
|
||||||
|
|
||||||
// 🔥 同步锁 - 防止状态更新期间接收新请求导致重复弹窗
|
|
||||||
bool _isProcessingPermissionRequest = false;
|
bool _isProcessingPermissionRequest = false;
|
||||||
|
|
||||||
|
// 🔥 模拟数据推送定时器
|
||||||
|
// Timer? _simulationTimer;
|
||||||
|
|
||||||
// 🔥 获取带时间戳的日志前缀
|
// 🔥 获取带时间戳的日志前缀
|
||||||
String _getTimePrefix() {
|
String _getTimePrefix() {
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
@@ -69,40 +69,138 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 新增:订阅 DeviceStatusBloc 的状态流,而不是直接监听TCP
|
// 🔥 新增:订阅 DeviceStatusBloc 的状态流,而不是直接监听TCP
|
||||||
|
// 类全局变量
|
||||||
|
DateTime? _lastUiUpdateTime;
|
||||||
|
String? _cacheVoltage;
|
||||||
|
String? _cacheBattery;
|
||||||
|
String? _cacheCtrlMode;
|
||||||
|
int? _cachePing;
|
||||||
|
|
||||||
void _initDeviceStatusListener() {
|
void _initDeviceStatusListener() {
|
||||||
// // _logger.logWithLevel('>>> [RemoteControl] begin 订阅 DeviceStatusBloc 状态流');
|
|
||||||
_deviceStatusSub?.cancel();
|
_deviceStatusSub?.cancel();
|
||||||
|
|
||||||
_deviceStatusSub = deviceStatusBloc.stream.listen((deviceState) async {
|
_deviceStatusSub = deviceStatusBloc.stream.listen((deviceState) async {
|
||||||
if (deviceState is DeviceStatusUpdated) {
|
if (deviceState is DeviceStatusUpdated) {
|
||||||
|
// 第一步:所有数据先存入缓存,不管来多频繁都存最新值
|
||||||
final voltage = deviceState.status.voltage;
|
final voltage = deviceState.status.voltage;
|
||||||
final battery = deviceState.status.battery;
|
final battery = deviceState.status.battery;
|
||||||
final controlMode = deviceState.status.controlMode == '3'
|
final controlMode = deviceState.status.controlMode == '3'
|
||||||
? '远程模式'
|
? '远程模式'
|
||||||
: '本地模式';
|
: '本地模式';
|
||||||
|
final c = await getNetworkDelay();
|
||||||
|
|
||||||
final c = getNetworkDelay();
|
_cacheVoltage = voltage.toString();
|
||||||
|
_cacheBattery = battery.toString();
|
||||||
|
_cacheCtrlMode = controlMode;
|
||||||
|
_cachePing = c;
|
||||||
|
|
||||||
|
// 500ms节流,不到时间不刷新UI
|
||||||
|
final now = DateTime.now();
|
||||||
|
if (_lastUiUpdateTime != null &&
|
||||||
|
now.difference(_lastUiUpdateTime!) <
|
||||||
|
const Duration(milliseconds: 500)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_lastUiUpdateTime = now;
|
||||||
|
|
||||||
|
// 间隔达标,统一一次刷新UI
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
runningStatusModel: state.runningStatusModel.copyWith(
|
runningStatusModel: state.runningStatusModel.copyWith(
|
||||||
voltage: voltage.toString(),
|
voltage: _cacheVoltage,
|
||||||
battery: battery.toString(),
|
battery: _cacheBattery,
|
||||||
controlMode: controlMode,
|
controlMode: _cacheCtrlMode,
|
||||||
),
|
),
|
||||||
battery: int.tryParse(battery) ?? 0,
|
battery: int.tryParse(_cacheBattery ?? '') ?? 0,
|
||||||
ping: await c,
|
ping: _cachePing,
|
||||||
|
// 🔥 标记为设备状态更新
|
||||||
|
updateType: 'device_status',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// // _logger.logWithLevel('✅ [RemoteControl] 从 DeviceStatusBloc 收到更新: 电压=$voltage, 电量=$battery, 模式=$controlMode');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// _logger.logWithLevel('>>> [RemoteControl] ✅ DeviceStatusBloc 订阅已建立完成');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 超简单方法:传入 IP,得到 ping 值
|
// 🔥 超简单方法:传入 IP,得到 ping 值
|
||||||
|
|
||||||
|
// 🔥 模拟设备状态更新 - 用于测试
|
||||||
|
// void simulateDeviceStatusUpdate({
|
||||||
|
// String? voltage,
|
||||||
|
// String? battery,
|
||||||
|
// String? controlMode,
|
||||||
|
// int? ping,
|
||||||
|
// // 🔥 是否随机生成数据
|
||||||
|
// bool random = false,
|
||||||
|
// }) {
|
||||||
|
// // 如果开启随机模式,生成随机数据
|
||||||
|
// final rand = Random();
|
||||||
|
|
||||||
|
/* if (random) {
|
||||||
|
voltage = (22.0 + rand.nextDouble() * 4.0).toStringAsFixed(
|
||||||
|
1,
|
||||||
|
); // 22.0-26.0V
|
||||||
|
battery = (rand.nextInt(100) + 1).toString(); // 1-100%
|
||||||
|
controlMode = rand.nextBool() ? '远程模式' : '本地模式';
|
||||||
|
ping = rand.nextInt(150) + 20; // 20-170ms
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* debugPrint(
|
||||||
|
'🔧 [模拟设备状态更新] voltage=$voltage V, battery=$battery%, controlMode=$controlMode, ping=$ping ms',
|
||||||
|
); */
|
||||||
|
|
||||||
|
// 更新缓存
|
||||||
|
/* if (voltage != null) _cacheVoltage = voltage;
|
||||||
|
if (battery != null) _cacheBattery = battery;
|
||||||
|
if (controlMode != null) _cacheCtrlMode = controlMode;
|
||||||
|
if (ping != null) _cachePing = ping;
|
||||||
|
|
||||||
|
// 直接触发状态更新(跳过节流,立即更新)
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
runningStatusModel: state.runningStatusModel.copyWith(
|
||||||
|
voltage: _cacheVoltage,
|
||||||
|
battery: _cacheBattery,
|
||||||
|
controlMode: _cacheCtrlMode,
|
||||||
|
),
|
||||||
|
battery: int.tryParse(_cacheBattery ?? '') ?? 0,
|
||||||
|
ping: _cachePing,
|
||||||
|
// 🔥 标记为设备状态更新
|
||||||
|
updateType: 'device_status',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} */
|
||||||
|
|
||||||
|
// 🔥 开始模拟设备状态推送(随机数据)
|
||||||
|
/* void startSimulation({int intervalMs = 500}) {
|
||||||
|
// 如果已经在运行,先停止
|
||||||
|
stopSimulation();
|
||||||
|
|
||||||
|
// debugPrint('🔔 [模拟推送] 开始模拟设备状态推送,间隔:${intervalMs}ms');
|
||||||
|
|
||||||
|
// 立即发送一次初始数据
|
||||||
|
simulateDeviceStatusUpdate(random: true);
|
||||||
|
|
||||||
|
// 定时推送随机数据
|
||||||
|
_simulationTimer = Timer.periodic(Duration(milliseconds: intervalMs), (
|
||||||
|
timer,
|
||||||
|
) {
|
||||||
|
if (!isClosed) {
|
||||||
|
simulateDeviceStatusUpdate(random: true);
|
||||||
|
} else {
|
||||||
|
stopSimulation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} */
|
||||||
|
|
||||||
|
// 🔥 停止模拟设备状态推送
|
||||||
|
/* void stopSimulation() {
|
||||||
|
if (_simulationTimer != null) {
|
||||||
|
_simulationTimer!.cancel();
|
||||||
|
_simulationTimer = null;
|
||||||
|
debugPrint('🔔 [模拟推送] 已停止模拟设备状态推送');
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
// 🔥 辅助方法:更新运行状态
|
// 🔥 辅助方法:更新运行状态
|
||||||
void _updateStatusFromDevice(RunningStatusModel newStatus) {
|
void _updateStatusFromDevice(RunningStatusModel newStatus) {
|
||||||
// // debugPrint('✅ [_updateStatusFromDevice] 收到运行状态更新:$newStatus');
|
// // debugPrint('✅ [_updateStatusFromDevice] 收到运行状态更新:$newStatus');
|
||||||
@@ -141,14 +239,37 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
_kickOutSub = dispatcher.onCommand(0x12).listen((packet) {
|
_kickOutSub = dispatcher.onCommand(0x12).listen((packet) {
|
||||||
final timeNow = _getTimePrefix();
|
final timeNow = _getTimePrefix();
|
||||||
debugPrint('$timeNow 🔍 [RemoteControl] [0x12监听器] ✅ 收到 0x12 原始包');
|
debugPrint('$timeNow 🔍 [RemoteControl] [0x12监听器] ✅ 收到 0x12 原始包');
|
||||||
debugPrint(
|
/* debugPrint(
|
||||||
'$timeNow 🔍 [RemoteControl] [0x12监听器] payload长度: ${packet.payload.length}',
|
'$timeNow 🔍 [RemoteControl] [0x12监听器] payload长度: ${packet.payload.length}',
|
||||||
);
|
);*/
|
||||||
_logger.logWithLevel(
|
_logger.logWithLevel(
|
||||||
'$timeNow 🔍 [RemoteControl] [0x12监听器] 收到 0x12 原始包,payload长度=${packet.payload.length}',
|
'$timeNow 🔍 [RemoteControl] [0x12监听器] 收到 0x12 原始包,payload长度=${packet.payload.length}',
|
||||||
shouldLog: true,
|
shouldLog: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 先解析JSON判断是否为响应格式
|
||||||
|
String jsonStringForCheck;
|
||||||
|
try {
|
||||||
|
if (packet.payload.length > 2) {
|
||||||
|
jsonStringForCheck = utf8.decode(
|
||||||
|
packet.payload.sublist(0, packet.payload.length - 2),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
jsonStringForCheck = utf8.decode(packet.payload);
|
||||||
|
}
|
||||||
|
final jsonMap = jsonDecode(jsonStringForCheck);
|
||||||
|
final respondData = jsonMap['respond'];
|
||||||
|
|
||||||
|
// 如果是响应格式,继续处理(更新权限状态)
|
||||||
|
// 如果是请求格式且弹窗已显示,忽略
|
||||||
|
if (respondData == null && state.showPermissionRequestDialog) {
|
||||||
|
debugPrint('$timeNow 🔍 [RemoteControl] [0x12监听器] ⚠️ 弹窗已显示(状态),忽略请求');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 解析失败,继续处理
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 🔥 关键:手动去掉最后 2 个 CRC 字节
|
// 🔥 关键:手动去掉最后 2 个 CRC 字节
|
||||||
String jsonString;
|
String jsonString;
|
||||||
@@ -179,11 +300,13 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
|
|
||||||
// 情况 1: 响应格式 - {"respond":{"switchResult":true,"deviceId":"...","holder":"you"}}
|
// 情况 1: 响应格式 - {"respond":{"switchResult":true,"deviceId":"...","holder":"you"}}
|
||||||
if (respondData != null && respondData is Map) {
|
if (respondData != null && respondData is Map) {
|
||||||
|
// 🔥 收到响应格式,更新权限状态
|
||||||
|
|
||||||
final switchResult = respondData['switchResult'];
|
final switchResult = respondData['switchResult'];
|
||||||
debugPrint('$timeNow 🔍 [RemoteControl] [0x12监听器] 📊 收到切换结果响应');
|
/* debugPrint('$timeNow 🔍 [RemoteControl] [0x12监听器] 📊 收到切换结果响应');
|
||||||
debugPrint(
|
debugPrint(
|
||||||
'$timeNow 🔍 [RemoteControl] [0x12监听器] switchResult: $switchResult',
|
'$timeNow 🔍 [RemoteControl] [0x12监听器] switchResult: $switchResult',
|
||||||
);
|
);*/
|
||||||
_logger.logWithLevel(
|
_logger.logWithLevel(
|
||||||
'$timeNow 🔍 [RemoteControl] [0x12监听器] 📊 收到切换结果响应 - switchResult: $switchResult',
|
'$timeNow 🔍 [RemoteControl] [0x12监听器] 📊 收到切换结果响应 - switchResult: $switchResult',
|
||||||
shouldLog: true,
|
shouldLog: true,
|
||||||
@@ -218,6 +341,15 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
final webLogPrefix =
|
final webLogPrefix =
|
||||||
'${_getTimePrefix()} 🚨 [RemoteControl] [Web端权限请求]';
|
'${_getTimePrefix()} 🚨 [RemoteControl] [Web端权限请求]';
|
||||||
|
|
||||||
|
// 🔥 新增:记录收到请求的时间,便于排查是否为后端持续推送
|
||||||
|
debugPrint(
|
||||||
|
'$webLogPrefix ⚡️⚡️⚡️ 收到Web端权限请求 - ${DateTime.now().toString()}',
|
||||||
|
);
|
||||||
|
_logger.logWithLevel(
|
||||||
|
'$webLogPrefix ⚡️⚡️⚡️ 收到Web端权限请求 - ${DateTime.now().toString()}',
|
||||||
|
shouldLog: true,
|
||||||
|
);
|
||||||
|
|
||||||
debugPrint('$webLogPrefix =========================================');
|
debugPrint('$webLogPrefix =========================================');
|
||||||
debugPrint('$webLogPrefix 收到 switch_control 请求');
|
debugPrint('$webLogPrefix 收到 switch_control 请求');
|
||||||
debugPrint('$webLogPrefix platform: $platform');
|
debugPrint('$webLogPrefix platform: $platform');
|
||||||
@@ -235,28 +367,32 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
|
|
||||||
if (currentDeviceId != null && requestDeviceId == currentDeviceId) {
|
if (currentDeviceId != null && requestDeviceId == currentDeviceId) {
|
||||||
debugPrint('$webLogPrefix 设备ID匹配');
|
debugPrint('$webLogPrefix 设备ID匹配');
|
||||||
// 🔥 添加防重复检查:只有当弹窗还没显示时才弹出
|
|
||||||
if (!state.showPermissionRequestDialog) {
|
// 🔥 只有当弹窗还没显示时才弹出,防止重复弹窗叠加
|
||||||
debugPrint('$webLogPrefix 弹出权限请求对话框');
|
if (state.showPermissionRequestDialog) {
|
||||||
_logger.logWithLevel(
|
|
||||||
'$webLogPrefix 设备ID匹配,弹出权限请求对话框',
|
|
||||||
shouldLog: true,
|
|
||||||
);
|
|
||||||
if (!isClosed) {
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
showPermissionRequestDialog: true,
|
|
||||||
requestingDeviceId: requestDeviceId?.toString(),
|
|
||||||
requestingPlatform: platform.toString(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debugPrint('$webLogPrefix ⚠️ 弹窗已显示,忽略重复请求');
|
debugPrint('$webLogPrefix ⚠️ 弹窗已显示,忽略重复请求');
|
||||||
_logger.logWithLevel(
|
_logger.logWithLevel(
|
||||||
'$webLogPrefix ⚠️ 弹窗已显示,忽略重复请求',
|
'$webLogPrefix ⚠️ 弹窗已显示,忽略重复请求',
|
||||||
shouldLog: true,
|
shouldLog: true,
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('$webLogPrefix 弹出权限请求对话框');
|
||||||
|
_logger.logWithLevel(
|
||||||
|
'$webLogPrefix 设备ID匹配,弹出权限请求对话框',
|
||||||
|
shouldLog: true,
|
||||||
|
);
|
||||||
|
if (!isClosed) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
showPermissionRequestDialog: true,
|
||||||
|
requestingDeviceId: requestDeviceId?.toString(),
|
||||||
|
requestingPlatform: platform.toString(),
|
||||||
|
// 🔥 标记为弹窗状态更新
|
||||||
|
updateType: 'permission_dialog',
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debugPrint('$webLogPrefix ⚠️ 设备ID不匹配,忽略');
|
debugPrint('$webLogPrefix ⚠️ 设备ID不匹配,忽略');
|
||||||
@@ -284,7 +420,8 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
'${_getTimePrefix()} ⚠️ [RemoteControl] 检测到异地登录,打开弹窗提示',
|
'${_getTimePrefix()} ⚠️ [RemoteControl] 检测到异地登录,打开弹窗提示',
|
||||||
shouldLog: true,
|
shouldLog: true,
|
||||||
);
|
);
|
||||||
if (!isClosed) {
|
// 🔥 只有当弹窗还没显示时才弹出
|
||||||
|
if (!isClosed && !state.showPermissionRequestDialog) {
|
||||||
emit(state.copyWith(showPermissionRequestDialog: true));
|
emit(state.copyWith(showPermissionRequestDialog: true));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -331,6 +468,9 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
//debugPrint('$logPrefix 启动控制循环,间隔: 100ms');
|
//debugPrint('$logPrefix 启动控制循环,间隔: 100ms');
|
||||||
///debugPrint('$logPrefix =========================================');
|
///debugPrint('$logPrefix =========================================');
|
||||||
|
|
||||||
|
// 🔥 启动模拟设备状态推送(用于测试)
|
||||||
|
// startSimulation();
|
||||||
|
|
||||||
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
|
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
|
||||||
if (isClosed) {
|
if (isClosed) {
|
||||||
// debugPrint('$logPrefix ❌ Cubit已关闭,取消定时器');
|
// debugPrint('$logPrefix ❌ Cubit已关闭,取消定时器');
|
||||||
@@ -538,27 +678,16 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void respondPermission(bool agreed, String deviceId) {
|
void respondPermission(bool agreed, String deviceId) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 🔥 记录响应时间,开启冷却期
|
|
||||||
_lastPermissionResponseTime = DateTime.now();
|
|
||||||
//debugPrint('$logPrefix 开启权限请求冷却期,持续${_coolDownDuration.inSeconds}秒');
|
|
||||||
|
|
||||||
// 1. 关闭弹窗(立即关闭,防止重复点击)
|
// 1. 关闭弹窗(立即关闭,防止重复点击)
|
||||||
emit(state.copyWith(showPermissionRequestDialog: false));
|
emit(state.copyWith(showPermissionRequestDialog: false));
|
||||||
|
|
||||||
// 2. 发送响应到服务器
|
// 2. 发送响应到服务器
|
||||||
//debugPrint('$logPrefix 📤 发送权限响应命令到服务器');
|
|
||||||
try {
|
try {
|
||||||
// 🔥 关键调用:发送 TCP 指令
|
|
||||||
debugPrint('{_coolDownDuration.inSeconds}秒');
|
|
||||||
_repository.respondPermission(agreed, deviceId);
|
_repository.respondPermission(agreed, deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(' ❌ TCP权限响应指令发送失败: $e');
|
debugPrint(' ❌ TCP权限响应指令发送失败: $e');
|
||||||
debugPrint(' ❌ 错误类型: ${e.runtimeType}');
|
debugPrint(' ❌ 错误类型: ${e.runtimeType}');
|
||||||
_logger.logWithLevel(' TCP权限响应指令发送失败 $e', shouldLog: true);
|
_logger.logWithLevel(' TCP权限响应指令发送失败 $e', shouldLog: true);
|
||||||
// 即使发送失败,也要更新状态
|
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,9 +706,7 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
state.copyWith(hasPermission: true, showPermissionRequestDialog: false),
|
state.copyWith(hasPermission: true, showPermissionRequestDialog: false),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
debugPrint(
|
debugPrint('${_getTimePrefix()} ====权限弹窗响应结束=====');
|
||||||
'${_getTimePrefix()} ====权限弹窗响应结束=====',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> requestControlPermissionS(
|
Future<void> requestControlPermissionS(
|
||||||
@@ -625,12 +752,13 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
final failLogPrefix =
|
final failLogPrefix =
|
||||||
'${_getTimePrefix()} 🔑 [RemoteControl] [请求权限接口-$source]';
|
'${_getTimePrefix()} 🔑 [RemoteControl] [请求权限接口-$source]';
|
||||||
debugPrint('$failLogPrefix APP请求控制权限失败: ${failure.message}');
|
debugPrint('$failLogPrefix APP请求控制权限失败: ${failure.message}');
|
||||||
debugPrint('$failLogPrefix 重新打开权限请求弹窗');
|
|
||||||
_logger.logWithLevel(
|
_logger.logWithLevel(
|
||||||
'$failLogPrefix APP请求控制权限失败: ${failure.message}',
|
'$failLogPrefix APP请求控制权限失败: ${failure.message}',
|
||||||
shouldLog: true,
|
shouldLog: true,
|
||||||
);
|
);
|
||||||
emit(state.copyWith(showPermissionRequestDialog: true));
|
// 🔥 修复:HTTP请求失败时不要自动打开弹窗,避免形成循环
|
||||||
|
// emit(state.copyWith(showPermissionRequestDialog: true));
|
||||||
|
debugPrint('$failLogPrefix HTTP请求失败,不自动打开弹窗');
|
||||||
},
|
},
|
||||||
(permissionInfo) async {
|
(permissionInfo) async {
|
||||||
final bool hasPermission =
|
final bool hasPermission =
|
||||||
@@ -689,7 +817,11 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 🔥 权限弹窗确认后调用- 发送TCP响应 + HTTP确认最终权限状态
|
/// 🔥 重置弹窗状态 - 在弹窗关闭后调用(已简化,不再需要标志位)
|
||||||
|
void resetPermissionCoolDown() {
|
||||||
|
// 标志位已移除,此方法保留以保持向后兼容性
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> confirmPermissionResponse(
|
Future<void> confirmPermissionResponse(
|
||||||
String deviceName,
|
String deviceName,
|
||||||
String platform,
|
String platform,
|
||||||
@@ -702,11 +834,12 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
debugPrint('$logPrefix 用户操作: ${agreed ? "同意" : "拒绝"}');
|
debugPrint('$logPrefix 用户操作: ${agreed ? "同意" : "拒绝"}');
|
||||||
debugPrint('$logPrefix deviceName: $deviceName');
|
debugPrint('$logPrefix deviceName: $deviceName');
|
||||||
debugPrint('$logPrefix platform: $platform');
|
debugPrint('$logPrefix platform: $platform');
|
||||||
|
|
||||||
respondPermission(agreed, deviceName);
|
respondPermission(agreed, deviceName);
|
||||||
|
|
||||||
// 2. 调用 HTTP 接口获取最终权限状态
|
// 2. 调用 HTTP 接口获取最终权限状态
|
||||||
debugPrint('$logPrefix 📡 调用 HTTP 接口确认最终权限状态..');
|
debugPrint('$logPrefix 📡 调用 HTTP 接口确认最终权限状态..');
|
||||||
/* final result = await _requestControlPermissionUseCase(
|
/* final result = await _requestControlPermissionUseCase(
|
||||||
RequestControlPermissionParams(
|
RequestControlPermissionParams(
|
||||||
deviceName: deviceName,
|
deviceName: deviceName,
|
||||||
deviceId: platform,
|
deviceId: platform,
|
||||||
@@ -714,7 +847,7 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
);*/
|
);*/
|
||||||
|
|
||||||
// 3. 根据 HTTP 返回的真实权限状态更新UI
|
// 3. 根据 HTTP 返回的真实权限状态更新UI
|
||||||
/* result.fold(
|
/* result.fold(
|
||||||
(failure) {
|
(failure) {
|
||||||
final failLogPrefix = '${_getTimePrefix()} 🔑 [RemoteControl] [权限确认]';
|
final failLogPrefix = '${_getTimePrefix()} 🔑 [RemoteControl] [权限确认]';
|
||||||
debugPrint('$failLogPrefix APP HTTP请求失败: ${failure.message}');
|
debugPrint('$failLogPrefix APP HTTP请求失败: ${failure.message}');
|
||||||
@@ -734,7 +867,7 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
|
|||||||
'$successLogPrefix 🔄 正在更新UI - hasPermission: ${state.hasPermission} -> $hasPermission',
|
'$successLogPrefix 🔄 正在更新UI - hasPermission: ${state.hasPermission} -> $hasPermission',
|
||||||
);
|
);
|
||||||
// 🔥 直接用HTTP 返回的权限状态覆盖
|
// 🔥 直接用HTTP 返回的权限状态覆盖
|
||||||
emit(state.copyWith(hasPermission: hasPermission));
|
// emit(state.copyWith(hasPermission: hasPermission));
|
||||||
debugPrint(
|
debugPrint(
|
||||||
'$successLogPrefix 📊 UI已同步完成- 当前 hasPermission=$hasPermission',
|
'$successLogPrefix 📊 UI已同步完成- 当前 hasPermission=$hasPermission',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ class RemoteControlState extends Equatable {
|
|||||||
final bool isEmergency;
|
final bool isEmergency;
|
||||||
final bool isLocked;
|
final bool isLocked;
|
||||||
final int ping;
|
final int ping;
|
||||||
final int battery;//电池量
|
final int battery; //电池量
|
||||||
final int voltage;//电压
|
final int voltage; //电压
|
||||||
final String permissionPlatform;
|
final String permissionPlatform;
|
||||||
final String currentPlatform;
|
final String currentPlatform;
|
||||||
final bool showPermissionRequestDialog;
|
final bool showPermissionRequestDialog;
|
||||||
@@ -28,8 +28,11 @@ class RemoteControlState extends Equatable {
|
|||||||
final bool obstacleRecognitionFlag; // 障碍物识别标志位(这是UI显示的)
|
final bool obstacleRecognitionFlag; // 障碍物识别标志位(这是UI显示的)
|
||||||
|
|
||||||
final String obstacleFlag; //障碍物标志位
|
final String obstacleFlag; //障碍物标志位
|
||||||
final DeviceEntity? targetDevice; // 🔥 待控制的设备
|
|
||||||
final RunningStatusModel runningStatusModel;
|
final RunningStatusModel runningStatusModel;
|
||||||
|
final DeviceEntity? targetDevice;
|
||||||
|
|
||||||
|
// 🔥 状态更新类型标记 - 用于区分是设备状态更新还是弹窗状态更新
|
||||||
|
final String? updateType;
|
||||||
|
|
||||||
const RemoteControlState({
|
const RemoteControlState({
|
||||||
this.status = RemoteControlStatus.initial,
|
this.status = RemoteControlStatus.initial,
|
||||||
@@ -53,6 +56,7 @@ class RemoteControlState extends Equatable {
|
|||||||
this.topRightIsExpanded = false,
|
this.topRightIsExpanded = false,
|
||||||
this.obstacleRecognitionFlag = true,
|
this.obstacleRecognitionFlag = true,
|
||||||
this.targetDevice,
|
this.targetDevice,
|
||||||
|
this.updateType,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 便利 UI 更新部分属性
|
// 便利 UI 更新部分属性
|
||||||
@@ -78,7 +82,7 @@ class RemoteControlState extends Equatable {
|
|||||||
bool? topRightIsExpanded,
|
bool? topRightIsExpanded,
|
||||||
bool? obstacleRecognitionFlag,
|
bool? obstacleRecognitionFlag,
|
||||||
DeviceEntity? targetDevice,
|
DeviceEntity? targetDevice,
|
||||||
|
String? updateType,
|
||||||
}) {
|
}) {
|
||||||
return RemoteControlState(
|
return RemoteControlState(
|
||||||
status: status ?? this.status,
|
status: status ?? this.status,
|
||||||
@@ -101,9 +105,10 @@ class RemoteControlState extends Equatable {
|
|||||||
runningStatusModel: runningStatusModel ?? this.runningStatusModel,
|
runningStatusModel: runningStatusModel ?? this.runningStatusModel,
|
||||||
obstacleFlag: obstacleFlag ?? this.obstacleFlag,
|
obstacleFlag: obstacleFlag ?? this.obstacleFlag,
|
||||||
topRightIsExpanded: topRightIsExpanded ?? this.topRightIsExpanded,
|
topRightIsExpanded: topRightIsExpanded ?? this.topRightIsExpanded,
|
||||||
obstacleRecognitionFlag: obstacleRecognitionFlag ?? this.obstacleRecognitionFlag,
|
obstacleRecognitionFlag:
|
||||||
|
obstacleRecognitionFlag ?? this.obstacleRecognitionFlag,
|
||||||
targetDevice: targetDevice ?? this.targetDevice,
|
targetDevice: targetDevice ?? this.targetDevice,
|
||||||
|
updateType: updateType, // 不使用 ??,因为我们想要 null 的时候就是 null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +135,6 @@ class RemoteControlState extends Equatable {
|
|||||||
topRightIsExpanded,
|
topRightIsExpanded,
|
||||||
obstacleRecognitionFlag,
|
obstacleRecognitionFlag,
|
||||||
targetDevice,
|
targetDevice,
|
||||||
|
updateType,
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
DevicesCubit? _devicesCubit;
|
DevicesCubit? _devicesCubit;
|
||||||
StreamSubscription? _permissionSubscription; // 🔥 权限监听订阅
|
StreamSubscription? _permissionSubscription; // 🔥 权限监听订阅
|
||||||
bool _isShowingPermissionDialog = false; // 🔥 防止弹窗重复显示
|
bool _isShowingPermissionDialog = false; // 🔥 防止弹窗重复显示
|
||||||
|
bool? _lastPermissionDialogState; // 🔥 记录上次弹窗状态,检测状态变化
|
||||||
bool _isLoadingPermission = true; // 🔥 标记是否正在加载权限状态
|
bool _isLoadingPermission = true; // 🔥 标记是否正在加载权限状态
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -44,10 +45,28 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
// 🔥 监听权限弹窗状态变化 (只订阅一次)
|
// 🔥 监听权限弹窗状态变化 (只订阅一次)
|
||||||
if (_permissionSubscription == null) {
|
if (_permissionSubscription == null) {
|
||||||
_permissionSubscription = _cubit.stream.listen((state) {
|
_permissionSubscription = _cubit.stream.listen((state) {
|
||||||
// 🔥 加强防重复逻辑:只在状态真正变化且不在显示弹窗时才显示
|
// 🔥 关键修复:只有当状态更新类型是弹窗更新时才处理弹窗逻辑
|
||||||
if (mounted &&
|
// 设备状态更新(500ms)不会触发弹窗显示
|
||||||
|
if (state.updateType != 'permission_dialog') {
|
||||||
|
// 如果是设备状态更新,只重置状态记录,不显示弹窗
|
||||||
|
if (!state.showPermissionRequestDialog) {
|
||||||
|
_lastPermissionDialogState = false;
|
||||||
|
}
|
||||||
|
return; // 跳过设备状态更新
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔥 只有当状态从 false 变为 true 时才显示弹窗
|
||||||
|
// 使用三个条件确保不会重复显示
|
||||||
|
final wasFalseBefore =
|
||||||
|
_lastPermissionDialogState == null ||
|
||||||
|
_lastPermissionDialogState == false;
|
||||||
|
final shouldShow =
|
||||||
state.showPermissionRequestDialog &&
|
state.showPermissionRequestDialog &&
|
||||||
!_isShowingPermissionDialog) {
|
!_isShowingPermissionDialog &&
|
||||||
|
wasFalseBefore;
|
||||||
|
|
||||||
|
if (mounted && shouldShow) {
|
||||||
|
_lastPermissionDialogState = true; // 记录当前状态
|
||||||
_isShowingPermissionDialog = true;
|
_isShowingPermissionDialog = true;
|
||||||
debugPrint('🔔 [权限弹窗] 检测到 showPermissionRequestDialog=true,准备显示弹窗');
|
debugPrint('🔔 [权限弹窗] 检测到 showPermissionRequestDialog=true,准备显示弹窗');
|
||||||
// 使用微任务确保标志位已设置
|
// 使用微任务确保标志位已设置
|
||||||
@@ -55,10 +74,17 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
_showPermissionDialog(state).then((_) {
|
_showPermissionDialog(state).then((_) {
|
||||||
debugPrint('🔔 [权限弹窗] 弹窗已关闭,重置标志位');
|
debugPrint('🔔 [权限弹窗] 弹窗已关闭,重置标志位');
|
||||||
_isShowingPermissionDialog = false; // 弹窗关闭后重置标志
|
_isShowingPermissionDialog = false; // 弹窗关闭后重置标志
|
||||||
|
_lastPermissionDialogState = false; // 重置状态记录
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
} else if (!state.showPermissionRequestDialog) {
|
||||||
|
// 状态变为 false 时,重置记录
|
||||||
|
_lastPermissionDialogState = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// 🔥 如果已经订阅,重置状态记录,确保下次能正确检测状态变化
|
||||||
|
_lastPermissionDialogState = _cubit.state.showPermissionRequestDialog;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +370,7 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// debugPrint('👆 [权限弹窗] 用户点击了拒绝按钮');
|
// debugPrint('👆 [权限弹窗] 用户点击了拒绝按钮');
|
||||||
final deviceId =
|
final deviceId =
|
||||||
context
|
context
|
||||||
.read<DevicesCubit>()
|
.read<DevicesCubit>()
|
||||||
@@ -355,19 +381,19 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
final remoteCubit = context.read<RemoteControlCubit>();
|
final remoteCubit = context.read<RemoteControlCubit>();
|
||||||
|
|
||||||
// 🔥 添加详细状态日志 - 检查为什么TCP指令发不出去
|
// 🔥 添加详细状态日志 - 检查为什么TCP指令发不出去
|
||||||
// debugPrint('👆 [权限弹窗] ====================状态检查====================');
|
// debugPrint('👆 [权限弹窗] ====================状态检查====================');
|
||||||
// debugPrint('👆 [权限弹窗] showPermissionRequestDialog: ${remoteCubit.state.showPermissionRequestDialog}');
|
// debugPrint('👆 [权限弹窗] showPermissionRequestDialog: ${remoteCubit.state.showPermissionRequestDialog}');
|
||||||
// debugPrint('👆 [权限弹窗] targetDevice: ${remoteCubit.state.targetDevice}');
|
// debugPrint('👆 [权限弹窗] targetDevice: ${remoteCubit.state.targetDevice}');
|
||||||
// debugPrint('👆 [权限弹窗] requestingDeviceId: ${remoteCubit.state.requestingDeviceId}');
|
// debugPrint('👆 [权限弹窗] requestingDeviceId: ${remoteCubit.state.requestingDeviceId}');
|
||||||
// debugPrint('👆 [权限弹窗] hasPermission: ${remoteCubit.state.hasPermission}');
|
// debugPrint('👆 [权限弹窗] hasPermission: ${remoteCubit.state.hasPermission}');
|
||||||
// debugPrint('👆 [权限弹窗] ==============================================');
|
// debugPrint('👆 [权限弹窗] ==============================================');
|
||||||
|
|
||||||
/* debugPrint(
|
/* debugPrint(
|
||||||
'📋 [权限弹窗] targetDevice=${remoteCubit.state.targetDevice}',
|
'📋 [权限弹窗] targetDevice=${remoteCubit.state.targetDevice}',
|
||||||
);*/
|
);*/
|
||||||
|
|
||||||
// 🔥 先发送 TCP 响应,等完成后再关闭弹窗
|
// 🔥 先发送 TCP 响应,等完成后再关闭弹窗
|
||||||
// debugPrint('🔑 [权限弹窗] 用户拒绝,调用 confirmPermissionResponse');
|
// debugPrint('🔑 [权限弹窗] 用户拒绝,调用 confirmPermissionResponse');
|
||||||
final targetDevice = remoteCubit.state.targetDevice;
|
final targetDevice = remoteCubit.state.targetDevice;
|
||||||
if (targetDevice != null) {
|
if (targetDevice != null) {
|
||||||
debugPrint(
|
debugPrint(
|
||||||
@@ -385,8 +411,18 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 关闭弹窗(在 TCP 发送完成后)
|
// 🔥 关键修复:先重置弹窗标志位,再关闭弹窗
|
||||||
|
// 避免 Navigator.pop() 后上下文失效导致后续代码不执行
|
||||||
|
context.read<RemoteControlCubit>().resetPermissionCoolDown();
|
||||||
|
context.read<RemoteControlCubit>().emit(
|
||||||
|
context.read<RemoteControlCubit>().state.copyWith(
|
||||||
|
showPermissionRequestDialog: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 🔥 关闭弹窗(在状态重置之后)
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
|
debugPrint('🔔 [权限弹窗] 弹窗已关闭,重置标志位');
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(
|
AppLocalizations.of(
|
||||||
@@ -407,7 +443,7 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
final remoteCubit = context.read<RemoteControlCubit>();
|
final remoteCubit = context.read<RemoteControlCubit>();
|
||||||
|
|
||||||
// 🔥 添加详细状态日志 - 检查为什么TCP指令发不出去
|
// 🔥 添加详细状态日志 - 检查为什么TCP指令发不出去
|
||||||
/* debugPrint(
|
/* debugPrint(
|
||||||
'👆 [权限弹窗] ====================状态检查====================',
|
'👆 [权限弹窗] ====================状态检查====================',
|
||||||
);
|
);
|
||||||
debugPrint(
|
debugPrint(
|
||||||
@@ -434,9 +470,7 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
debugPrint('🔑 [权限弹窗] 用户同意,调用 confirmPermissionResponse');
|
debugPrint('🔑 [权限弹窗] 用户同意,调用 confirmPermissionResponse');
|
||||||
final targetDevice = remoteCubit.state.targetDevice;
|
final targetDevice = remoteCubit.state.targetDevice;
|
||||||
if (targetDevice != null) {
|
if (targetDevice != null) {
|
||||||
debugPrint(
|
debugPrint('✅ [权限弹窗] targetDevice 不为空');
|
||||||
'✅ [权限弹窗] targetDevice 不为空',
|
|
||||||
);
|
|
||||||
await remoteCubit.confirmPermissionResponse(
|
await remoteCubit.confirmPermissionResponse(
|
||||||
targetDevice.deviceName,
|
targetDevice.deviceName,
|
||||||
'app',
|
'app',
|
||||||
@@ -449,8 +483,18 @@ class _RemoteControlPageState extends State<RemoteControlPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 关闭弹窗(在 TCP 发送完成后)
|
// 🔥 关键修复:先重置弹窗标志位,再关闭弹窗
|
||||||
|
// 避免 Navigator.pop() 后上下文失效导致后续代码不执行
|
||||||
|
context.read<RemoteControlCubit>().resetPermissionCoolDown();
|
||||||
|
context.read<RemoteControlCubit>().emit(
|
||||||
|
context.read<RemoteControlCubit>().state.copyWith(
|
||||||
|
showPermissionRequestDialog: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 🔥 关闭弹窗(在状态重置之后)
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
|
debugPrint('🔔 [权限弹窗] 弹窗已关闭,重置标志位');
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(
|
AppLocalizations.of(
|
||||||
|
|||||||
Reference in New Issue
Block a user