Files
feature-next-arch/lib/features/remote_control/presentation/bloc/remote_control_cubit.dart

266 lines
8.7 KiB
Dart
Raw Normal View History

2026-01-18 20:21:14 +08:00
import 'dart:async';
2026-03-13 20:29:06 +08:00
import 'dart:convert';
import 'dart:ffi';
2026-01-18 20:21:14 +08:00
import 'package:flutter_bloc/flutter_bloc.dart';
2026-01-21 13:27:55 +08:00
import 'package:maibu_satabot_v2/features/remote_control/data/models/running_status_model.dart';
2026-01-18 20:21:14 +08:00
import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remote_control_state.dart';
2026-03-13 20:29:06 +08:00
import '../../../../core/network/net_message_dispatcher.dart';
2026-01-18 20:21:14 +08:00
import '../../domain/entities/machine_control_status_entity.dart';
import '../../domain/repositories/remote_control_repository.dart';
import '../../domain/usecase/remote_control_usecase.dart';
2026-01-18 20:21:14 +08:00
class RemoteControlCubit extends Cubit<RemoteControlState> {
final RemoteControlRepository _repository;
final RequestControlPermissionUseCase _requestControlPermissionUseCase;
2026-01-18 20:21:14 +08:00
Timer? _timer;
2026-03-13 20:29:06 +08:00
StreamSubscription? _kickOutSub; // 新增:用于管理监听生命周期
final NetMessageDispatcher dispatcher;
2026-01-18 20:21:14 +08:00
2026-03-13 20:29:06 +08:00
RemoteControlCubit(this._repository, this._requestControlPermissionUseCase, this.dispatcher)
2026-01-21 13:27:55 +08:00
: super(
RemoteControlState(
controlEntity: MachineControlStatusEntity(),
runningStatusModel: RunningStatusModel(),
),
) {
2026-01-18 20:21:14 +08:00
_initPacketListener();
2026-03-16 15:31:14 +08:00
2026-01-18 20:21:14 +08:00
}
// 1. 初始化回包监听 (如 0x12 权限)
2026-03-13 20:29:06 +08:00
// void _initPacketListener() {
// _repository.responseStream.listen((packet) {
// if (packet.command == 0x12) {
// // 根据负载判断是否有权限,更新状态
// emit(state.copyWith(hasPermission: true));
// }
// });
// }
2026-01-18 20:21:14 +08:00
void _initPacketListener() {
2026-03-13 20:29:06 +08:00
print('>>> [RemoteControl] begin 初始化 0x12 监听器');
_kickOutSub?.cancel(); // 防止重复监听
_kickOutSub = dispatcher.onCommand(0x12).listen((packet) {
print('>>> [RemoteControl] 收到 0x12 原始包,payload 长度=${packet.payload.length}');
try {
// 🔥 关键:手动去掉最后 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);
}
print('>>> [RemoteControl] 去除 CRC 后的 JSON: $jsonString');
final jsonMap = jsonDecode(jsonString);
2026-03-16 15:31:14 +08:00
// 🔥 区分两种数据格式
final requestType = jsonMap['request'];
final platform = jsonMap['platform'];
final respondData = jsonMap['respond'];
print('>>> [RemoteControl] 📋 requestType=$requestType, platform=$platform');
// 情况 1: 响应格式 - {"respond":{"switchResult":true,"deviceId":"...","holder":"you"}}
if (respondData != null && respondData is Map) {
final switchResult = respondData['switchResult'];
print('>>> [RemoteControl] 📊 收到切换结果响应:switchResult = $switchResult');
if (!isClosed) {
if (switchResult == true) {
// 切换成功,当前 APP 失去控制权
emit(state.copyWith(hasPermission: true, showPermissionRequestDialog: false));
print('>>> [RemoteControl] ✅ 权限已切');
} else {
// 切换失败或拒绝,保持当前状态
emit(state.copyWith(showPermissionRequestDialog: false));
print('>>> [RemoteControl] ❌ 权限切换失败/被拒绝');
}
}
}
// 情况 2: 请求格式 - {"request":"switch_control","deviceId":"...","platform":"web",...}
else if (requestType == 'switch_control') {
// 🔥 关键判断:只有当是其他平台(web)请求时才弹窗
if (platform != null && platform.toString().toLowerCase() != 'app') {
print('>>> [RemoteControl] 🚨 $platform 端请求控制权,打开弹窗询问用户');
if (!isClosed) {
emit(state.copyWith(showPermissionRequestDialog: true));
}
} else {
print('>>> [RemoteControl] ℹ️ APP 自己的请求回显,忽略不弹窗');
}
}
// 情况 3: 异地登录通知 - {"request":"have_logged_in",...}
else if (requestType == 'have_logged_in') {
print('>>> [RemoteControl] ⚠️ 检测到异地登录,打开弹窗提示');
if (!isClosed) {
emit(state.copyWith(showPermissionRequestDialog: true));
}
}
else {
print('>>> [RemoteControl] ℹ️ 未知类型的 0x12 包,忽略');
2026-03-13 20:29:06 +08:00
}
} catch (e) {
print('>>> [RemoteControl] ❌ 解析失败:$e');
2026-01-18 20:21:14 +08:00
}
});
2026-03-13 20:29:06 +08:00
print('>>> [RemoteControl] ✅ 0x12 监听器已建立完成');
2026-01-18 20:21:14 +08:00
}
2026-03-16 15:31:14 +08:00
2026-01-18 20:21:14 +08:00
// 2. 开启 100ms 控制循环 (在进入遥控页面或点击“开始”时调用)
void startControlLoop() {
_timer?.cancel();
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
// 核心调用:直接把 state 里的实体丢给 repository
_repository.sendControlMachineCmd(state.controlEntity);
});
emit(state.copyWith(status: RemoteControlStatus.controlling));
}
// 3. 更新摇杆数据
void updateJoystick(double x, double y) {
final updatedEntity = state.controlEntity.copyWith(
x: x.toInt(),
y: y.toInt(),
);
emit(state.copyWith(controlEntity: updatedEntity));
}
// 4. 更新功能开关 (比如割刀速度、灯光、点火等)
void updateFunction({int? mower, int? lift, int? ignition, bool? emergency}) {
final updatedEntity = state.controlEntity.copyWith(
mower: mower,
lift: lift,
ignition: ignition,
emergency: emergency,
);
emit(state.copyWith(controlEntity: updatedEntity));
}
void updateOriginY(int y) {
final updatedEntity = state.controlEntity.copyWith(
y: y,
);
emit(state.copyWith(controlEntity: updatedEntity));
}
void updateOriginX(int x) {
final updatedEntity = state.controlEntity.copyWith(
x: x,
);
emit(state.copyWith(controlEntity: updatedEntity));
}
2026-01-18 20:21:14 +08:00
// 5. 停止控制循环
void stopControlLoop() {
_timer?.cancel();
_timer = null;
emit(state.copyWith(status: RemoteControlStatus.initial));
}
void toggleLock() {}
void togglePermissionDialog(bool show) {
emit(state.copyWith(showPermissionRequestDialog: show));
}
void requestControlPermission() {
// 1. 关闭弹窗
emit(state.copyWith(showPermissionRequestDialog: false));
}
2026-01-21 13:27:55 +08:00
void toggleLeftPip() => emit(state.copyWith(showLeftPip: !state.showLeftPip));
void toggleRightPip() =>
emit(state.copyWith(showRightPip: !state.showRightPip));
2026-01-18 20:21:14 +08:00
@override
Future<void> close() {
_timer?.cancel(); // 退出页面时务必销毁定时器
return super.close();
}
void updateChassisLift(int i) {}
void updateEmergency(bool bool) {}
2026-03-16 15:31:14 +08:00
void respondPermission(bool bool, String deviceId) {
emit(state.copyWith(showPermissionRequestDialog: false));
// 2. 发送响应到服务端
_repository.respondPermission(bool, deviceId);
// 3. 根据用户选择更新控制状态
if (bool) {
// 用户同意 → APP 失去控制权,Web 端获得控制权
emit(state.copyWith(hasPermission: false));
//路由到首页home
} else {
// 用户拒绝 → APP 继续保持控制权
emit(state.copyWith(hasPermission: true));
}
}
void requestControlPermissionS(String deviceName, String deviceId) async {
// 1. 关闭弹窗
emit(state.copyWith(showPermissionRequestDialog: false));
// 2. 调用 UseCase
final result = await _requestControlPermissionUseCase(
RequestControlPermissionParams(
deviceName: deviceName,
deviceId: deviceId,
),
);
// 3. 处理结果
result.fold(
(failure) {
print('❌ [RemoteControl] 请求控制权限失败:${failure.message}');
// 可以在这里显示错误提示或重新打开弹窗
emit(state.copyWith(showPermissionRequestDialog: true));
},
(success) {
2026-03-13 20:29:06 +08:00
// 更新状态
print('✅ [RemoteControl] 请求控制权限成功:$success');
///处理result
if(success){
emit(state.copyWith(hasPermission: true));
}else{
emit(state.copyWith(hasPermission: false));
}
print('✅ c:$success');
// 权限申请已发送,等待 0x12 回包更新状态
},
);
}
/// 发送底盘指令
void sendChassisCommand(int i) {
updateFunction(lift: i);
}
/// 发送割刀指令
void sendMowerCommand(int i) {
updateFunction(mower: i);
}
/// 发送点火指令
void sendFireCommand(int i) {
//void updateFunction({int? mower, int? lift, int? ignition, bool? emergency})
// updateFunction(mower:0, lift: 0, ignition: i, emergency: false);
updateFunction(ignition: i);
}
2026-03-13 20:29:06 +08:00
2026-03-16 15:31:14 +08:00
2026-01-18 20:21:14 +08:00
}
2026-03-13 20:29:06 +08:00