From 3c3b2ce4eebe04362bde6d69974ee09f589abc8a Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Wed, 25 Mar 2026 15:09:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BF=9C=E7=A8=8B=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=E7=9A=84=E9=A1=B6=E9=83=A8=E7=9A=84=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=20=E5=AE=8C=E6=88=90=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E8=BF=9C=E7=A8=8B=E9=81=A5=E6=8E=A7=E7=9A=84=E7=94=B5?= =?UTF-8?q?=E5=8E=8B=E5=92=8C=E7=94=B5=E9=87=8F=E5=92=8C=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E4=BB=8Etcp=E8=8E=B7=E5=8F=96=E5=92=8C?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bloc/remote_control_cubit.dart | 118 +++++++++++++----- .../bloc/remote_control_state.dart | 4 +- .../pages/remote_control_page.dart | 8 -- .../presentation/widgets/status_chip.dart | 2 +- .../presentation/widgets/top_status_bar.dart | 5 +- 5 files changed, 93 insertions(+), 44 deletions(-) diff --git a/lib/features/remote_control/presentation/bloc/remote_control_cubit.dart b/lib/features/remote_control/presentation/bloc/remote_control_cubit.dart index b5cca598..c0bd1081 100644 --- a/lib/features/remote_control/presentation/bloc/remote_control_cubit.dart +++ b/lib/features/remote_control/presentation/bloc/remote_control_cubit.dart @@ -3,11 +3,13 @@ import 'dart:convert'; import 'dart:ffi'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:maibu_satabot_v2/features/remote_control/data/models/running_status_model.dart'; import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remote_control_state.dart'; import '../../../../core/network/net_message_dispatcher.dart'; +import '../../../devices/domain/entities/running_status_entity.dart'; import '../../domain/entities/machine_control_status_entity.dart'; import '../../domain/repositories/remote_control_repository.dart'; import '../../domain/usecase/remote_control_usecase.dart'; @@ -18,7 +20,10 @@ class RemoteControlCubit extends Cubit { Timer? _timer; StreamSubscription? _kickOutSub; // 新增:用于管理监听生命周期 final NetMessageDispatcher dispatcher; - StreamSubscription? _deviceStatusSub;//🔥 新增:用于监听 DeviceStat + StreamSubscription? _stringMessageSub; // + static const platform = MethodChannel('com.maibu.satabot/ping'); + int _currentPing = 50; + RemoteControlCubit(this._repository, this._requestControlPermissionUseCase, this.dispatcher) : super( @@ -28,62 +33,85 @@ class RemoteControlCubit extends Cubit { ), ) { _initPacketListener(); - + _initStringMessageListener(); // 🔥 新增 } - // 🔥 新增:监听 DeviceStatusBloc 的状态更新 - void subscribeToDeviceStatus(Stream deviceStatusStream) { - _deviceStatusSub?.cancel(); + void _initStringMessageListener() { + print('>>> [RemoteControl] begin 初始化 0x02 字符串监听器'); + _stringMessageSub?.cancel(); + + _stringMessageSub = dispatcher.onStringMessage().listen((message) async { + print('>>> [RemoteControl] 收到 0x02 字符串推送:$message'); + + if (message.isEmpty) { + print('⚠️ [RemoteControl] 消息为空,跳过解析'); + return; + } - _deviceStatusSub = deviceStatusStream.listen((deviceState) { try { - // 🔥 关键:从 DeviceStatusBloc 的 state 中提取数据 - // 这里假设 deviceState 是 DevicesCubit 的 state - // 你需要根据实际的 DevicesCubit state 类型来调整 + // 🔥 关键:使用与 DeviceStatusBloc 相同的解析方法 + print('>>> [RemoteControl] 🔍 开始解析数据(使用 fromFields)...'); - debugPrint('📡 [收到设备状态更新] deviceState: $deviceState'); + final fields = message.trim().split(','); + print('>>> [RemoteControl] 字段数量:${fields.length}'); - // 如果 DevicesCubit 的 state 中有 runningStatusModel 或类似字段 - // 方式 1:直接同步整个 RunningStatusModel - if (deviceState is Map && deviceState.containsKey('runningStatusModel')) { - final newStatus = deviceState['runningStatusModel'] as RunningStatusModel; - _updateStatusFromDevice(newStatus); + if (fields.length < 18) { + print('⚠️ [RemoteControl] 字段不足:${fields.length},期望 ≥18'); + return; } - // 方式 2:如果 DevicesCubit 直接暴露 voltage, battery 等字段 - else if (deviceState is Map) { - final voltage = deviceState['voltage'] as int? ?? 0; - final battery = deviceState['battery'] as int? ?? 0; - emit(state.copyWith( - voltage: voltage, - battery: battery, - )); + // 🔥 使用 RunningStatusEntity.fromFields() 解析 + final status = RunningStatusEntity.fromFields(fields); + // 🔥 只提取电压、电量、控制模式 + final voltage = status.voltage; + final battery = status.battery; + final controlMode = status.controlMode == '3' ? '远程模式' : '本地模式'; - debugPrint('📡 [同步设备状态] 电压:${voltage}V, 电量:${battery}%'); - } - } catch (e) { - debugPrint('❌ [同步设备状态失败] $e'); + + // final c = getPing('1.95.137.212'); // ⚠️ 替换为你的服务器 IP + emit(state.copyWith( + runningStatusModel: state.runningStatusModel.copyWith( + voltage: voltage.toString(), // 更新电压 + battery: battery.toString(), // 更新电量 + controlMode: controlMode, // 更新控制模式 + ), + battery: int.tryParse(battery) ?? 0, + //ping: c, // 这里直接使用异步返回的数值 + )); + + + } catch (e, stackTrace) { + print('>>> [RemoteControl] ❌ 解析失败:$e'); + // print('>>> [RemoteControl] ❌ 堆栈跟踪:$stackTrace'); + // print('>>> [RemoteControl] ❌ 原始消息:$message'); } }); - debugPrint('✅ [DeviceStatus] 已建立监听'); + print('>>> [RemoteControl] ✅ 0x02 字符串监听器已建立完成'); } + // 🔥 超简单方法:传入 IP,得到 ping 值 + + + + // 🔥 辅助方法:更新运行状态 void _updateStatusFromDevice(RunningStatusModel newStatus) { + + debugPrint('✅ [_updateStatusFromDevice] 收到运行状态更新:$newStatus'); if (!isClosed) { emit(state.copyWith( runningStatusModel: newStatus, - voltage:int.tryParse(newStatus.voltage) ?? 0, + voltage: int.tryParse(newStatus.voltage) ?? 0, battery: int.tryParse(newStatus.battery) ?? 0, - // 如果需要同步其他字段,在这里添加 - // controlMode: newStatus.controlMode, )); debugPrint('✅ [更新运行状态] 电压:${newStatus.voltage}V, 电量:${newStatus.battery}%'); } } + + // 🔥 辅助方法:更新运行状态 // 1. 初始化回包监听 (如 0x12 权限) // void _initPacketListener() { // _repository.responseStream.listen((packet) { @@ -243,7 +271,8 @@ class RemoteControlCubit extends Cubit { @override Future close() { _timer?.cancel(); // 退出页面时务必销毁定时器 - _deviceStatusSub?.cancel(); // 🔥 确保清理订阅 + _kickOutSub?.cancel(); + _stringMessageSub?.cancel(); return super.close(); } @@ -333,6 +362,31 @@ class RemoteControlCubit extends Cubit { emit(state.copyWith(topRightIsExpanded: !state.topRightIsExpanded)); } + int getPing(String host) { + print('>>> [RemoteControl] 📡 开始 ping $host...'); + + // 后台异步获取,不阻塞 + platform.invokeMethod('ping', { + 'host': host, + 'count': 1, + 'timeout': 2, + }).then((result) { + final success = result['success'] as bool? ?? false; + final delay = (result['delayMs'] as num?)?.toInt() ?? 100; + _currentPing = success ? delay.clamp(0, 100) : 100; + print('📶 [Ping 结果] $host - $_currentPing ms'); + + // 获取到新值后,再次 emit 更新 state + if (!isClosed) { + emit(state.copyWith(ping: _currentPing)); + } + }).catchError((e) { + print('⚠️ [Ping 错误] $e'); + _currentPing = 100; + }); + + return _currentPing; // 立即返回当前值 + } diff --git a/lib/features/remote_control/presentation/bloc/remote_control_state.dart b/lib/features/remote_control/presentation/bloc/remote_control_state.dart index 2942376d..f94c2708 100644 --- a/lib/features/remote_control/presentation/bloc/remote_control_state.dart +++ b/lib/features/remote_control/presentation/bloc/remote_control_state.dart @@ -17,8 +17,8 @@ class RemoteControlState extends Equatable { final bool isEmergency; final bool isLocked; final int ping; - final int battery; - final int voltage; + final int battery;//电池量 + final int voltage;//电压 final String permissionPlatform; final String currentPlatform; final bool showPermissionRequestDialog; diff --git a/lib/features/remote_control/presentation/pages/remote_control_page.dart b/lib/features/remote_control/presentation/pages/remote_control_page.dart index 45a9a575..4aa7f436 100644 --- a/lib/features/remote_control/presentation/pages/remote_control_page.dart +++ b/lib/features/remote_control/presentation/pages/remote_control_page.dart @@ -27,7 +27,6 @@ class RemoteControlPage extends StatefulWidget { class _RemoteControlPageState extends State { String _videoStreamUrl = ""; - StreamSubscription? _deviceStatusSubscription; @override void initState() { super.initState(); @@ -36,17 +35,12 @@ class _RemoteControlPageState extends State { // 2. 隐藏状态栏和虚拟按键 SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); - // 🔥 关键:订阅 DeviceStatusBloc 的状态流 WidgetsBinding.instance.addPostFrameCallback((_) { final remoteCubit = context.read(); final devicesCubit = context.read(); remoteCubit.startControlLoop(); - // 🔥 关键:订阅 DeviceStatusBloc 的状态流 - remoteCubit.subscribeToDeviceStatus(devicesCubit.stream); - - debugPrint('🚀 [遥控页面] 已启动控制循环和设备状态监听'); }); } @@ -54,7 +48,6 @@ class _RemoteControlPageState extends State { void dispose() { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - _deviceStatusSubscription?.cancel(); context.read().stopControlLoop(); super.dispose(); } @@ -167,7 +160,6 @@ class _RemoteControlPageState extends State { ], ), ), - // 权限弹窗 BlocBuilder( buildWhen: (p, c) => p.showPermissionRequestDialog != c.showPermissionRequestDialog, diff --git a/lib/features/remote_control/presentation/widgets/status_chip.dart b/lib/features/remote_control/presentation/widgets/status_chip.dart index dff9a171..51e020d3 100644 --- a/lib/features/remote_control/presentation/widgets/status_chip.dart +++ b/lib/features/remote_control/presentation/widgets/status_chip.dart @@ -110,7 +110,7 @@ class _StatusChipState extends State widget.text, style: const TextStyle( color: Colors.white, - fontSize: 13, + fontSize: 10, fontWeight: FontWeight.w600, ), ), diff --git a/lib/features/remote_control/presentation/widgets/top_status_bar.dart b/lib/features/remote_control/presentation/widgets/top_status_bar.dart index 9e786e95..4b9dc56b 100644 --- a/lib/features/remote_control/presentation/widgets/top_status_bar.dart +++ b/lib/features/remote_control/presentation/widgets/top_status_bar.dart @@ -6,7 +6,10 @@ import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remot import 'package:maibu_satabot_v2/features/remote_control/presentation/widgets/status_chip.dart'; import 'package:cc_ui_kit/cc_ui_kit.dart'; +import '../../../../core/di/injection.dart'; +import '../../../../core/logging/i_logger_service.dart'; import '../../../devices/presentation/bloc/devices_cubit.dart'; +import '../../data/models/running_status_model.dart'; import '../bloc/remote_control_cubit.dart'; class TopStatusBar extends StatelessWidget { @@ -357,7 +360,7 @@ class TopStatusBar extends StatelessWidget { Widget _buildSliderBox(String label, bool isLeft, BuildContext context) { // 1. 核心尺寸调整:足够宽的容器解决拥挤,高度匹配状态栏 - const double boxWidth = 76; // 水平宽度放大,容纳左右图标 + const double boxWidth = 66; // 水平宽度放大,容纳左右图标 const double boxHeight = 32; // 高度和其他按钮保持一致 const double iconSize = 20; // 图标尺寸放大,避免过小拥挤