You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
9.5 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/ble_test_controller.dart';
class BleTestView extends GetView<BleTestController> {
const BleTestView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BLE测试'),
actions: [
Obx(() => IconButton(
icon: const Icon(Icons.refresh),
onPressed: controller.isScanning.value ? null : controller.startScan,
)),
],
),
body: Column(
children: [
// 状态消息 - 使用AnimatedContainer让过渡更平滑
Obx(() => AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.all(8),
width: double.infinity,
color: Colors.grey[200],
child: Text(
controller.statusMessage.value,
style: const TextStyle(fontSize: 14),
),
)),
// 根据连接状态显示不同的内容
Expanded(
child: Obx(() {
// 保存连接状态到局部变量,避免多次访问反应式变量
final isConnected = controller.isConnected.value;
return isConnected ? _buildConnectedView() : _buildScanView();
}),
),
],
),
);
}
// 扫描视图
Widget _buildScanView() {
return Column(
children: [
// 扫描控制
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Obx(() {
final isScanning = controller.isScanning.value;
return ElevatedButton(
onPressed: isScanning ? null : controller.startScan,
child: Text(isScanning ? '扫描中...' : '开始扫描'),
);
}),
Obx(() => ElevatedButton(
onPressed: controller.isScanning.value
? controller.stopScan
: null,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
child: const Text('停止扫描'),
)),
],
),
),
// 设备列表 - 使用RepaintBoundary提高性能
Expanded(
child: RepaintBoundary(
child: Obx(() {
if (controller.deviceList.isEmpty) {
return const Center(
child: Text('没有找到设备,请开始扫描'),
);
}
// 仅在需要时创建列表视图
return ListView.builder(
// 使用常量key避免整体重建
key: const ValueKey('device_list'),
itemCount: controller.deviceList.length,
itemBuilder: (context, index) {
final device = controller.deviceList[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: ListTile(
title: Text(device.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('ID: ${device.id}'),
if (device.uuids.isNotEmpty)
Text(
'UUID: ${device.uuids.length > 0 ? device.uuids.first : "无"}',
style: const TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
if (device.uuids.length > 1)
Text(
'其他UUID: ${device.uuids.length - 1}个',
style: const TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis,
),
],
),
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('RSSI: ${device.rssi}'),
const SizedBox(height: 4),
const Icon(Icons.bluetooth, size: 16),
],
),
onTap: () => controller.connectToDevice(device.id),
),
);
},
);
}),
),
),
],
);
}
// 已连接设备视图
Widget _buildConnectedView() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 设备信息卡片
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Obx(() => Text(
'设备地址: ${controller.connectedDeviceAddress.value}',
style: const TextStyle(fontWeight: FontWeight.bold),
)),
const SizedBox(height: 8),
Obx(() => Text('电池电量: ${controller.batteryLevel.value}%')),
const SizedBox(height: 4),
Obx(() => Text('固件版本: ${controller.firmwareVersion.value}')),
const SizedBox(height: 16),
Wrap(
spacing: 8, // 水平间距
runSpacing: 8, // 垂直间距
alignment: WrapAlignment.spaceBetween,
children: [
SizedBox(
width: 110,
child: ElevatedButton(
onPressed: controller.getDeviceVersion,
child: const Text('获取版本'),
),
),
SizedBox(
width: 110,
child: ElevatedButton(
onPressed: controller.getBatteryInfo,
child: const Text('获取电量'),
),
),
SizedBox(
width: 110,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
onPressed: controller.disconnect,
child: const Text('断开连接'),
),
),
],
),
],
),
),
),
const SizedBox(height: 24),
// 音频控制
const Text('音频控制', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.start,
children: [
SizedBox(
width: 140,
child: ElevatedButton(
onPressed: controller.openEncoder,
child: const Text('打开编码器'),
),
),
SizedBox(
width: 140,
child: ElevatedButton(
onPressed: controller.openDecoder,
child: const Text('打开解码器'),
),
),
],
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.start,
children: [
SizedBox(
width: 140,
child: ElevatedButton(
onPressed: controller.closeCodec,
child: const Text('关闭编解码器'),
),
),
SizedBox(
width: 140,
child: ElevatedButton(
onPressed: controller.playA2DP,
child: const Text('播放A2DP'),
),
),
],
),
const SizedBox(height: 24),
// 音量控制
const Text('音量控制', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
alignment: WrapAlignment.start,
children: [
SizedBox(
width: 140,
child: ElevatedButton(
onPressed: controller.volumeUp,
child: const Text('音量+'),
),
),
SizedBox(
width: 140,
child: ElevatedButton(
onPressed: controller.volumeDown,
child: const Text('音量-'),
),
),
],
),
],
),
);
}
}