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

97 lines
3.2 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: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,
);