Files
flutterApp/lib/features/remote_control/presentation/widgets/center_control_area.dart

187 lines
6.5 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:cc_ui_kit/cc_ui_kit.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:maibu_satabot_v2/components/capsule_toast.dart';
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
import '../bloc/remote_control_cubit.dart';
import 'emergency_stop_button.dart';
class CenterControlArea extends StatelessWidget {
final double totalWidth;
const CenterControlArea({super.key, required this.totalWidth});
@override
Widget build(BuildContext context) {
final remoteState = context.watch<RemoteControlCubit>().state;
if (remoteState.isEmergency) {
return const Column(
mainAxisSize: MainAxisSize.min,
children: [EmergencyStopButton(), SizedBox(height: 16)],
);
}
return LayoutBuilder(
builder: (context, constraints) {
final double expandedWidth = totalWidth * 0.25;
final double emergencyStopButtonWidth = constraints.maxWidth * 0.5;
return Container(
// 这里不再使用 Row 包装三个 Expanded,而是直接固定宽度
child: Row(
//mainAxisSize: MainAxisSize.min, // 极其重要:防止在 spaceBetween 下挤压
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
// 左摇杆 (3份)
// _buildSliderBox(expandedWidth, "底盘", true),
SizedBox(
width: expandedWidth,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
_buildSliderBox(expandedWidth, 'chassis', true,context),
SizedBox(height: totalWidth * 0.01),
],
),
),
// 急停 (2份)
SizedBox(
width: emergencyStopButtonWidth,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
EmergencyStopButton(width: emergencyStopButtonWidth),
SizedBox(height: totalWidth * 0.05),
Text(
AppLocalizations.of(context).translate('remote_control.switch_view_hint'),
style: const TextStyle(fontSize: 8, color: Colors.grey),
),
],
),
),
// 右摇杆 (3份)
// _buildSliderBox(expandedWidth, "备用", false),
SizedBox(
width: expandedWidth,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [_buildSliderBox(expandedWidth, 'mower', false,context)],
),
),
],
),
);
},
);
}
Widget _buildSliderBox(double boxWidth, String deviceKey, bool isLeft,BuildContext context) {
// 🔥 使用deviceKey作为唯一标识,不依赖显示文本
final label = deviceKey == 'chassis'
? AppLocalizations.of(context).translate('remote_control.chassis')
: AppLocalizations.of(context).translate('remote_control.mower');
return SizedBox(
width: boxWidth,
child: Center(
child: SizedBox(
width: boxWidth * 0.6,
height: boxWidth * 0.6 * 3,
child: CCExpandSlider(
label: label,
svgStart: "assets/svgs/remote_up.svg",
svgCenter: deviceKey == 'mower'
? "assets/svgs/remote_scissors.svg"
: "assets/svgs/remote_layers.svg",
svgEnd: "assets/svgs/remote_down.svg",
onStart: () => _handleSliderAction(deviceKey, "start", context),
onCenter: () => _handleSliderAction(deviceKey, "center", context),
onEnd: () => _handleSliderAction(deviceKey, "end", context),
iconSize: boxWidth * 0.6 * 0.35,
),
),
),
);
}
// 🔥 新增:统一的业务逻辑分发方法
void _handleSliderAction(String deviceKey, String action, BuildContext context) {
debugPrint('🎯 [Slider 业务] deviceKey: $deviceKey, action: $action');
// 🔥 门槛检查:与摇杆一致,未收到 TCP 0x02 推送时禁止操作并提示。
// 胶囊 Toast 全局去重、自动消失,适配 StatelessWidget 无实例状态。
if (!context.read<RemoteControlCubit>().isStatusPushActive()) {
CapsuleToast.show('暂未收到该机器的推送,不能控制', showCheck: false);
return;
}
// 🔥 使用deviceKey进行判断,不依赖显示文本
switch (deviceKey) {
case 'chassis':
_handleChassisAction(action, context);
break;
case 'mower':
_handleMowerAction(action, context);
break;
default:
debugPrint('⚠️ 未知的 deviceKey: $deviceKey');
}
// 🔥 在指令执行后触发震动反馈(增强手感)
HapticFeedback.mediumImpact();
}
// 🔥 底盘的业务逻辑(左滑块)
void _handleChassisAction(String action, BuildContext context) {
final cubit = context.read<RemoteControlCubit>();
switch (action) {
case "start":
debugPrint('⬆️ 底盘 - 向上(例如:前进)');
// TODO: 发送底盘前进指令
cubit.sendChassisCommand(1);
break;
case "center":
debugPrint('️ 底盘 - 中间(例如:停止)');
// TODO: 发送底盘停止指令
cubit.sendChassisCommand(0);
break;
case "end":
debugPrint('⬇️ 底盘 - 向下(例如:后退)');
// TODO: 发送底盘后退指令
cubit.sendChassisCommand(2);
break;
}
}
// 🔥 割刀的业务逻辑(右滑块)
void _handleMowerAction(String action, BuildContext context) {
final cubit = context.read<RemoteControlCubit>();
switch (action) {
case "start":
debugPrint('⬆️ 割刀 - 向上(例如:抬刀)');
// TODO: 发送抬刀指令
cubit.sendMowerCommand(1);
break;
case "center":
debugPrint('⏹️ 割刀 - 中间(例如:保持)');
// TODO: 发送保持指令
cubit.sendMowerCommand(0);
break;
case "end":
debugPrint('⬇️ 割刀 - 向下(例如:降刀)');
// TODO: 发送降刀指令
cubit.sendMowerCommand(2);
break;
}
}
}