flutter_sdk/example/lib/tabs/device_scan_tab.dart

184 lines
6.3 KiB
Dart
Raw Normal View History

2026-08-20 09:25:05 +08:00
import 'package:flutter/material.dart';
import 'package:flutter_sdk/starcloud_flutter_sdk.dart';
import 'package:starcloud/entity/star_cloud_lock_list.dart' as scl;
import '../l10n.dart';
import '../global.dart';
import '../widgets/common_widgets.dart';
class DeviceScanTab extends StatefulWidget {
const DeviceScanTab({super.key});
@override
State<DeviceScanTab> createState() => _DeviceScanTabState();
}
class _DeviceScanTabState extends State<DeviceScanTab> {
bool _scanning = false;
bool _pairing = false;
List<dynamic> _devices = [];
final List<String> _log = [];
void _log_(String msg) {
final ts = DateTime.now().toIso8601String().substring(11, 19);
setState(() => _log.add('[$ts] $msg'));
}
Future<void> _scan() async {
if (!sdkCloudAccountReady.value) {
_log_(S.isEn
? 'Set an SDK cloud account before scanning and pairing a lock.'
: '请先在“登录”页创建或设置 SDK 星云账户,再扫描绑定锁。');
return;
}
setState(() {
_scanning = true;
_devices = [];
});
_log_(S.isEn ? 'Scan start (10s)...' : '开始扫描(10 秒超时)...');
try {
await StarCloudClient.instance.device.scanDeviceList(
timeout: 10,
onScan: (results) {
setState(() => _devices = results);
});
_log_(S.isEn
? 'Done. Found ${_devices.length}'
: '扫描完成,发现 ${_devices.length} 个设备');
} catch (e) {
_log_('${S.isEn ? "Failed" : "失败"}: $e');
} finally {
setState(() => _scanning = false);
}
}
Future<void> _pair(int idx) async {
if (!sdkCloudAccountReady.value) {
_log_(
S.isEn ? 'Please set an SDK cloud account first.' : '请先设置 SDK 星云账户。');
return;
}
setState(() => _pairing = true);
_log_(S.isEn ? 'Pairing...' : '正在配对...');
try {
final lock = await StarCloudClient.instance.device
.pairDevice(scanResult: _devices[idx]);
// 更新 ValueNotifier 的值
2026-10-19 16:17:25 +08:00
wifiConfiguredLockId.value = null;
2026-08-20 09:25:05 +08:00
pairedLockId.value = lock.lockId;
pairedLock.value = lock;
_log_('${S.isEn ? "Success" : "成功"}! ID: ${lock.lockId}');
} catch (e) {
_log_('${S.isEn ? "Failed" : "失败"}: $e');
} finally {
setState(() => _pairing = false);
}
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>(
valueListenable: S.langNotifier,
builder: (context, isEn, _) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _scanning ? null : _scan,
icon: _scanning
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2))
: const Icon(Icons.bluetooth_searching),
label: Text(_scanning ? S.btnScanning : S.btnScan),
),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: _scanning
? () => StarCloudClient.instance.device
.stopScan()
.then((_) => setState(() => _scanning = false))
: null,
child: Text(S.btnStop)),
],
),
),
// 使用 ValueListenableBuilder 监听配对状态
ValueListenableBuilder<int?>(
valueListenable: pairedLockId,
builder: (context, id, _) {
if (id == null) return const SizedBox.shrink();
return Container(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
alignment: Alignment.centerLeft,
child: Chip(
label: Text('${S.pairedStatus}: #$id'),
backgroundColor: Colors.green.shade50,
onDeleted: () {
2026-10-19 16:17:25 +08:00
wifiConfiguredLockId.value = null;
2026-08-20 09:25:05 +08:00
pairedLockId.value = null;
pairedLock.value = null;
},
),
);
},
),
Expanded(
child: ValueListenableBuilder<scl.StarCloudLock?>(
valueListenable: pairedLock,
builder: (context, paired, _) {
if (_devices.isEmpty) {
return Center(
child: Text(
S.scanHint,
style: const TextStyle(color: Colors.grey),
),
);
}
return ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 12),
itemCount: _devices.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (context, i) {
final device = _devices[i] as StarCloudScanResult;
final isPaired = _isPairedDevice(device, paired);
return ListTile(
title: Text(device.advName.isNotEmpty
? device.advName
: (S.isEn ? 'Unknown' : '未知设备')),
subtitle: Text('MAC: ${device.id}'),
trailing: ElevatedButton(
onPressed:
_pairing || isPaired ? null : () => _pair(i),
child: Text(isPaired ? S.pairedStatus : S.btnPair),
),
);
},
);
},
),
),
LogArea(log: _log),
],
);
},
);
}
bool _isPairedDevice(
StarCloudScanResult device,
scl.StarCloudLock? paired,
) {
if (paired == null) return false;
return paired.mac == device.id ||
paired.bluetooth.bluetoothDeviceName == device.advName;
}
}