feat: 新增设备绑定、扫码与联系人管理功能

This commit is contained in:
TongTongStudio
2026-08-21 17:12:17 +08:00
parent 06cdc77172
commit 98de1e1132
49 changed files with 5699 additions and 204 deletions

View File

@@ -0,0 +1,96 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ttstd_family_care/core/network/error_message.dart';
import 'package:ttstd_family_care/features/device/data/device_providers.dart';
/// 设备管理(绑定 / 解绑)操作状态。
///
/// [submitting] 表示正在请求中,用于禁用按钮并展示 loading
/// [alert] 为一次性提示文案UI 展示后必须调用 [DeviceManageController.consumeAlert] 消费;
/// [lastSuccess] 标记最近一次操作是否成功,供 UI 决定是否关闭页面。
class DeviceManageState {
const DeviceManageState({
this.submitting = false,
this.alert,
this.lastSuccess = false,
});
final bool submitting;
final String? alert;
final bool lastSuccess;
DeviceManageState copyWith({
bool? submitting,
String? alert,
bool? lastSuccess,
}) =>
DeviceManageState(
submitting: submitting ?? this.submitting,
alert: alert,
lastSuccess: lastSuccess ?? this.lastSuccess,
);
}
/// 设备绑定 / 解绑控制器。
///
/// 页面级控制器,**不使用** keepAlive随页面销毁自动释放见 AGENTS.md §4
/// 操作成功后主动 `ref.invalidate(myDevicesProvider)` 刷新绑定列表。
class DeviceManageController extends Notifier<DeviceManageState> {
@override
DeviceManageState build() => const DeviceManageState();
/// 绑定设备。[sn] 为设备序列号,[remark] 为可选备注名。
///
/// SN 为空等输入校验由 UI 层负责(便于使用本地化文案),此处只做兜底裁剪。
/// 返回是否绑定成功。
Future<bool> bind(String sn, {String? remark}) =>
_run(() => ref.read(deviceRepositoryProvider).bindDevice(
sn.trim(),
remark: remark?.trim(),
));
/// 解绑设备。返回是否解绑成功。
Future<bool> unbind(String sn) =>
_run(() => ref.read(deviceRepositoryProvider).unbindDevice(sn));
/// 消费一次性提示,避免重复弹窗。
void consumeAlert() {
if (state.alert != null) {
state = state.copyWith(alert: null, lastSuccess: state.lastSuccess);
}
}
/// 统一执行绑定/解绑请求:处理 submitting 开关、错误文案与列表刷新。
Future<bool> _run(Future<String?> Function() action) async {
if (state.submitting) return false;
state = state.copyWith(submitting: true, alert: null, lastSuccess: false);
try {
final error = await action();
if (error != null) {
state = state.copyWith(
submitting: false,
alert: error,
lastSuccess: false,
);
return false;
}
// 绑定关系变化,刷新已绑定设备列表。
ref.invalidate(myDevicesProvider);
state = state.copyWith(submitting: false, lastSuccess: true);
return true;
} catch (e) {
// 统一文案映射,禁止直接 toString()(见 AGENTS.md §12
state = state.copyWith(
submitting: false,
alert: userMessageOf(e),
lastSuccess: false,
);
return false;
}
}
}
/// 设备管理控制器 Provider页面级不 keepAlive
final deviceManageControllerProvider =
NotifierProvider<DeviceManageController, DeviceManageState>(
DeviceManageController.new,
);