wolfplus 2 years ago
parent
commit
357eb35ac8
  1. 60
      android/app/src/main/kotlin/com/example/deep_voice/AzureAsrHelper.kt
  2. 1
      android/app/src/main/kotlin/com/example/deep_voice/VoiceInteractionService.kt
  3. 439
      lib/data/services/bluetooth_service.dart
  4. 1
      lib/main.dart
  5. 41
      lib/modules/home/controllers/home_controller.dart
  6. 20
      lib/modules/home/views/home_view.dart
  7. 523
      lib/modules/pairing/controllers/pairing_controller.dart
  8. 232
      lib/modules/pairing/views/pairing_view.dart

60
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
}
}

1
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()
}

439
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<BluetoothService>();
@ -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 = <BluetoothDevice>[].obs;
final _systemPairedDevices = <BluetoothDevice>[].obs;
final _scanResults = <ScanResult>[].obs;
final _selectedDevice = Rx<BluetoothDevice?>(null);
final _deviceType = Rx<DeviceType>(DeviceType.unknown);
final _connectionState = Rx<BluetoothConnectionState>(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<BluetoothDevice> get connectedDevices => _connectedDevices;
List<BluetoothDevice> get systemPairedDevices => _systemPairedDevices;
List<ScanResult> 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<BluetoothDevice> get connectedDevicesObs => _connectedDevices;
RxList<ScanResult> get scanResultsObs => _scanResults;
Rx<BluetoothDevice?> get selectedDeviceObs => _selectedDevice;
Rx<DeviceType> get deviceTypeObs => _deviceType;
Rx<BluetoothConnectionState> 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>[
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<BluetoothDevice> devices = await FlutterBluePlus.connectedSystemDevices
@ -238,275 +241,8 @@ class BluetoothService extends GetxService {
Logger.info('获取到${pairedDevices.length}个系统已配对设备');
} catch (e) {
Logger.error('刷新系统设备失败: $e');
}
}
/// 开始扫描附近的蓝牙设备
Future<List<ScanResult>> 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<void> stopScan() async {
if (!_isScanning.value) return;
try {
await FlutterBluePlus.stopScan();
_isScanning.value = false;
Logger.info('已停止蓝牙扫描');
} catch (e) {
Logger.error('停止扫描失败: $e');
}
}
/// 连接到指定蓝牙设备
Future<bool> 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<bool> _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<bool> _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>();
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<bool> 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<BluetoothDevice?> 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<String, dynamic> 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<String> 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<BluetoothDevice?> 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();
}
}

1
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';

41
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;

20
lib/modules/home/views/home_view.dart

@ -368,6 +368,26 @@ class HomeView extends GetView<HomeController> {
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(),
),
),
),
],
),
],
),
),

523
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 = <ScanResult>[].obs;
List<ScanResult> get scannedDevices => _scannedDevices;
// 已连接的设备列表
final _connectedDevices = <BluetoothDevice>[].obs;
List<BluetoothDevice> get connectedDevices => _connectedDevices;
// 已配对的设备列表
final _pairedDevices = <BluetoothDevice>[].obs;
List<BluetoothDevice> 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<void> _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>()) {
_bluetoothService = Get.find<BluetoothService>();
// 如果服务未初始化,等待初始化完成
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<void> _waitForInitialization() async {
// 使用 Completer 将事件监听转换为 Future
final Completer<void> completer = Completer<void>();
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<BluetoothDevice> devices) {
_connectedDevices.value = devices;
// 只有当设备列表不为空时才刷新设备信息
if (devices.isNotEmpty) {
// 延迟一下再刷新,避免频繁刷新
Future.delayed(const Duration(milliseconds: 500), () {
_refreshDeviceInfo();
});
}
});
// 监听已配对设备变化
_pairedDevices.value = _bluetoothService.systemPairedDevices;
}
// 检查并请求权限
Future<void> _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<void> _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<void> _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<void> _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<BluetoothDevice> devices) {
if (devices.isEmpty) return null;
// 刷新设备信息
Future<void> _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<void> _scanForDevices() async {
_updateStatus(PairingStatus.scanning, '正在扫描附近设备...');
_scanRetryCount = 0;
_isRefreshing = true;
try {
// 确保先停止之前的扫描
await _bluetoothService.stopScan();
// 开始扫描
List<ScanResult> results = await _bluetoothService.startScan(
timeout: const Duration(seconds: 12)
);
_scannedDevices.value = results;
if (results.isEmpty) {
_handleNoDevicesFound();
return;
}
// 过滤可能的音频设备
List<ScanResult> 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<void> _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);
}
}

232
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<PairingController> {
const PairingView({Key? key}) : super(key: key);
@ -171,60 +172,77 @@ class PairingView extends GetView<PairingController> {
// 搜索状态
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<PairingController> {
),
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<PairingController> {
),
],
);
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<PairingController> {
elevation: 0,
),
child: Text(
'手动连接',
'刷新搜索',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,

Loading…
Cancel
Save