chore(project): 初始化项目基础配置文件
- 添加 CodeGraph、Android 和通用 gitignore 配置 - 创建项目元数据文件跟踪 Flutter 项目属性 - 添加 Codex AI 指导文档 AGENTS.md 说明项目架构 - 配置代码分析选项 analysis_options.yaml - 设置 Android 应用清单权限和 Kiosk 模式配置 - 实现中英文国际化支持 AppLocalizations - 配置 GoRouter 应用路由导航 - 创建明亮工业控制风格的主题配置 AppTheme
This commit is contained in:
161
lib/features/program_detail/providers/steps_provider.dart
Normal file
161
lib/features/program_detail/providers/steps_provider.dart
Normal file
@@ -0,0 +1,161 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../programs/models/step.dart';
|
||||
import '../../programs/services/program_service.dart';
|
||||
|
||||
/// 步骤状态
|
||||
class StepsState {
|
||||
final List<Step> steps;
|
||||
final int? selectedStepId;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
const StepsState({
|
||||
this.steps = const [],
|
||||
this.selectedStepId,
|
||||
this.isLoading = false,
|
||||
this.error,
|
||||
});
|
||||
|
||||
StepsState copyWith({
|
||||
List<Step>? steps,
|
||||
int? selectedStepId,
|
||||
bool? isLoading,
|
||||
String? error,
|
||||
bool clearSelection = false,
|
||||
bool clearError = false,
|
||||
}) {
|
||||
return StepsState(
|
||||
steps: steps ?? this.steps,
|
||||
selectedStepId: clearSelection ? null : (selectedStepId ?? this.selectedStepId),
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
error: clearError ? null : (error ?? this.error),
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取选中的步骤
|
||||
Step? get selectedStep {
|
||||
if (selectedStepId == null) return null;
|
||||
return steps.where((s) => s.id == selectedStepId).firstOrNull;
|
||||
}
|
||||
}
|
||||
|
||||
/// 步骤 Notifier
|
||||
class StepsNotifier extends StateNotifier<StepsState> {
|
||||
final ProgramService _service;
|
||||
final int programId;
|
||||
|
||||
StepsNotifier(this._service, this.programId) : super(const StepsState()) {
|
||||
loadSteps();
|
||||
}
|
||||
|
||||
/// 加载步骤
|
||||
Future<void> loadSteps() async {
|
||||
state = state.copyWith(isLoading: true, clearError: true);
|
||||
try {
|
||||
final steps = await _service.getStepsByProgramId(programId);
|
||||
state = state.copyWith(steps: steps, isLoading: false);
|
||||
} catch (e) {
|
||||
state = state.copyWith(isLoading: false, error: e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/// 选择步骤
|
||||
void selectStep(int? stepId) {
|
||||
state = state.copyWith(selectedStepId: stepId);
|
||||
}
|
||||
|
||||
/// 清除选择
|
||||
void clearSelection() {
|
||||
state = state.copyWith(clearSelection: true);
|
||||
}
|
||||
|
||||
/// 添加步骤
|
||||
Future<bool> addStep(Step step) async {
|
||||
try {
|
||||
await _service.addStep(step);
|
||||
await loadSteps();
|
||||
return true;
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新步骤
|
||||
Future<bool> updateStep(Step step) async {
|
||||
if (step.id == null) return false;
|
||||
try {
|
||||
await _service.updateStep(step);
|
||||
await loadSteps();
|
||||
return true;
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 删除步骤
|
||||
Future<bool> deleteStep(int stepId) async {
|
||||
try {
|
||||
await _service.deleteStep(stepId);
|
||||
if (state.selectedStepId == stepId) {
|
||||
state = state.copyWith(clearSelection: true);
|
||||
}
|
||||
await loadSteps();
|
||||
return true;
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 批量删除步骤
|
||||
Future<bool> deleteSteps(List<int> stepIds) async {
|
||||
try {
|
||||
await _service.deleteSteps(stepIds);
|
||||
if (stepIds.contains(state.selectedStepId)) {
|
||||
state = state.copyWith(clearSelection: true);
|
||||
}
|
||||
await loadSteps();
|
||||
return true;
|
||||
} catch (e) {
|
||||
state = state.copyWith(error: e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 重新排序步骤
|
||||
Future<void> reorderSteps(int oldIndex, int newIndex) async {
|
||||
final steps = List<Step>.from(state.steps);
|
||||
final step = steps.removeAt(oldIndex);
|
||||
steps.insert(newIndex, step);
|
||||
|
||||
// 更新 step_no
|
||||
for (int i = 0; i < steps.length; i++) {
|
||||
steps[i] = steps[i].copyWith(stepNo: i + 1);
|
||||
}
|
||||
|
||||
state = state.copyWith(steps: steps);
|
||||
|
||||
// 持久化排序
|
||||
await _service.reorderSteps(programId, steps.map((s) => s.id!).toList());
|
||||
}
|
||||
}
|
||||
|
||||
/// 程序服务 Provider
|
||||
final programServiceProvider = Provider<ProgramService>((ref) {
|
||||
return ProgramService.instance;
|
||||
});
|
||||
|
||||
/// 步骤 Provider(按程序ID)
|
||||
final stepsProvider = StateNotifierProvider.family<StepsNotifier, StepsState, int>(
|
||||
(ref, programId) {
|
||||
final service = ref.watch(programServiceProvider);
|
||||
return StepsNotifier(service, programId);
|
||||
},
|
||||
);
|
||||
|
||||
/// 选中的步骤 Provider
|
||||
final selectedStepProvider = Provider.family<Step?, int>((ref, programId) {
|
||||
return ref.watch(stepsProvider(programId)).selectedStep;
|
||||
});
|
||||
Reference in New Issue
Block a user