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