Files
ttstd_family_care/lib/features/device/presentation/device_bind_page.dart
2026-08-21 17:12:17 +08:00

142 lines
4.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:cupertino_ui/cupertino_ui.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../core/widgets/feature_ui.dart';
import '../../../core/widgets/settings_ui.dart';
import '../../../l10n/app_localizations.dart';
import 'device_manage_controller.dart';
/// 绑定设备页(手动输入 SN
///
/// 提供 SN / 备注名输入、「确认绑定」与「扫码绑定」两个入口。
/// 扫码入口跳转 `/device/scan`,扫描结果回填到 SN 输入框。
class DeviceBindPage extends ConsumerStatefulWidget {
const DeviceBindPage({super.key, this.initialSn});
/// 由扫码页回传的初始 SN可选
final String? initialSn;
@override
ConsumerState<DeviceBindPage> createState() => _DeviceBindPageState();
}
class _DeviceBindPageState extends ConsumerState<DeviceBindPage> {
late final TextEditingController _snController;
final TextEditingController _remarkController = TextEditingController();
@override
void initState() {
super.initState();
_snController = TextEditingController(text: widget.initialSn ?? '');
}
@override
void dispose() {
_snController.dispose();
_remarkController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final action = ref.watch(deviceManageControllerProvider);
// 一次性错误提示:展示后立即消费。
ref.listen<DeviceManageState>(deviceManageControllerProvider, (prev, next) {
final alert = next.alert;
if (alert == null) return;
ref.read(deviceManageControllerProvider.notifier).consumeAlert();
AppDialogs.alert(context, message: alert, confirmText: l10n.commonConfirm);
});
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(l10n.deviceBindTitle),
leading: CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.back),
onPressed: () => context.pop(),
),
),
child: SafeArea(
child: ListView(
padding: const EdgeInsets.only(top: 8, bottom: 24),
children: [
CardBox(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(
children: [
LabeledField(
label: l10n.deviceBindSnLabel,
controller: _snController,
placeholder: l10n.deviceBindSnHint,
keyboardType: TextInputType.text,
),
LabeledField(
label: l10n.deviceBindRemarkLabel,
controller: _remarkController,
placeholder: l10n.deviceBindRemarkHint,
maxLength: 20,
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(22, 6, 22, 2),
child: Text(
l10n.deviceBindTip,
style: const TextStyle(fontSize: 12, color: AppColors.sub, height: 1.5),
),
),
const SizedBox(height: 6),
PrimaryButton(
text: l10n.deviceBindConfirm,
loading: action.submitting,
onPressed: () => _submit(l10n),
),
SecondaryButton(
text: l10n.deviceBindScan,
icon: CupertinoIcons.qrcode_viewfinder,
onPressed: action.submitting ? null : () => _openScanner(l10n),
),
],
),
),
);
}
/// 校验 SN 后提交绑定,成功则提示并返回上一页。
Future<void> _submit(AppLocalizations l10n) async {
final sn = _snController.text.trim();
if (sn.isEmpty) {
await AppDialogs.alert(
context,
message: l10n.deviceBindSnEmpty,
confirmText: l10n.commonConfirm,
);
return;
}
final ok = await ref.read(deviceManageControllerProvider.notifier).bind(
sn,
remark: _remarkController.text,
);
if (!ok || !mounted) return;
await AppDialogs.alert(
context,
message: l10n.deviceBindSuccess,
confirmText: l10n.commonConfirm,
);
if (mounted) context.pop();
}
/// 打开扫码页;扫描成功后把 SN 回填输入框。
Future<void> _openScanner(AppLocalizations l10n) async {
final code = await context.push<String>('/device/scan');
if (code == null || code.isEmpty || !mounted) return;
setState(() => _snController.text = code);
}
}