Files
flutterApp/lib/features/remote_control/presentation/bloc/remote_control_cubit.dart
2026-01-29 19:16:41 +08:00

198 lines
6.3 KiB
Dart

import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:maibu_satabot_v2/core/logging/i_logger_service.dart';
import 'package:maibu_satabot_v2/core/protocol/packet_entity.dart';
import 'package:maibu_satabot_v2/features/remote_control/domain/entities/running_status_entity.dart';
import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remote_control_state.dart';
import '../../../../core/di/injection.dart';
import '../../../connectivity/presentation/bloc/connectivity_cubit.dart';
import '../../domain/entities/machine_control_entity.dart';
import '../../domain/repositories/remote_control_repository.dart';
class RemoteControlCubit extends Cubit<RemoteControlState> {
final RemoteControlRepository _repository;
final ConnectivityCubit connectivityCubit;
// 定时器与流订阅管理
Timer? _timer;
StreamSubscription<RunningStatusEntity>? _statusSubscription;
StreamSubscription<PacketEntity>? _responseSubscription;
RemoteControlCubit(this._repository,this.connectivityCubit)
: super(
RemoteControlState(
controlEntity: MachineControlEntity(),
runningStatusEntity: RunningStatusEntity(),
),
) {
// 构造时立即开启监听
_initPacketListener();
_initRunningStatusListener();
}
// ==========================================
// 1. 数据监听逻辑 (Data Listening)
// ==========================================
/// 监听原始回包 (处理如 0x12 权限申请等指令)
void _initPacketListener() {
_responseSubscription?.cancel();
_responseSubscription = _repository.responseStream.listen((packet) {
// 处理权限申请回包 (假设 0x12)
if (packet.cmdType == 0x12) {
// 假设 payload[0] == 1 表示获得权限,这里可以解析出平台信息
final bool granted = packet.payload.isNotEmpty && packet.payload[0] == 0x01;
emit(state.copyWith(
hasPermission: granted,
// 假设协议中后续字节带有平台名称
permissionPlatform: granted ? "Other Device" : "",
));
}
});
}
/// 监听运行状态回包 (0x02) 并更新 UI
void _initRunningStatusListener() {
_statusSubscription?.cancel();
_statusSubscription = _repository.runningStatusStream.listen((entity) {
// 同步硬件状态到 Bloc State
emit(state.copyWith(
runningStatusEntity: entity,
obstacleFlag: entity.obstacleFlag == 1 ? "检测到障碍物" : "无",
// 如果硬件上报了急停或锁定,这里也可以同步更新状态
isEmergency: entity.obstacleFlag == 1,
));
}, onError: (e) {
emit(state.copyWith(errorMessage: "运行状态流监听异常: $e"));
});
}
// ==========================================
// 2. 控制循环逻辑 (Control Loop)
// ==========================================
/// 启动 100ms 高频控制循环
void startControlLoop() {
_timer?.cancel();
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) async {
// 核心:在具备驾驶条件(有权限、未锁定、非急停)时发送指令
if (state.canDrive) {
try {
await _repository.sendControlMachineCmd(state.controlEntity);
} catch (e) {
print("发送控制指令失败: $e");
}
}
});
emit(state.copyWith(status: RemoteControlStatus.controlling));
}
/// 停止控制循环
void stopControlLoop() {
_timer?.cancel();
_timer = null;
emit(state.copyWith(status: RemoteControlStatus.initial));
}
// ==========================================
// 3. UI 交互方法 (UI Actions)
// ==========================================
/// 更新摇杆坐标 (x, y 为 -100 到 100)
void updateJoystick(double x, double y) {
final updatedEntity = state.controlEntity.copyWith(
x: x.toInt(),
y: y.toInt(),
);
emit(state.copyWith(controlEntity: updatedEntity));
}
/// 更新原点 Y 轴 (针对特定的 UI 逻辑)
void updateOriginY(int y) {
final updatedEntity = state.controlEntity.copyWith(y: y);
emit(state.copyWith(controlEntity: updatedEntity));
}
/// 更新底盘升降
void updateChassisLift(int level) {
final updatedEntity = state.controlEntity.copyWith(lift: level);
emit(state.copyWith(controlEntity: updatedEntity));
}
/// 更新急停状态
void updateEmergency(bool emergency) {
final updatedEntity = state.controlEntity.copyWith(emergency: emergency);
emit(state.copyWith(
controlEntity: updatedEntity,
isEmergency: emergency,
));
}
/// 更新割刀/功能开关
void updateMower(int speed) {
final updatedEntity = state.controlEntity.copyWith(mower: speed);
emit(state.copyWith(controlEntity: updatedEntity));
}
/// 切换控制锁定
void toggleLock() {
emit(state.copyWith(isLocked: !state.isLocked));
}
/// 权限请求弹窗控制
void togglePermissionDialog(bool show) {
emit(state.copyWith(showPermissionRequestDialog: show));
}
/// 发起/响应权限请求
void respondPermission(bool accept) {
// 这里可以添加发送 0x12 响应包给硬件的逻辑
emit(state.copyWith(
hasPermission: accept,
showPermissionRequestDialog: false,
));
}
/// 切换画中画显示
void toggleLeftPip() => emit(state.copyWith(showLeftPip: !state.showLeftPip));
void toggleRightPip() => emit(state.copyWith(showRightPip: !state.showRightPip));
void toggleTopLeftExpand() {
emit(state.copyWith(topRightIsExpanded: !state.topRightIsExpanded));
}
void toggleObstacleRecognition() {
emit(state.copyWith(obstacleRecognitionFlag: !state.obstacleRecognitionFlag));
}
void initVideoUrls(String main, String ai) {
emit(state.copyWith(
mainStreamUrl: main,
aiStreamUrl: ai,
isVideoEnabled: true,
));
}
void disposeVideo() {
emit(state.copyWith(
mainStreamUrl: "",
aiStreamUrl: "",
isVideoEnabled: false,
obstacleRecognitionFlag: false,
));
sl<ILoggerService>().log("Cubit: 视频地址已置空,准备断开连接");
}
// ==========================================
// 4. 销毁与清理 (Cleanup)
// ==========================================
@override
Future<void> close() {
_timer?.cancel();
_statusSubscription?.cancel();
_responseSubscription?.cancel();
return super.close();
}
}