import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart'; import 'package:maibu_satabot_v2/core/localization/app_localizations.dart'; import 'package:maibu_satabot_v2/core/consts/tcp_consts.dart'; import 'package:maibu_satabot_v2/core/router/route_paths.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart'; import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_state.dart'; import 'package:maibu_satabot_v2/features/devices/presentation/bloc/device_status_bloc.dart'; import 'package:maibu_satabot_v2/features/devices/presentation/bloc/device_status_state.dart'; import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remote_control_cubit.dart'; // 🔥 添加 RemoteControlCubit import 'package:maibu_satabot_v2/features/remote_control/presentation/widgets/webrtc/webrtc_local_player.dart'; class MachineDetailsPage extends StatefulWidget { final DeviceEntity? device; const MachineDetailsPage({super.key, this.device}); @override State createState() => _MachineDetailsPageState(); } class _MachineDetailsPageState extends State { late TextEditingController _nameController; late String _deviceName; late String _deviceId; BuildContext? _dialogContext; BuildContext? _editNameSheetContext; BuildContext? _loadingDialogContext; // 解绑加载弹窗 BuildContext? _updateLoadingContext; // 修改名称加载弹窗 bool _isUpdatingName = false; // 🔥 保存 stream 引用,避免每次 rebuild 都重新获取 late Stream _deviceStatusStream; late DeviceStatusState _initialState; // 🔥 新增:视频相关状态 String _videoStreamUrl = ''; int _currentViewIndex = 0; // 0=前, 1=后, 2=左, 3=右, 4=上 // 视角配置 final List> _viewConfigs = [ {'name': '前视', 'alignment': Alignment.topLeft, 'icon': Icons.arrow_upward}, {'name': '后视', 'alignment': Alignment.topRight, 'icon': Icons.arrow_downward}, {'name': '左视', 'alignment': Alignment.bottomLeft, 'icon': Icons.arrow_back}, {'name': '右视', 'alignment': Alignment.bottomRight, 'icon': Icons.arrow_forward}, {'name': '全景', 'alignment': Alignment.center, 'icon': Icons.view_agenda}, ]; @override void initState() { super.initState(); _deviceName = (widget.device?.deviceAlias?.trim().isEmpty ?? true) ? '未知设备' : widget.device!.deviceAlias!; _deviceId = widget.device?.deviceName ?? ''; _nameController = TextEditingController(text: _deviceName); // 🔥 在 initState 中保存 stream 和 initial state final bloc = context.read(); _deviceStatusStream = bloc.stream; _initialState = bloc.state; debugPrint('📦 [MachineDetails] initState - 初始状态: ${_initialState.runtimeType}'); // 🔥 初始化视频 URL _initVideoUrl(); } /// 🔥 初始化视频流 URL void _initVideoUrl() { final userState = context.read().state; debugPrint('🎬 [MachineDetails] 开始初始化视频URL'); debugPrint('🎬 [MachineDetails] deviceId: $_deviceId'); debugPrint('🎬 [MachineDetails] user: ${userState.user}'); debugPrint('🎬 [MachineDetails] token: ${userState.user?.token}'); if (_deviceId.isNotEmpty && userState.user != null && userState.user!.token != null) { setState(() { _videoStreamUrl = "webrtc://${TCPConsts.TCP_IP}/live/livestream/$_deviceId?token=${userState.user!.token}"; }); debugPrint('✅ [MachineDetails] 视频URL初始化成功: $_videoStreamUrl'); } else { debugPrint('❌ [MachineDetails] 视频URL初始化失败'); debugPrint(' - deviceId.isEmpty: ${_deviceId.isEmpty}'); debugPrint(' - user == null: ${userState.user == null}'); debugPrint(' - token == null: ${userState.user?.token == null}'); } } @override void dispose() { _nameController.dispose(); // 兜底关闭所有弹窗 if (_loadingDialogContext != null && Navigator.canPop(_loadingDialogContext!)) { Navigator.pop(_loadingDialogContext!); } if (_updateLoadingContext != null && Navigator.canPop(_updateLoadingContext!)) { Navigator.pop(_updateLoadingContext!); } if (_dialogContext != null && Navigator.canPop(_dialogContext!)) { Navigator.pop(_dialogContext!); } if (_editNameSheetContext != null && Navigator.canPop(_editNameSheetContext!)) { Navigator.pop(_editNameSheetContext!); } super.dispose(); } /// 弹出修改设备名称底部抽屉(保持不变) void _showEditNameSheet() { _nameController.text = _deviceName; Future bottomSheetFuture = showModalBottomSheet( context: context, isScrollControlled: true, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), builder: (ctx) { _editNameSheetContext = ctx; return Padding( padding: EdgeInsets.only(left: 20, right: 20, top: 20, bottom: MediaQuery.of(ctx).viewInsets.bottom + 20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(AppLocalizations.of(context).translate('machine_details.edit_name_title'), style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w600)), const SizedBox(height: 16), TextField( controller: _nameController, autofocus: true, maxLength: 20, decoration: InputDecoration(hintText: AppLocalizations.of(ctx).translate('machine_details.edit_name_hint'), border: const OutlineInputBorder(), counterText: ""), ), const SizedBox(height: 10), Row( children: [ Expanded( child: OutlinedButton( onPressed: () { _isUpdatingName = false; Navigator.pop(ctx); }, child: Text(AppLocalizations.of(context).translate('common.cancel')), ), ), const SizedBox(width: 12), Expanded( child: OutlinedButton( onPressed: _isUpdatingName ? null : () async { final text = _nameController.text.trim(); if (text.isEmpty) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.name_empty_error')))); } return; } if (text == _deviceName) { Navigator.pop(ctx); return; } setState(() => _isUpdatingName = true); await _executeUpdateDeviceName(text); }, child: _isUpdatingName ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : Text(AppLocalizations.of(context).translate('common.confirm')), ), ), ], ), ], ), ); }, ); bottomSheetFuture.whenComplete(() { setState(() { _isUpdatingName = false; _editNameSheetContext = null; }); }); } @override Widget build(BuildContext context) { if (widget.device == null) { return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: AppBar( title: Text(AppLocalizations.of(context).translate('machine_details.title')), leading: IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: () { // 优化1:先刷新列表,再返回(保证刷新逻辑执行) // 核心:返回上一页 Navigator.pop(context); if (context.mounted) { final username = context.read().state.user?.username ?? ""; // 🔥 修复:检查是否已有 targetDevice final remoteControlState = context.read().state; if (remoteControlState.targetDevice == null) { debugPrint('🔄 [MachineDetails] 无 targetDevice,开始加载设备列表'); context.read().fetchAllDevices(username); } else { debugPrint('✅ [MachineDetails] 已有 targetDevice: ${remoteControlState.targetDevice!.deviceName},跳过加载'); } } }, ), ), body: Center(child: Text(AppLocalizations.of(context).translate('machine_details.device_info_error'))), ); } final currentDevice = widget.device!; return BlocListener( listener: (context, state) { if (state.operationType == DeviceOperationType.unbind) { _handleUnbindResult(state); } if (state.operationType == DeviceOperationType.updateName) { _handleUpdateNameResult(state); } }, child: Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: AppBar( centerTitle: true, title: Text(AppLocalizations.of(context).translate('machine_details.title'), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), leading: IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: () { Navigator.pop(context); if (context.mounted) { final username = context.read().state.user?.username ?? ""; // 🔥 修复:检查是否已有 targetDevice final remoteControlState = context.read().state; if (remoteControlState.targetDevice == null) { debugPrint('🔄 [MachineDetails AppBar] 无 targetDevice,开始加载设备列表'); context.read().fetchAllDevices(username); } else { debugPrint('✅ [MachineDetails AppBar] 已有 targetDevice: ${remoteControlState.targetDevice!.deviceName},跳过加载'); } } }, ), elevation: 1, backgroundColor: Colors.white, foregroundColor: Colors.black, ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: [ _buildDeviceStatusCard(currentDevice), const SizedBox(height: 16), // 🔥 新增:实时状态卡片 _buildRealTimeStatusCard(), const SizedBox(height: 16), _buildBasicInfoCard(context, currentDevice), const SizedBox(height: 16), _buildResourceCenterCard(), const SizedBox(height: 24), _buildUnbindButton(context), ], ), ), ), ); } /// 🔥 新增:实时状态卡片(显示控制模式、电压、电量) Widget _buildRealTimeStatusCard() { return StreamBuilder( stream: _deviceStatusStream, initialData: _initialState, builder: (context, snapshot) { final blocState = snapshot.data; debugPrint('🔍 [MachineDetails] StreamBuilder 收到状态: ${blocState?.runtimeType}'); String controlMode = AppLocalizations.of(context).translate('common.unknown'); String voltage = '--'; String battery = '--'; if (blocState is DeviceStatusUpdated) { debugPrint('✅ [MachineDetails] 有实时数据 - 电压:${blocState.status.voltage}, 电量:${blocState.status.battery}'); controlMode = blocState.status.controlMode == '3' ? AppLocalizations.of(context).translate('machine_details.remote_mode') : AppLocalizations.of(context).translate('machine_details.local_mode'); voltage = '${blocState.status.voltage}V'; battery = '${blocState.status.battery}%'; } else { debugPrint('⚠️ [MachineDetails] 没有实时数据,状态类型: ${blocState?.runtimeType}'); } return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 2))], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 12), child: Text(AppLocalizations.of(context).translate('machine_details.real_time_status'), style: const TextStyle(fontSize: 14, color: Color(0xFF999999))), ), _buildStatusRow(AppLocalizations.of(context).translate('machine_details.control_mode'), controlMode), const Divider(height: 24, color: Color(0xFFF0F0F0)), _buildStatusRow(AppLocalizations.of(context).translate('machine_details.battery_voltage'), voltage), const Divider(height: 24, color: Color(0xFFF0F0F0)), _buildStatusRow(AppLocalizations.of(context).translate('machine_details.remaining_battery'), battery), ], ), ); }, ); } Widget _buildStatusRow(String label, String value) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: const TextStyle(fontSize: 16, color: Color(0xFF333333))), Text(value, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF007AFF))), ], ); } /// 设备状态卡片(🔥 修改为视频展示 + 视角切换) Widget _buildDeviceStatusCard(DeviceEntity device) { return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 2))], ), child: Column( children: [ // 🔥 视频展示区域 AspectRatio( aspectRatio: 16 / 9, child: _videoStreamUrl.isNotEmpty ? WebRTCLocalPlayer( streamUrl: _videoStreamUrl, showLeftPip: false, // 不显示悬浮小窗 showRightPip: false, mainViewAlignment: _viewConfigs[_currentViewIndex]['alignment'] as Alignment, // 🔥 根据视角切换画面 ) : Container( color: Colors.black87, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.videocam_off, size: 64, color: Colors.white54), const SizedBox(height: 16), Text( '视频未加载', style: TextStyle(color: Colors.white70, fontSize: 16, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text( 'deviceId: $_deviceId', style: TextStyle(color: Colors.white54, fontSize: 12), ), const SizedBox(height: 4), Text( 'URL: ${_videoStreamUrl.isEmpty ? "空" : "已设置"}', style: TextStyle(color: Colors.white54, fontSize: 12), ), ], ), ), ), ), // 🔥 在线状态标签 Padding( padding: const EdgeInsets.all(12), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( color: device.isOnline ? const Color(0xFF00C853).withOpacity(0.1) : const Color(0xFF999999).withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( device.isOnline ? AppLocalizations.of(context).translate('home.device_online') : AppLocalizations.of(context).translate('home.device_offline'), style: TextStyle(fontSize: 14, color: device.isOnline ? const Color(0xFF00C853) : const Color(0xFF999999)), ), ), ], ), ), // 🔥 视角切换按钮 Padding( padding: const EdgeInsets.fromLTRB(12, 0, 12, 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: _viewConfigs.asMap().entries.map((entry) { final index = entry.key; final config = entry.value; final isSelected = _currentViewIndex == index; return Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 2), child: ElevatedButton( onPressed: () { setState(() { _currentViewIndex = index; }); debugPrint('🎬 [MachineDetails] 切换视角: ${config['name']}'); }, style: ElevatedButton.styleFrom( backgroundColor: isSelected ? const Color(0xFF165DFF) : Colors.grey[200], foregroundColor: isSelected ? Colors.white : Colors.grey[700], elevation: 0, padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), minimumSize: const Size(0, 36), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(config['icon'] as IconData, size: 16), const SizedBox(height: 2), Text( config['name'] as String, style: const TextStyle(fontSize: 10), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ), ); }).toList(), ), ), ], ), ); } /// 基本信息卡片(保持不变) Widget _buildBasicInfoCard(BuildContext context, DeviceEntity device) { final deviceId = device.deviceName ?? AppLocalizations.of(context).translate('common.unknown'); return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 2))], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 16), child: Text(AppLocalizations.of(context).translate('machine_details.basic_info'), style: const TextStyle(fontSize: 14, color: Color(0xFF999999))), ), _buildInfoRow( context: context, icon: Icons.info_outline, label: AppLocalizations.of(context).translate('machine_details.device_name'), trailing: GestureDetector( onTap: _isUpdatingName ? null : _showEditNameSheet, child: Row( mainAxisSize: MainAxisSize.min, children: [ Text(_deviceName, style: const TextStyle(fontSize: 16)), const SizedBox(width: 8), const Icon(Icons.edit, size: 16, color: Color(0xFF007AFF)), ], ), ), ), const Divider(height: 32, color: Color(0xFFF0F0F0)), _buildInfoRow( context: context, icon: Icons.shield_outlined, label: AppLocalizations.of(context).translate('machine_details.device_id'), trailing: Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ SizedBox( width: MediaQuery.of(context).size.width - 180, child: GestureDetector( onLongPress: () => _copyToClipboard(deviceId, AppLocalizations.of(context).translate('machine_details.copied')), child: Text( deviceId, textAlign: TextAlign.right, softWrap: true, overflow: TextOverflow.visible, style: const TextStyle(fontSize: 14, color: Colors.black87), ), ), ), const SizedBox(height: 4), GestureDetector( onTap: () => _copyToClipboard(deviceId, AppLocalizations.of(context).translate('machine_details.device_id') + AppLocalizations.of(context).translate('machine_details.copied')), child: const Icon(Icons.copy, size: 16, color: Color(0xFF999999)), ), ], ), ), ], ), ); } /// 资源中心卡片(保持不变) Widget _buildResourceCenterCard() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 2))], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(bottom: 16), child: Text(AppLocalizations.of(context).translate('machine_details.resource_center'), style: const TextStyle(fontSize: 14, color: Color(0xFF999999))), ), _buildResourceItem(AppLocalizations.of(context).translate('machine_details.user_manual'), Icons.description_outlined), const Divider(height: 32, color: Color(0xFFF0F0F0)), _buildResourceItem(AppLocalizations.of(context).translate('machine_details.product_manual'), Icons.book_outlined), ], ), ); } /// 通用信息行组件(保持不变) Widget _buildInfoRow({required BuildContext context, required IconData icon, required String label, required Widget trailing}) { return Row( children: [ Icon(icon, size: 18, color: const Color(0xFF999999)), const SizedBox(width: 12), Text(label, style: const TextStyle(fontSize: 16)), const Spacer(), trailing, ], ); } /// 资源项组件(保持不变) Widget _buildResourceItem(String title, IconData icon) { return InkWell( onTap: () { final loc = AppLocalizations.of(context); if (title == loc.translate('machine_details.user_manual')) { context.push(RoutePaths.usage); } else { context.push(RoutePaths.productDesc); } }, child: Row( children: [ Icon(icon, size: 18, color: const Color(0xFF007AFF)), const SizedBox(width: 12), Text(title, style: const TextStyle(fontSize: 16)), const Spacer(), const Icon(Icons.arrow_forward_ios, size: 16, color: Color(0xFF999999)), ], ), ); } /// 解绑设备按钮(保持不变) Widget _buildUnbindButton(BuildContext context) { return SizedBox( width: double.infinity, height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: const Color(0xFFFF3B30), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), side: const BorderSide(color: Color(0xFFFF3B30), width: 1), padding: const EdgeInsets.symmetric(vertical: 8), textStyle: const TextStyle(height: 1.2), ), onPressed: _isUpdatingName ? null : () => _showUnbindConfirmDialog(), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon(Icons.unarchive_outlined, size: 18), const SizedBox(width: 8), Text(AppLocalizations.of(context).translate('machine_details.unbind'), style: const TextStyle(fontSize: 16, height: 1.0), overflow: TextOverflow.visible), ], ), ), ); } /// 显示解绑确认弹窗(保持不变) void _showUnbindConfirmDialog() { showDialog( context: context, builder: (dialogContext) { _dialogContext = dialogContext; return AlertDialog( title: Text(AppLocalizations.of(dialogContext).translate('machine_details.unbind_confirm_title')), content: Text(AppLocalizations.of(dialogContext).translate('machine_details.unbind_confirm_content').replaceAll('%s', _deviceName)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), actions: [ TextButton(onPressed: () => Navigator.pop(dialogContext), child: Text(AppLocalizations.of(dialogContext).translate('common.cancel'))), TextButton( style: TextButton.styleFrom(foregroundColor: const Color(0xFFFF3B30)), onPressed: _executeUnbind, child: Text(AppLocalizations.of(dialogContext).translate('common.confirm')), ), ], ); }, ); } Future _executeUnbind() async { if (_deviceId.isEmpty || _deviceName.isEmpty) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.device_info_error')), backgroundColor: Colors.red)); } return; } // 关闭确认弹窗 if (_dialogContext != null && Navigator.canPop(_dialogContext!)) { Navigator.pop(_dialogContext!); } try { // 显示加载弹窗并记录上下文 if (context.mounted) { showDialog( context: context, barrierDismissible: false, builder: (ctx) { _loadingDialogContext = ctx; return AlertDialog(content: Row(children: [const CircularProgressIndicator(strokeWidth: 2), const SizedBox(width: 16), Text(AppLocalizations.of(ctx).translate('machine_details.unbinding_device'))])); }, ); } // 调用Cubit解绑方法 await context.read().unbindDevice(_deviceId, _deviceName); // 主动关闭加载弹窗 if (_loadingDialogContext != null && Navigator.canPop(_loadingDialogContext!)) { Navigator.pop(_loadingDialogContext!); _loadingDialogContext = null; } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.unbind_exception').replaceAll('%s', e.toString())), backgroundColor: Colors.red)); // 关闭加载弹窗 if (_loadingDialogContext != null && Navigator.canPop(_loadingDialogContext!)) { Navigator.pop(_loadingDialogContext!); _loadingDialogContext = null; } } } } /// 执行修改设备名称(核心修改:新增兜底逻辑) Future _executeUpdateDeviceName(String newDeviceName) async { // 基础校验 if (_deviceId.isEmpty || newDeviceName.isEmpty) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.device_info_error')), backgroundColor: Colors.red)); } setState(() => _isUpdatingName = false); return; } try { // 显示加载弹窗并记录专属上下文 if (context.mounted) { showDialog( context: context, barrierDismissible: false, builder: (ctx) { _updateLoadingContext = ctx; return AlertDialog(content: Row(children: [const CircularProgressIndicator(strokeWidth: 2), const SizedBox(width: 16), Text(AppLocalizations.of(ctx).translate('machine_details.updating_name'))])); }, ); } //print("调用updateDeviceName,deviceId: $_deviceId, newDeviceName: $newDeviceName"); // 调用Cubit修改方法 await context.read().updateDeviceName(_deviceId, newDeviceName); // 主动关闭修改名称加载弹窗 if (_updateLoadingContext != null && Navigator.canPop(_updateLoadingContext!)) { Navigator.pop(_updateLoadingContext!); _updateLoadingContext = null; } // 主动重置更新状态 setState(() => _isUpdatingName = false); // 兜底:强制将Cubit的isLoading置为false if (context.mounted) { context.read().emit(context.read().state.copyWith(isLoading: false, operationType: DeviceOperationType.none)); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.update_exception').replaceAll('%s', e.toString())), backgroundColor: Colors.red)); // 关闭修改名称加载弹窗 if (_updateLoadingContext != null && Navigator.canPop(_updateLoadingContext!)) { Navigator.pop(_updateLoadingContext!); _updateLoadingContext = null; } } setState(() => _isUpdatingName = false); // 兜底:强制重置Cubit的loading状态 if (context.mounted) { context.read().emit(context.read().state.copyWith(isLoading: false, operationType: DeviceOperationType.none)); } } } /// 处理解绑结果(保持不变) void _handleUnbindResult(DevicesState state) { // 强制关闭加载弹窗 if (_loadingDialogContext != null && Navigator.canPop(_loadingDialogContext!)) { Navigator.pop(_loadingDialogContext!); _loadingDialogContext = null; } else if (!state.isLoading && context.mounted && Navigator.canPop(context)) { Navigator.pop(context); } if (state.errorMessage?.isEmpty == true && !state.isLoading) { if (context.mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.unbind_success').replaceAll('%s', _deviceName)), backgroundColor: Colors.green, duration: const Duration(seconds: 2))); final username = context.read().state.user?.username ?? ""; // 🔥 修复:检查是否已有 targetDevice final remoteControlState = context.read().state; if (remoteControlState.targetDevice == null) { debugPrint('🔄 [MachineDetails Unbind] 无 targetDevice,开始加载设备列表'); context.read().fetchAllDevices(username); } else { debugPrint('✅ [MachineDetails Unbind] 已有 targetDevice: ${remoteControlState.targetDevice!.deviceName},跳过加载'); } } } else if (state.errorMessage?.isNotEmpty == true && !state.isLoading) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.unbind_failed').replaceAll('%s', state.errorMessage ?? AppLocalizations.of(context).translate('common.unknown'))), backgroundColor: Colors.red)); } } context.go(RoutePaths.home); } /// 处理修改名称结果(核心修改:放宽判断条件) void _handleUpdateNameResult(DevicesState state) { // 强制关闭修改名称加载弹窗(优先用专属上下文) if (_updateLoadingContext != null && Navigator.canPop(_updateLoadingContext!)) { Navigator.pop(_updateLoadingContext!); _updateLoadingContext = null; } // 兜底:兼容旧逻辑 else if (context.mounted && Navigator.canPop(context)) { // 不管loading状态,只要弹窗存在就关闭 Navigator.pop(context); } // 处理结果:放宽条件,只要无错误信息就认为成功(不管loading) // print( // "处理修改名称结果,operationType: ${state.operationType}, isLoading: ${state.isLoading}, errorMessage: ${state.errorMessage},state.errorMessage?.isEmpty: ${state.errorMessage?.isEmpty}", // ); // 核心修改:去掉!state.isLoading的判断 if (state.errorMessage?.isEmpty == true) { setState(() { _deviceName = _nameController.text.trim(); _isUpdatingName = false; // 双重保障重置状态 }); if (context.mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.name_updated_success').replaceAll('%s', _deviceName)), backgroundColor: Colors.green, duration: const Duration(seconds: 2))); // 关闭修改名称的底部抽屉(如果还在) if (_editNameSheetContext != null && Navigator.canPop(_editNameSheetContext!)) { Navigator.pop(_editNameSheetContext!); _editNameSheetContext = null; } // 强制重置Cubit的loading状态 context.read().emit(state.copyWith(isLoading: false, operationType: DeviceOperationType.none)); } } else if (state.errorMessage?.isNotEmpty == true) { setState(() => _isUpdatingName = false); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).translate('machine_details.update_failed').replaceAll('%s', state.errorMessage ?? AppLocalizations.of(context).translate('common.unknown'))), backgroundColor: Colors.red)); // 强制重置Cubit的loading状态 context.read().emit(state.copyWith(isLoading: false, operationType: DeviceOperationType.none)); } } } /// 复制到剪贴板(保持不变) void _copyToClipboard(String text, String tip) { Clipboard.setData(ClipboardData(text: text)); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(tip), duration: const Duration(seconds: 1))); } } }