187 lines
6.5 KiB
Dart
187 lines
6.5 KiB
Dart
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;
|
||
}
|
||
}
|
||
}
|