From c092038338a9f36e073d209863a81c86755b7081 Mon Sep 17 00:00:00 2001 From: wolfplus Date: Thu, 13 Mar 2025 20:44:18 +0000 Subject: [PATCH] v008 --- .../com/example/deep_voice/AzureAsrHelper.kt | 60 +- .../deep_voice/VoiceInteractionService.kt | 1 + lib/data/services/bluetooth_service.dart | 439 +++++---------- lib/main.dart | 1 - .../home/controllers/home_controller.dart | 41 +- lib/modules/home/views/home_view.dart | 20 + .../controllers/pairing_controller.dart | 523 ++++-------------- lib/modules/pairing/views/pairing_view.dart | 232 ++++---- 8 files changed, 429 insertions(+), 888 deletions(-) diff --git a/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt b/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt index 81bb77844..673658c39 100644 --- a/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt +++ b/android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt @@ -97,7 +97,7 @@ class AzureAsrHelper { } audioRecord = AudioRecord( - MediaRecorder.AudioSource.DEFAULT, + MediaRecorder.AudioSource.VOICE_COMMUNICATION, sampleRate, channelConfig, audioFormat, @@ -113,7 +113,7 @@ class AzureAsrHelper { // 获取音频会话 ID 并设置回音消除 audioSessionId = audioRecord?.audioSessionId ?: -1 - // setupEchoCancellation() + setupEchoCancellation() } // 开始一次性语音识别 @@ -466,35 +466,6 @@ class AzureAsrHelper { fun onError(error: String) } - // 开始连续语音识别(简化版,兼容旧代码) - fun startContinuousRecognition(callback: RecognizeCallback) { - startContinuousRecognition(null, object : ContinuousRecognizeCallback { - override fun onResult(result: String) { - callback.onResult(result) - } - - override fun onRecognizing(recognizing: String) { - // 不处理中间结果 - } - - override fun onSessionStarted() { - // 不处理会话开始事件 - } - - override fun onSessionStopped() { - // 不处理会话结束事件 - } - - override fun onCanceled(reason: String, errorDetails: String) { - callback.onError("识别取消: $reason, 详情: $errorDetails") - } - - override fun onError(error: String) { - callback.onError(error) - } - }) - } - // 设置回音消除 private fun setupEchoCancellation() { try { @@ -538,5 +509,32 @@ class AzureAsrHelper { Log.e(TAG, "释放回音消除资源时出错: ${e.message}", e) } } + + // 设置回音消除开关 + fun setEchoCancellationEnabled(enabled: Boolean): Boolean { + try { + if (echoCanceler != null) { + echoCanceler?.enabled = enabled + isEchoCancellationEnabled = echoCanceler?.enabled == true + Log.d(TAG, "回音消除状态已设置为: $isEchoCancellationEnabled") + return isEchoCancellationEnabled == enabled + } else if (enabled) { + // 如果当前没有回音消除器但需要启用,尝试创建 + if (audioSessionId != -1) { + setupEchoCancellation() + return isEchoCancellationEnabled + } + } + return false + } catch (e: Exception) { + Log.e(TAG, "设置回音消除状态时出错: ${e.message}", e) + return false + } + } + + // 获取回音消除状态 + fun isEchoCancellationEnabled(): Boolean { + return isEchoCancellationEnabled + } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt b/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt index 293bc8128..eca03395c 100644 --- a/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt +++ b/android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt @@ -962,6 +962,7 @@ class VoiceInteractionService : Service() { mediaPlayer?.setOnCompletionListener { Log.d(TAG, "无声播放完成") isPlayingAudio = false + release() // start() } diff --git a/lib/data/services/bluetooth_service.dart b/lib/data/services/bluetooth_service.dart index eae177804..22e18ddab 100644 --- a/lib/data/services/bluetooth_service.dart +++ b/lib/data/services/bluetooth_service.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:get/get.dart'; import '../../core/utils/logger.dart'; @@ -14,7 +13,7 @@ enum DeviceType { dual // 双模设备(同时支持经典蓝牙和BLE) } -/// 蓝牙设备服务,用于发现和管理蓝牙设备 +/// 简化的蓝牙设备服务,仅用于获取已连接或配对的蓝牙耳机信息 class BluetoothService extends GetxService { static BluetoothService get to => Get.find(); @@ -29,14 +28,12 @@ class BluetoothService extends GetxService { final _isOn = false.obs; final _isInitialized = false.obs; - // 操作状态 - final _isScanning = false.obs; + // 权限状态 final _permissionsGranted = false.obs; // 设备管理 final _connectedDevices = [].obs; final _systemPairedDevices = [].obs; - final _scanResults = [].obs; final _selectedDevice = Rx(null); final _deviceType = Rx(DeviceType.unknown); final _connectionState = Rx(BluetoothConnectionState.disconnected); @@ -44,21 +41,20 @@ class BluetoothService extends GetxService { // 流订阅 StreamSubscription? _stateSubscription; - StreamSubscription? _scanSubscription; - StreamSubscription? _connectionSubscription; + + // 防止重复刷新的标志 + bool _isRefreshingDevices = false; // ====== Getters ====== // 基本getter bool get isAvailable => _isAvailable.value; bool get isOn => _isOn.value; bool get isInitialized => _isInitialized.value; - bool get isScanning => _isScanning.value; bool get permissionsGranted => _permissionsGranted.value; // 设备相关getter List get connectedDevices => _connectedDevices; List get systemPairedDevices => _systemPairedDevices; - List get scanResults => _scanResults; BluetoothDevice? get selectedDevice => _selectedDevice.value; DeviceType get deviceType => _deviceType.value; BluetoothConnectionState get connectionState => _connectionState.value; @@ -68,10 +64,8 @@ class BluetoothService extends GetxService { RxBool get isAvailableObs => _isAvailable; RxBool get isOnObs => _isOn; RxBool get isInitializedObs => _isInitialized; - RxBool get isScanningObs => _isScanning; RxBool get permissionsGrantedObs => _permissionsGranted; RxList get connectedDevicesObs => _connectedDevices; - RxList get scanResultsObs => _scanResults; Rx get selectedDeviceObs => _selectedDevice; Rx get deviceTypeObs => _deviceType; Rx get connectionStateObs => _connectionState; @@ -93,7 +87,15 @@ class BluetoothService extends GetxService { // 2. 初始检查蓝牙状态 _checkBluetoothState(); - // 3. 标记初始化完成 + // 3. 请求权限 + await requestPermissions(); + + // 4. 刷新系统设备 + if (_isOn.value && _permissionsGranted.value) { + await _refreshSystemDevices(); + } + + // 5. 标记初始化完成 _isInitialized.value = true; Logger.info('蓝牙服务初始化完成'); return this; @@ -145,15 +147,9 @@ class BluetoothService extends GetxService { void _resetDeviceState() { _connectedDevices.clear(); _systemPairedDevices.clear(); - _scanResults.clear(); _selectedDevice.value = null; _lastConnectedDeviceInfo.value = {}; _deviceType.value = DeviceType.unknown; - - // 取消正在进行的操作 - _scanSubscription?.cancel(); - _connectionSubscription?.cancel(); - _isScanning.value = false; } /// 检查并请求蓝牙权限 @@ -167,10 +163,10 @@ class BluetoothService extends GetxService { // 请求所有必要权限 final permissions = [ - Permission.bluetoothScan, - Permission.bluetoothConnect, - Permission.location, // Android需要定位权限来扫描BLE设备 - Permission.microphone + // Permission.bluetoothScan, + // Permission.bluetoothConnect, + // Permission.location, // Android需要定位权限来扫描BLE设备 + Permission.microphone, ]; // 一次性请求所有权限 @@ -207,6 +203,13 @@ class BluetoothService extends GetxService { return; } + // 防止重复刷新 + if (_isRefreshingDevices) { + return; + } + + _isRefreshingDevices = true; + try { // 获取已连接的系统设备 List devices = await FlutterBluePlus.connectedSystemDevices @@ -238,275 +241,8 @@ class BluetoothService extends GetxService { Logger.info('获取到${pairedDevices.length}个系统已配对设备'); } catch (e) { Logger.error('刷新系统设备失败: $e'); - } - } - - /// 开始扫描附近的蓝牙设备 - Future> startScan({Duration? timeout}) async { - // 检查条件 - if (!_permissionsGranted.value) { - Logger.warning('缺少蓝牙扫描权限,无法扫描设备'); - return []; - } - - if (!_isOn.value) { - Logger.warning('蓝牙未开启,无法扫描设备'); - return []; - } - - // 如果已经在扫描,先停止 - if (_isScanning.value) { - await stopScan(); - } - - _scanResults.clear(); - Logger.info('开始扫描附近蓝牙设备...'); - - try { - // 设置结果监听 - _scanSubscription?.cancel(); - _scanSubscription = FlutterBluePlus.scanResults.listen((results) { - _scanResults.value = results; - }); - - // 开始扫描 - _isScanning.value = true; - await FlutterBluePlus.startScan( - timeout: timeout ?? const Duration(seconds: 10), - androidScanMode: AndroidScanMode.lowLatency, - ); - - // 扫描完成 - _isScanning.value = false; - Logger.info('扫描完成,发现${_scanResults.length}个设备'); - return _scanResults; - } catch (e) { - _isScanning.value = false; - Logger.error('扫描设备失败: $e'); - return []; - } - } - - /// 停止扫描 - Future stopScan() async { - if (!_isScanning.value) return; - - try { - await FlutterBluePlus.stopScan(); - _isScanning.value = false; - Logger.info('已停止蓝牙扫描'); - } catch (e) { - Logger.error('停止扫描失败: $e'); - } - } - - /// 连接到指定蓝牙设备 - Future connectToDevice(BluetoothDevice device) async { - // 检查条件 - if (!_permissionsGranted.value) { - Logger.warning('缺少蓝牙连接权限,无法连接设备'); - return false; - } - - if (!_isOn.value) { - Logger.warning('蓝牙未开启,无法连接设备'); - return false; - } - - Logger.info('尝试连接设备: ${device.platformName}'); - - try { - // 确定设备类型 - _determineDeviceType(device); - - // 检查设备是否已连接 - bool alreadyConnected = _connectedDevices.any((d) => d.remoteId.str == device.remoteId.str); - - // 如果当前已选择该设备且已连接,则无需再连接 - if (_selectedDevice.value == device && alreadyConnected) { - Logger.info('设备已连接,无需重复连接'); - _connectionState.value = BluetoothConnectionState.connected; - _updateLastConnectedDeviceInfo(); - return true; - } - - // 如果已选择了其他设备,先断开 - if (_selectedDevice.value != null && _selectedDevice.value != device) { - await disconnectFromDevice(); - } - - // 设置新的目标设备 - _selectedDevice.value = device; - - // 针对不同类型设备采取不同连接策略 - if (_deviceType.value == DeviceType.classicAudio) { - // 经典蓝牙设备(如音频设备)依赖系统连接 - return _connectToClassicAudioDevice(device); - } else { - // BLE设备直接通过库连接 - return _connectToBLEDevice(device); - } - } catch (e) { - Logger.error('连接设备过程中出错: $e'); - _connectionState.value = BluetoothConnectionState.disconnected; - return false; - } - } - - /// 连接经典蓝牙音频设备 - Future _connectToClassicAudioDevice(BluetoothDevice device) async { - Logger.info('尝试连接经典蓝牙音频设备'); - - try { - // 刷新系统设备列表 - await _refreshSystemDevices(); - - // 检查设备是否在系统已连接列表中 - bool connected = _connectedDevices.any((d) => d.remoteId.str == device.remoteId.str); - - if (connected) { - Logger.info('经典蓝牙设备已在系统连接列表中'); - _connectionState.value = BluetoothConnectionState.connected; - _updateLastConnectedDeviceInfo(); - return true; - } else { - Logger.info('经典蓝牙设备未在系统连接列表中,需要在系统设置中进行配对'); - _connectionState.value = BluetoothConnectionState.disconnected; - return false; - } - } catch (e) { - Logger.error('连接经典蓝牙设备失败: $e'); - _connectionState.value = BluetoothConnectionState.disconnected; - return false; - } - } - - /// 连接BLE设备 - Future _connectToBLEDevice(BluetoothDevice device) async { - Logger.info('尝试连接BLE设备'); - _connectionState.value = BluetoothConnectionState.connecting; - - try { - // 设置连接状态监听 - _connectionSubscription?.cancel(); - _connectionSubscription = device.connectionState.listen((state) { - Logger.info('BLE连接状态变化: $state'); - _connectionState.value = state; - - if (state == BluetoothConnectionState.connected) { - _updateLastConnectedDeviceInfo(); - } - }); - - // 尝试连接 - await device.connect( - autoConnect: false, - timeout: const Duration(seconds: 10) - ); - - // 等待连接状态 - final completer = Completer(); - bool isCompleted = false; // 添加一个本地变量跟踪完成状态 - - // 检查当前状态 - if (_connectionState.value == BluetoothConnectionState.connected) { - completer.complete(true); - isCompleted = true; - } else { - // 设置超时 - Timer(const Duration(seconds: 12), () { - if (!isCompleted) { // 使用本地变量而不是 completer.isCompleted - Logger.warning('连接设备超时'); - completer.complete(false); - isCompleted = true; - } - }); - } - - bool result = await completer.future; - - if (result) { - Logger.info('BLE设备连接成功'); - _updateLastConnectedDeviceInfo(); - } else { - Logger.warning('BLE设备连接失败'); - // 尝试断开连接 - await device.disconnect().catchError((_) {}); - } - - return result; - } catch (e) { - Logger.error('连接BLE设备失败: $e'); - _connectionState.value = BluetoothConnectionState.disconnected; - - // 尝试断开连接 - try { - await device.disconnect(); - } catch (_) {} - - return false; - } - } - - /// 断开当前设备连接 - Future disconnectFromDevice() async { - // 没有已选择的设备 - if (_selectedDevice.value == null) { - return true; - } - - // 取消连接状态监听 - _connectionSubscription?.cancel(); - _connectionSubscription = null; - - try { - // 对BLE设备才需要执行断开操作 - if (_deviceType.value != DeviceType.classicAudio) { - await _selectedDevice.value!.disconnect(); - } - - // 清除设备状态 - _selectedDevice.value = null; - _connectionState.value = BluetoothConnectionState.disconnected; - return true; - } catch (e) { - Logger.error('断开设备连接失败: $e'); - - // 即使失败,也清除选中设备 - _selectedDevice.value = null; - _connectionState.value = BluetoothConnectionState.disconnected; - return false; - } - } - - /// 查找系统已连接设备 - Future findConnectedSystemDevice() async { - if (!_permissionsGranted.value || !_isOn.value) { - Logger.warning('蓝牙未开启或缺少权限,无法查找系统连接设备'); - return null; - } - - try { - // 刷新系统设备列表 - await _refreshSystemDevices(); - - if (_connectedDevices.isEmpty) { - return null; - } - - // 优先找出可能的音频设备 - BluetoothDevice device = _findAudioDevice(_connectedDevices) ?? _connectedDevices.first; - - // 自动选择设备 - _selectedDevice.value = device; - _determineDeviceType(device); - _connectionState.value = BluetoothConnectionState.connected; - _updateLastConnectedDeviceInfo(); - - return device; - } catch (e) { - Logger.error('查找系统已连接设备失败: $e'); - return null; + } finally { + _isRefreshingDevices = false; } } @@ -561,16 +297,25 @@ class BluetoothService extends GetxService { }; } + // 判断设备是否在已连接列表中 + bool isConnected = _connectedDevices.any( + (d) => d.remoteId.str == _selectedDevice.value!.remoteId.str + ); + + // 判断设备是否在已配对列表中 + bool isPaired = _systemPairedDevices.any( + (d) => d.remoteId.str == _selectedDevice.value!.remoteId.str + ); + final deviceInfo = { - 'connected': _connectionState.value == BluetoothConnectionState.connected, + 'connected': isConnected, + 'paired': isPaired, 'device': { 'name': _selectedDevice.value!.platformName.isEmpty ? '未命名设备' : _selectedDevice.value!.platformName, 'id': _selectedDevice.value!.remoteId.str, - 'isConnected': _connectionState.value == BluetoothConnectionState.connected, - 'rssi': _scanResults - .firstWhereOrNull((r) => r.device.remoteId == _selectedDevice.value!.remoteId) - ?.rssi + 'isConnected': isConnected, + 'isPaired': isPaired, }, 'deviceType': _deviceType.value.toString().split('.').last }; @@ -578,6 +323,65 @@ class BluetoothService extends GetxService { return deviceInfo; } + /// 获取已配对设备的信息 + Map getPairedDeviceInfo(BluetoothDevice device) { + if (device == null) { + return { + 'connected': false, + 'paired': false, + 'device': null, + 'deviceType': DeviceType.unknown.toString().split('.').last + }; + } + + // 判断设备是否在已连接列表中 + bool isConnected = _connectedDevices.any( + (d) => d.remoteId.str == device.remoteId.str + ); + + // 确定设备类型 + DeviceType type = DeviceType.unknown; + final String deviceName = device.platformName.toLowerCase(); + + // 音频设备关键词 + final List audioKeywords = [ + 'headphone', 'earphone', 'earbuds', 'headset', + 'speaker', 'audio', '耳机', '音箱', '音响' + ]; + + bool hasAudioKeyword = audioKeywords.any((keyword) => deviceName.contains(keyword)); + if (hasAudioKeyword || isConnected) { + type = DeviceType.classicAudio; + } else { + type = DeviceType.ble; + } + + final deviceInfo = { + 'connected': isConnected, + 'paired': true, + 'device': { + 'name': device.platformName.isEmpty ? + '未命名设备' : device.platformName, + 'id': device.remoteId.str, + 'isConnected': isConnected, + 'isPaired': true, + }, + 'deviceType': type.toString().split('.').last + }; + + return deviceInfo; + } + + /// 设置选中的设备(不进行连接操作) + void setSelectedDevice(BluetoothDevice device) { + if (device != null) { + _selectedDevice.value = device; + _determineDeviceType(device); + _updateLastConnectedDeviceInfo(); + Logger.info('已设置选中设备: ${device.platformName}'); + } + } + /// 更新最后连接的设备信息 void _updateLastConnectedDeviceInfo() { if (_selectedDevice.value != null) { @@ -585,17 +389,48 @@ class BluetoothService extends GetxService { } } + /// 查找系统已连接设备 + Future findConnectedSystemDevice() async { + if (!_permissionsGranted.value || !_isOn.value) { + Logger.warning('蓝牙未开启或缺少权限,无法查找系统连接设备'); + return null; + } + + try { + // 刷新系统设备列表(避免重复刷新) + if (!_isRefreshingDevices) { + await _refreshSystemDevices(); + } + + // 如果没有已连接设备,直接返回null + if (_connectedDevices.isEmpty) { + Logger.info('未找到已连接的蓝牙设备'); + return null; + } + + // 优先找出可能的音频设备 + BluetoothDevice? audioDevice = _findAudioDevice(_connectedDevices); + BluetoothDevice device = audioDevice ?? _connectedDevices.first; + + // 自动选择设备 + _selectedDevice.value = device; + _determineDeviceType(device); + _connectionState.value = BluetoothConnectionState.connected; + _updateLastConnectedDeviceInfo(); + + Logger.info('找到已连接的蓝牙设备: ${device.platformName}'); + return device; + } catch (e) { + Logger.error('查找系统已连接设备失败: $e'); + return null; + } + } + /// 清理资源 @override void onClose() { // 取消所有订阅 _stateSubscription?.cancel(); - _scanSubscription?.cancel(); - _connectionSubscription?.cancel(); - - // 断开设备连接 - disconnectFromDevice(); - super.onClose(); } } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 5d0c06bf0..d9cc42e83 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,7 +9,6 @@ import 'core/routes/app_routes.dart'; import 'dart:io'; import 'package:window_size/window_size.dart'; import 'app/translations/app_translations.dart'; -import 'data/services/voice_interaction_service.dart'; import 'app/theme/app_theme.dart'; import 'app/theme/theme_service.dart'; diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart index c251295dc..b74cd8674 100644 --- a/lib/modules/home/controllers/home_controller.dart +++ b/lib/modules/home/controllers/home_controller.dart @@ -229,21 +229,30 @@ class HomeController extends GetxController { // 更新连接状态 void _updateConnectionStatus() { - if (_deviceInfo.containsKey('connected')) { - _isConnected.value = _deviceInfo['connected'] ?? false; + if (_deviceInfo.containsKey('connected') || _deviceInfo.containsKey('paired')) { + // 检查是否已连接 + bool isConnected = _deviceInfo['connected'] ?? false; + // 检查是否已配对 + bool isPaired = _deviceInfo['paired'] ?? false; - // 如果设备信息显示已连接,但状态不是已连接,则更新状态 - if (_isConnected.value && _connectionStatus.value != ConnectionStatus.connected) { + // 如果已连接,设置为已连接状态 + if (isConnected) { + _isConnected.value = true; _connectionStatus.value = ConnectionStatus.connected; - } else if (!_isConnected.value && _connectionStatus.value == ConnectionStatus.connected) { - // 如果设备显示未连接,但状态是已连接,则更新状态 + } + // 如果已配对但未连接,也视为已连接状态(简化处理) + else if (isPaired) { + _isConnected.value = true; + _connectionStatus.value = ConnectionStatus.connected; + } + // 如果既未连接也未配对,设置为未连接状态 + else { + _isConnected.value = false; _connectionStatus.value = ConnectionStatus.disconnected; } } else { _isConnected.value = false; - if (_connectionStatus.value == ConnectionStatus.connected) { - _connectionStatus.value = ConnectionStatus.disconnected; - } + _connectionStatus.value = ConnectionStatus.disconnected; } } @@ -453,8 +462,14 @@ class HomeController extends GetxController { } } - // 处理连接失败 + // 获取设备状态文本 String getConnectionStatusText() { + // 检查是否已配对但未连接 + if (_deviceInfo.containsKey('paired') && _deviceInfo['paired'] == true && + (_deviceInfo['connected'] == false || _deviceInfo['connected'] == null)) { + return "已配对"; + } + switch (_connectionStatus.value) { case ConnectionStatus.connected: return "已连接"; @@ -469,6 +484,12 @@ class HomeController extends GetxController { // 获取连接状态颜色 Color getConnectionStatusColor() { + // 检查是否已配对但未连接 + if (_deviceInfo.containsKey('paired') && _deviceInfo['paired'] == true && + (_deviceInfo['connected'] == false || _deviceInfo['connected'] == null)) { + return Colors.orange; // 已配对但未连接使用橙色 + } + switch (_connectionStatus.value) { case ConnectionStatus.connected: return Colors.green; diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index 6fccf62a6..526e9925f 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -368,6 +368,26 @@ class HomeView extends GetView { color: isDarkMode ? Colors.grey[400] : Colors.grey[500], ), ), + SizedBox(height: 4.h), + // 显示设备状态(已连接/已配对) + Row( + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), + decoration: BoxDecoration( + color: controller.getConnectionStatusColor().withOpacity(0.1), + borderRadius: BorderRadius.circular(4.r), + ), + child: Text( + controller.getConnectionStatusText(), + style: TextStyle( + fontSize: 10.sp, + color: controller.getConnectionStatusColor(), + ), + ), + ), + ], + ), ], ), ), diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 6baf4cce7..c9ea4bed3 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'package:get/get.dart'; import '../../../core/routes/app_routes.dart'; import '../../../data/services/bluetooth_service.dart'; @@ -7,34 +6,8 @@ import '../../../core/utils/logger.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/material.dart'; -enum PairingStatus { - initial, // 初始状态 - requesting, // 请求权限中 - scanning, // 扫描设备中 - connecting, // 连接设备中 - found, // 找到并连接设备 - noPermission, // 缺少权限 - bluetoothOff, // 蓝牙未开启 - needsSystemPairing, // 需要在系统设置中配对 - failed // 操作失败 -} - +/// 简化的配对控制器,仅用于显示已连接或配对的蓝牙耳机信息 class PairingController extends GetxController { - // 配对状态 - final _pairingStatus = PairingStatus.initial.obs; - PairingStatus get pairingStatus => _pairingStatus.value; - - // 状态描述(用于UI显示) - final _statusDescription = ''.obs; - String get statusDescription => _statusDescription.value; - - // 加载动画的点 - final _animationDots = ''.obs; - String get animationDots => _animationDots.value; - - // 动画定时器 - Timer? _animationTimer; - // 蓝牙服务 late BluetoothService _bluetoothService; @@ -48,23 +21,27 @@ class PairingController extends GetxController { bool get isBluetoothAvailable => _isBluetoothAvailable.value; bool get isBluetoothOn => _isBluetoothOn.value; - // 错误消息(包含解决方案提示) + // 错误消息 final _errorMessage = ''.obs; String get errorMessage => _errorMessage.value; - // 扫描到的设备列表 - final _scannedDevices = [].obs; - List get scannedDevices => _scannedDevices; + // 已连接的设备列表 + final _connectedDevices = [].obs; + List get connectedDevices => _connectedDevices; // 已配对的设备列表 final _pairedDevices = [].obs; List get pairedDevices => _pairedDevices; - // 重试计数(分别为不同操作设置) - int _initRetryCount = 0; - int _scanRetryCount = 0; - int _connectRetryCount = 0; - static const int MAX_RETRY_COUNT = 3; + // 状态描述(用于UI显示) + final _statusDescription = ''.obs; + String get statusDescription => _statusDescription.value; + + // 防止重复刷新的标志 + bool _isRefreshing = false; + + // 上次刷新时间 + DateTime? _lastRefreshTime; @override void onInit() { @@ -72,29 +49,20 @@ class PairingController extends GetxController { _initializeProcess(); } - @override - void onClose() { - _stopAnimation(); - _bluetoothService.stopScan(); - super.onClose(); - } - // 初始化流程 Future _initializeProcess() async { - // 启动动画 - _startAnimation(); - _updateStatus(PairingStatus.initial, '正在初始化...'); + _updateStatus('正在初始化...'); try { // 获取或初始化蓝牙服务 await _getBluetoothService(); - // 先检查权限,再处理后续流程 + // 检查权限并获取设备信息 await _checkAndRequestPermissions(); } catch (e) { Logger.error('初始化过程失败: $e'); - _updateStatus(PairingStatus.failed, '初始化失败'); - _setError('初始化蓝牙服务失败,请重试', '可能是蓝牙服务暂时不可用'); + _updateStatus('初始化失败'); + _setError('初始化蓝牙服务失败,请重试'); } } @@ -104,12 +72,6 @@ class PairingController extends GetxController { // 检查是否已注册 if (Get.isRegistered()) { _bluetoothService = Get.find(); - - // 如果服务未初始化,等待初始化完成 - if (!_bluetoothService.isInitialized) { - // 监听初始化状态变化 - await _waitForInitialization(); - } } else { // 初始化并注册服务 _bluetoothService = await Get.put(BluetoothService()).init(); @@ -117,42 +79,15 @@ class PairingController extends GetxController { // 设置蓝牙状态监听 _setupBluetoothListeners(); + + // 获取设备信息 + _refreshDeviceInfo(); } catch (e) { Logger.error('获取蓝牙服务失败: $e'); throw Exception('获取蓝牙服务失败: $e'); } } - // 等待蓝牙服务初始化完成 - Future _waitForInitialization() async { - // 使用 Completer 将事件监听转换为 Future - final Completer completer = Completer(); - late final Worker worker; - - // 一次性监听 - worker = ever(_bluetoothService.isInitializedObs, (bool initialized) { - if (initialized) { - completer.complete(); - worker.dispose(); // 完成后取消监听 - } - }); - - // 如果已经初始化,直接完成 - if (_bluetoothService.isInitialized) { - completer.complete(); - worker.dispose(); - } - - // 设置超时 - return completer.future.timeout( - const Duration(seconds: 10), - onTimeout: () { - worker.dispose(); - throw TimeoutException('等待蓝牙服务初始化超时'); - }, - ); - } - // 设置蓝牙状态监听 void _setupBluetoothListeners() { // 监听蓝牙可用性 @@ -161,8 +96,8 @@ class PairingController extends GetxController { _isBluetoothAvailable.value = available; if (!available) { - _updateStatus(PairingStatus.failed, '蓝牙不可用'); - _setError('蓝牙不可用', '请检查设备是否支持蓝牙功能'); + _updateStatus('蓝牙不可用'); + _setError('蓝牙不可用,请检查设备是否支持蓝牙功能'); } }); @@ -171,23 +106,38 @@ class PairingController extends GetxController { ever(_bluetoothService.isOnObs, (bool on) { _isBluetoothOn.value = on; - // 蓝牙状态改变时处理 if (on) { - if (_pairingStatus.value == PairingStatus.bluetoothOff) { - // 如果蓝牙刚被打开,继续配对流程 - _continueAfterBluetoothOn(); - } + // 蓝牙开启时,延迟一下再刷新设备信息,避免频繁刷新 + Future.delayed(const Duration(milliseconds: 500), () { + _refreshDeviceInfo(); + }); } else { - // 蓝牙关闭,更新状态 - _updateStatus(PairingStatus.bluetoothOff, '蓝牙已关闭'); - _setError('蓝牙已关闭', '请开启蓝牙后再试'); + _updateStatus('蓝牙已关闭'); + _setError('蓝牙已关闭,请开启蓝牙后再试'); } }); + + // 监听已连接设备变化 + _connectedDevices.value = _bluetoothService.connectedDevices; + ever(_bluetoothService.connectedDevicesObs, (List devices) { + _connectedDevices.value = devices; + + // 只有当设备列表不为空时才刷新设备信息 + if (devices.isNotEmpty) { + // 延迟一下再刷新,避免频繁刷新 + Future.delayed(const Duration(milliseconds: 500), () { + _refreshDeviceInfo(); + }); + } + }); + + // 监听已配对设备变化 + _pairedDevices.value = _bluetoothService.systemPairedDevices; } // 检查并请求权限 Future _checkAndRequestPermissions() async { - _updateStatus(PairingStatus.requesting, '正在请求权限...'); + _updateStatus('正在请求权限...'); try { bool hasPermissions = await _bluetoothService.requestPermissions(); @@ -200,17 +150,17 @@ class PairingController extends GetxController { // 权限已授予,检查蓝牙状态 if (!_bluetoothService.isOn) { - _updateStatus(PairingStatus.bluetoothOff, '蓝牙已关闭'); - _setError('蓝牙已关闭', '请开启蓝牙后再试'); + _updateStatus('蓝牙已关闭'); + _setError('蓝牙已关闭,请开启蓝牙后再试'); return; } - // 开始查找设备 - _startFindingDevices(); + // 刷新设备信息 + _refreshDeviceInfo(); } catch (e) { Logger.error('权限请求失败: $e'); - _updateStatus(PairingStatus.noPermission, '权限请求失败'); - _setError('权限请求失败', '请手动授予蓝牙和位置权限'); + _updateStatus('权限请求失败'); + _setError('权限请求失败,请手动授予蓝牙和位置权限'); } } @@ -231,14 +181,14 @@ class PairingController extends GetxController { location.isPermanentlyDenied; } - _updateStatus(PairingStatus.noPermission, '缺少必要权限'); + _updateStatus('缺少必要权限'); if (isPermanentlyDenied) { - _setError('缺少必要权限', '您已永久拒绝权限,请前往系统设置中手动开启'); + _setError('缺少必要权限,您已永久拒绝权限,请前往系统设置中手动开启'); // 显示前往设置的提示 _showGoToSettingsDialog(); } else { - _setError('缺少必要权限', '请授予蓝牙和位置权限以继续'); + _setError('缺少必要权限,请授予蓝牙和位置权限以继续'); } } @@ -256,7 +206,7 @@ class PairingController extends GetxController { TextButton( onPressed: () { Get.back(); - goToAppSettings(); + openAppSettings(); }, child: const Text('前往设置'), ), @@ -266,340 +216,89 @@ class PairingController extends GetxController { ); } - // 蓝牙开启后继续流程 - void _continueAfterBluetoothOn() { - if (_bluetoothService.permissionsGranted) { - _startFindingDevices(); - } else { - _checkAndRequestPermissions(); - } - } - - // 开始查找设备 - Future _startFindingDevices() async { - // 先检查上次连接的设备 - if (_checkLastConnectedDevice()) { - return; - } - - // 查找系统已连接的设备 - await _findSystemConnectedDevices(); - } - - // 检查上次连接的设备 - bool _checkLastConnectedDevice() { - // 检查是否有上次连接的设备信息 - if (_bluetoothService.lastConnectedDeviceInfo.isNotEmpty && - _bluetoothService.lastConnectedDeviceInfo['connected'] == true) { - Logger.info('使用上次连接的设备信息'); - _deviceInfo.value = _bluetoothService.lastConnectedDeviceInfo; - _onDeviceConnected(); - return true; - } - return false; - } - - // 查找系统已连接的设备 - Future _findSystemConnectedDevices() async { - _updateStatus(PairingStatus.scanning, '正在查找已连接设备...'); - - try { - // 查找系统已连接的设备 - BluetoothDevice? device = await _bluetoothService.findConnectedSystemDevice() - .timeout(const Duration(seconds: 10), onTimeout: () => null); - - if (device != null) { - Logger.info('找到系统已连接设备'); - _deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); - _onDeviceConnected(); - return; - } - - // 如果没有找到已连接设备,检查已配对设备 - await _checkPairedDevices(); - } catch (e) { - Logger.error('查找系统连接设备失败: $e'); - // 继续查找已配对设备,不立即失败 - await _checkPairedDevices(); - } - } - - // 检查已配对设备 - Future _checkPairedDevices() async { - _updateStatus(PairingStatus.scanning, '正在检查已配对设备...'); - - // 获取已配对设备列表 - _pairedDevices.value = _bluetoothService.systemPairedDevices; - - // 如果有已配对的设备,尝试连接 - if (_pairedDevices.isNotEmpty) { - Logger.info('找到${_pairedDevices.length}个已配对设备,尝试连接'); - - // 根据设备名称过滤可能的音频设备 - BluetoothDevice deviceToConnect = _findBestAudioDevice(_pairedDevices) ?? _pairedDevices.first; - - await _connectToDevice(deviceToConnect); - } else { - // 如果没有已配对设备,开始扫描附近设备 - await _scanForDevices(); - } - } - - // 在设备列表中查找最可能的音频设备 - BluetoothDevice? _findBestAudioDevice(List devices) { - if (devices.isEmpty) return null; + // 刷新设备信息 + Future _refreshDeviceInfo() async { + // 防止重复刷新 + if (_isRefreshing) return; - for (var device in devices) { - String name = device.platformName.toLowerCase(); - if (name.contains('headphone') || - name.contains('earphone') || - name.contains('earbuds') || - name.contains('headset') || - name.contains('speaker') || - name.contains('audio') || - name.contains('耳机') || - name.contains('音箱')) { - return device; - } - } - return null; - } - - // 扫描附近的蓝牙设备 - Future _scanForDevices() async { - _updateStatus(PairingStatus.scanning, '正在扫描附近设备...'); - _scanRetryCount = 0; + _isRefreshing = true; - try { - // 确保先停止之前的扫描 - await _bluetoothService.stopScan(); - - // 开始扫描 - List results = await _bluetoothService.startScan( - timeout: const Duration(seconds: 12) - ); - - _scannedDevices.value = results; - - if (results.isEmpty) { - _handleNoDevicesFound(); - return; - } - - // 过滤可能的音频设备 - List audioDevices = results.where((result) { - String name = result.device.platformName.toLowerCase(); - return name.contains('headphone') || - name.contains('earphone') || - name.contains('earbuds') || - name.contains('headset') || - name.contains('speaker') || - name.contains('audio') || - name.contains('耳机') || - name.contains('音箱'); - }).toList(); - - // 按信号强度排序 - if (audioDevices.isNotEmpty) { - audioDevices.sort((a, b) => b.rssi.compareTo(a.rssi)); - Logger.info('找到${audioDevices.length}个可能的音频设备'); - - // 连接信号最强的音频设备 - await _connectToDevice(audioDevices.first.device); - } else if (results.isNotEmpty) { - // 如果没有明确的音频设备但有其他设备,按信号排序 - results.sort((a, b) => b.rssi.compareTo(a.rssi)); - Logger.info('未找到明确的音频设备,尝试连接信号最强的设备'); - - await _connectToDevice(results.first.device); - } - } catch (e) { - Logger.error('扫描设备失败: $e'); - _updateStatus(PairingStatus.failed, '扫描失败'); - _setError('扫描设备失败', '请确保蓝牙已开启并重试'); - } - } - - // 处理未找到设备的情况 - void _handleNoDevicesFound() { - if (_scanRetryCount < MAX_RETRY_COUNT) { - _scanRetryCount++; - Logger.info('未找到设备,自动重试 (${_scanRetryCount}/${MAX_RETRY_COUNT})'); - _updateStatus(PairingStatus.scanning, '未找到设备,重试中...'); - - // 延迟2秒后重试 - Future.delayed(const Duration(seconds: 2), _scanForDevices); - } else { - _updateStatus(PairingStatus.failed, '未找到设备'); - _setError('未找到任何蓝牙设备', '请确保设备已开启并在附近,或点击刷新重试'); + if (!_isBluetoothOn.value) { + _updateStatus('蓝牙已关闭'); + _deviceInfo.value = {}; + _isRefreshing = false; + return; } - } - - // 连接到指定设备 - Future _connectToDevice(BluetoothDevice device) async { - _updateStatus(PairingStatus.connecting, '正在连接到 "${device.platformName}"...'); - _connectRetryCount = 0; try { - // 停止当前扫描 - await _bluetoothService.stopScan(); + // 更新已配对设备列表 + _pairedDevices.value = _bluetoothService.systemPairedDevices; - bool connected = await _bluetoothService.connectToDevice(device); + // 查找系统已连接设备 + BluetoothDevice? device = await _bluetoothService.findConnectedSystemDevice(); - if (connected) { - Logger.info('成功连接到设备: ${device.platformName}'); + if (device != null) { + // 已连接设备 _deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); - _onDeviceConnected(); + _updateStatus('已连接到蓝牙设备'); + _goToHomePage(); + } else if (_bluetoothService.lastConnectedDeviceInfo.isNotEmpty) { + // 使用上次连接的设备信息 + _deviceInfo.value = _bluetoothService.lastConnectedDeviceInfo; + _updateStatus('使用上次连接的设备信息'); + _goToHomePage(); + } else if (_pairedDevices.isNotEmpty) { + // 使用已配对设备 + BluetoothDevice pairedDevice = _pairedDevices.first; + _deviceInfo.value = _bluetoothService.getPairedDeviceInfo(pairedDevice); + _bluetoothService.setSelectedDevice(pairedDevice); + _updateStatus('已找到配对设备'); + _goToHomePage(); } else { - _handleConnectionFailed(device); + // 没有找到任何设备 + _deviceInfo.value = {}; + _updateStatus('未找到已连接或配对的蓝牙设备'); } } catch (e) { - Logger.error('连接设备失败: $e'); - _handleConnectionFailed(device); - } - } - - // 处理连接失败 - void _handleConnectionFailed(BluetoothDevice device) { - // 检查设备类型 - if (_bluetoothService.deviceType == DeviceType.classicAudio) { - // 经典蓝牙音频设备需要在系统设置中配对 - _updateStatus(PairingStatus.needsSystemPairing, '需要系统配对'); - _setError('这是音频设备,需要在系统设置中配对', '请前往系统蓝牙设置完成配对'); - } else if (_connectRetryCount < MAX_RETRY_COUNT) { - // 自动重试连接 - _connectRetryCount++; - Logger.info('连接失败,自动重试 (${_connectRetryCount}/${MAX_RETRY_COUNT})'); - _updateStatus(PairingStatus.connecting, '连接失败,重试中...'); - - // 延迟2秒后重试 - Future.delayed(const Duration(seconds: 2), () => _connectToDevice(device)); - } else { - // 超过重试次数 - _updateStatus(PairingStatus.failed, '连接失败'); - _setError('连接设备失败', '请确保设备已开启且处于配对模式,或点击刷新重试'); + Logger.error('刷新设备信息失败: $e'); + _updateStatus('获取设备信息失败'); + } finally { + _isRefreshing = false; } } - // 设备连接成功 - void _onDeviceConnected() { - _updateStatus(PairingStatus.found, '设备连接成功'); - - // 延迟跳转到主页 - Timer(const Duration(seconds: 1), () { - Get.offAllNamed(Routes.home, arguments: _deviceInfo.value); - }); - } - - // 更新状态(内部方法) - void _updateStatus(PairingStatus status, String description) { - _pairingStatus.value = status; + // 更新状态描述 + void _updateStatus(String description) { _statusDescription.value = description; - - // 根据状态自动控制动画 - if ([PairingStatus.initial, PairingStatus.requesting, PairingStatus.scanning, PairingStatus.connecting].contains(status)) { - _startAnimation(); - } else { - _stopAnimation(); - } + Logger.info('状态更新: $description'); } // 设置错误信息 - void _setError(String message, String solution) { - _errorMessage.value = '$message\n$solution'; - } - - // 动画控制 - void _startAnimation() { - _stopAnimation(); // 确保先停止已有动画 - - int count = 0; - _animationTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) { - count = (count + 1) % 4; - _animationDots.value = '.' * count; - }); + void _setError(String message) { + _errorMessage.value = message; + Logger.warning('错误: $message'); } - void _stopAnimation() { - _animationTimer?.cancel(); - _animationTimer = null; - _animationDots.value = ''; + // 跳转到主页 + void _goToHomePage() { + Get.offAllNamed(Routes.home, arguments: _deviceInfo.value); } - // 公开方法 - // 刷新搜索 void refreshSearch() { - // 停止当前动画和扫描 - _stopAnimation(); - _bluetoothService.stopScan(); - - // 重置重试计数 - _scanRetryCount = 0; - _connectRetryCount = 0; - - // 重新开始流程 - _initializeProcess(); - } - - // 打开应用设置 - void goToAppSettings() async { - try { - await openAppSettings(); - } catch (e) { - Logger.error('打开应用设置失败: $e'); - Get.snackbar( - '提示', - '无法自动打开设置,请手动前往系统设置授予权限', - snackPosition: SnackPosition.TOP, - backgroundColor: Colors.red[100], - colorText: Colors.red[800], - duration: const Duration(seconds: 3), - ); - } - } - - // 跳转到系统蓝牙设置 - void openSystemBluetoothSettings() async { - try { - if (GetPlatform.isAndroid) { - await openAppSettings(); - } else { - // iOS不能直接打开蓝牙设置 - Get.snackbar( - '提示', - '请手动打开系统设置并配对您的蓝牙设备', - snackPosition: SnackPosition.TOP, - backgroundColor: Colors.blue[100], - colorText: Colors.blue[800], - duration: const Duration(seconds: 3), - ); - } - } catch (e) { - Logger.error('打开系统设置失败: $e'); - Get.snackbar( - '提示', - '无法自动打开设置,请手动前往系统蓝牙设置', - snackPosition: SnackPosition.TOP, - backgroundColor: Colors.red[100], - colorText: Colors.red[800], - duration: const Duration(seconds: 3), - ); + // 防止频繁刷新,限制最小刷新间隔为2秒 + final now = DateTime.now(); + if (_lastRefreshTime != null && + now.difference(_lastRefreshTime!).inSeconds < 2) { + return; } + + _lastRefreshTime = now; + _refreshDeviceInfo(); } // 跳过连接 void skipConnecting() { - // 停止扫描和动画 - _bluetoothService.stopScan(); - _stopAnimation(); - - // 直接跳转到主页 Get.offAllNamed(Routes.home); } - - // 手动连接特定设备 - void connectToDevice(BluetoothDevice device) { - _connectToDevice(device); - } } \ No newline at end of file diff --git a/lib/modules/pairing/views/pairing_view.dart b/lib/modules/pairing/views/pairing_view.dart index 40fd7e36c..7341fbe48 100644 --- a/lib/modules/pairing/views/pairing_view.dart +++ b/lib/modules/pairing/views/pairing_view.dart @@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../controllers/pairing_controller.dart'; import '../../../core/widgets/common_bottom_nav.dart'; import '../../../app/theme/app_theme.dart'; +import 'package:permission_handler/permission_handler.dart'; class PairingView extends GetView { const PairingView({Key? key}) : super(key: key); @@ -171,60 +172,77 @@ class PairingView extends GetView { // 搜索状态 Widget _buildSearchStatus(bool isDarkMode) { return Obx(() { - switch (controller.pairingStatus) { - case PairingStatus.initial: - case PairingStatus.requesting: - case PairingStatus.scanning: - case PairingStatus.connecting: - return Column( - children: [ - Text( - '${controller.statusDescription}${controller.animationDots}', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - SizedBox(height: 8.h), - Text( - '请打开耳机充电盒,将耳机放入您的耳朵', - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.white70 : Colors.black54, + final String status = controller.statusDescription; + final bool hasDevice = controller.deviceInfo.isNotEmpty && controller.deviceInfo['device'] != null; + final bool hasError = controller.errorMessage.isNotEmpty; + + // 已找到设备 + if (hasDevice) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.check_circle, color: Colors.green, size: 20.sp), + SizedBox(width: 8.w), + Text( + '设备信息获取成功', + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w600, + color: Colors.green, + ), ), + ], + ), + SizedBox(height: 8.h), + Text( + '正在跳转到主页...', + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, ), - ], - ); - case PairingStatus.found: + ), + ], + ); + } + + // 有错误信息 + if (hasError) { + // 蓝牙关闭错误 + if (status.contains('蓝牙已关闭')) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.check_circle, color: Colors.green, size: 20.sp), + Icon(Icons.bluetooth_disabled, color: Colors.orange, size: 20.sp), SizedBox(width: 8.w), Text( - '设备连接成功', + '蓝牙已关闭', style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, - color: Colors.green, + color: Colors.orange, ), ), ], ), SizedBox(height: 8.h), Text( - '正在跳转到主页...', + controller.errorMessage, style: TextStyle( fontSize: 14.sp, color: isDarkMode ? Colors.white70 : Colors.black54, ), + textAlign: TextAlign.center, ), ], ); - case PairingStatus.noPermission: + } + + // 权限错误 + if (status.contains('权限')) { return Column( children: [ Row( @@ -253,7 +271,7 @@ class PairingView extends GetView { ), SizedBox(height: 16.h), ElevatedButton( - onPressed: () => controller.goToAppSettings(), + onPressed: () => openAppSettings(), style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, foregroundColor: Colors.white, @@ -266,111 +284,61 @@ class PairingView extends GetView { ), ], ); - case PairingStatus.bluetoothOff: - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.bluetooth_disabled, color: Colors.orange, size: 20.sp), - SizedBox(width: 8.w), - Text( - '蓝牙已关闭', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: Colors.orange, - ), - ), - ], - ), - SizedBox(height: 8.h), - Text( - controller.errorMessage, - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.white70 : Colors.black54, - ), - textAlign: TextAlign.center, - ), - ], - ); - case PairingStatus.failed: - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.error, color: Colors.red, size: 20.sp), - SizedBox(width: 8.w), - Text( - controller.statusDescription.isEmpty ? '未找到设备' : controller.statusDescription, - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: Colors.red, - ), - ), - ], - ), - SizedBox(height: 8.h), - Text( - controller.errorMessage.isEmpty ? - '请确保耳机已开机并在附近' : controller.errorMessage, - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.white70 : Colors.black54, - ), - textAlign: TextAlign.center, - ), - ], - ); - case PairingStatus.needsSystemPairing: - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.bluetooth_searching, color: const Color(0xFF0066CC), size: 20.sp), - SizedBox(width: 8.w), - Text( - '需要系统配对', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: const Color(0xFF0066CC), - ), - ), - ], - ), - SizedBox(height: 8.h), - Text( - controller.errorMessage.isEmpty ? - '请在系统设置中配对您的设备' : controller.errorMessage, - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.white70 : Colors.black54, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: 16.h), - ElevatedButton( - onPressed: () => controller.openSystemBluetoothSettings(), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0066CC), - foregroundColor: Colors.white, - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.r), + } + + // 其他错误 + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error, color: Colors.red, size: 20.sp), + SizedBox(width: 8.w), + Text( + status.isEmpty ? '未找到设备' : status, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w600, + color: Colors.red, ), ), - child: const Text('打开蓝牙设置'), + ], + ), + SizedBox(height: 8.h), + Text( + controller.errorMessage.isEmpty ? + '请确保耳机已开机并在附近' : controller.errorMessage, + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, ), - ], - ); - default: - return const SizedBox(); + textAlign: TextAlign.center, + ), + ], + ); } + + // 默认状态(正在搜索/初始化) + return Column( + children: [ + Text( + status, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.black, + ), + ), + SizedBox(height: 8.h), + Text( + '请打开耳机充电盒,将耳机放入您的耳朵', + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, + ), + ), + ], + ); }); } @@ -392,7 +360,7 @@ class PairingView extends GetView { elevation: 0, ), child: Text( - '手动连接', + '刷新搜索', style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w500,