2026-08-20 09:25:05 +08:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_sdk/starcloud_flutter_sdk.dart';
|
|
|
|
|
import '../l10n.dart';
|
|
|
|
|
import '../global.dart';
|
|
|
|
|
import '../widgets/common_widgets.dart';
|
|
|
|
|
|
|
|
|
|
class LockControlTab extends StatefulWidget {
|
|
|
|
|
const LockControlTab({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<LockControlTab> createState() => _LockControlTabState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _LockControlTabState extends State<LockControlTab> {
|
|
|
|
|
final List<String> _log = [];
|
|
|
|
|
bool _loading = false;
|
|
|
|
|
|
|
|
|
|
void _log_(String msg) {
|
|
|
|
|
final ts = DateTime.now().toIso8601String().substring(11, 19);
|
|
|
|
|
setState(() => _log.add('[$ts] $msg'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _run(String desc, Future<void> Function() fn) async {
|
|
|
|
|
if (pairedLockId.value == null) return;
|
|
|
|
|
_log_('$desc...');
|
|
|
|
|
setState(() => _loading = true);
|
|
|
|
|
try {
|
|
|
|
|
await fn();
|
|
|
|
|
_log_('${S.isEn ? "Success" : "成功"}');
|
|
|
|
|
} catch (e) {
|
|
|
|
|
_log_('${S.isEn ? "Failed" : "失败"}: $e');
|
|
|
|
|
} finally {
|
|
|
|
|
setState(() => _loading = false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-19 16:17:25 +08:00
|
|
|
Future<void> _deleteLock() async {
|
|
|
|
|
final id = pairedLockId.value;
|
|
|
|
|
if (id == null || _loading) return;
|
|
|
|
|
final confirmed = await showDialog<bool>(
|
|
|
|
|
context: context,
|
|
|
|
|
builder: (dialogContext) => AlertDialog(
|
|
|
|
|
title: Text(S.confirmDeleteLockTitle),
|
|
|
|
|
content: Text(S.confirmDeleteLockMessage),
|
|
|
|
|
actions: [
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: () => Navigator.of(dialogContext).pop(false),
|
|
|
|
|
child: Text(S.isEn ? 'Cancel' : '取消'),
|
|
|
|
|
),
|
|
|
|
|
ElevatedButton(
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
|
foregroundColor: Colors.white,
|
|
|
|
|
),
|
|
|
|
|
onPressed: () => Navigator.of(dialogContext).pop(true),
|
|
|
|
|
child: Text(S.btnDeleteLock),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
if (confirmed != true || !mounted) return;
|
|
|
|
|
|
|
|
|
|
final label = S.btnDeleteLock;
|
|
|
|
|
_log_('$label...');
|
|
|
|
|
setState(() => _loading = true);
|
|
|
|
|
try {
|
|
|
|
|
await StarCloudClient.instance.device.resetLock(lockId: id);
|
|
|
|
|
wifiConfiguredLockId.value = null;
|
|
|
|
|
pairedLockId.value = null;
|
|
|
|
|
pairedLock.value = null;
|
|
|
|
|
final result = S.isEn ? "Success" : "成功";
|
|
|
|
|
_log_('$result: $label');
|
|
|
|
|
} catch (e) {
|
|
|
|
|
final result = S.isEn ? "Failed" : "失败";
|
|
|
|
|
_log_('$result: $e');
|
|
|
|
|
} finally {
|
|
|
|
|
if (mounted) setState(() => _loading = false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-20 09:25:05 +08:00
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
// 监听语言切换通知
|
|
|
|
|
return ValueListenableBuilder<bool>(
|
|
|
|
|
valueListenable: S.langNotifier,
|
|
|
|
|
builder: (context, isEn, _) {
|
|
|
|
|
return Padding(
|
|
|
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
|
child: ValueListenableBuilder<int?>(
|
|
|
|
|
valueListenable: pairedLockId,
|
|
|
|
|
builder: (context, id, _) {
|
|
|
|
|
return Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
|
|
|
children: [
|
|
|
|
|
Text('${S.lockIdLabel}: ${id ?? S.notPaired}',
|
|
|
|
|
style: const TextStyle(fontWeight: FontWeight.bold)),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Expanded(
|
|
|
|
|
child: ActionButton(
|
|
|
|
|
label: S.btnOpen,
|
|
|
|
|
icon: Icons.lock_open,
|
|
|
|
|
color: Colors.green,
|
|
|
|
|
loading: _loading || id == null,
|
|
|
|
|
onTap: () => _run(S.btnOpen,
|
|
|
|
|
() => StarCloudClient.instance.device.openLock(lockId: id!)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(width: 8),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: ActionButton(
|
|
|
|
|
label: S.btnClose,
|
|
|
|
|
icon: Icons.lock,
|
|
|
|
|
color: Colors.orange,
|
|
|
|
|
loading: _loading || id == null,
|
|
|
|
|
onTap: () => _run(S.btnClose,
|
|
|
|
|
() => StarCloudClient.instance.device.closeLock(lockId: id!)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
2026-10-19 16:17:25 +08:00
|
|
|
const SizedBox(height: 12),
|
|
|
|
|
ElevatedButton.icon(
|
|
|
|
|
onPressed: id == null || _loading ? null : _deleteLock,
|
|
|
|
|
icon: const Icon(Icons.delete_forever),
|
|
|
|
|
label: Text(S.btnDeleteLock),
|
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
|
foregroundColor: Colors.red,
|
|
|
|
|
side: const BorderSide(color: Colors.red),
|
|
|
|
|
),
|
|
|
|
|
),
|
2026-08-20 09:25:05 +08:00
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
LogArea(log: _log),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|