chore(project): 初始化项目基础配置文件

- 添加 CodeGraph、Android 和通用 gitignore 配置
- 创建项目元数据文件跟踪 Flutter 项目属性
- 添加 Codex AI 指导文档 AGENTS.md 说明项目架构
- 配置代码分析选项 analysis_options.yaml
- 设置 Android 应用清单权限和 Kiosk 模式配置
- 实现中英文国际化支持 AppLocalizations
- 配置 GoRouter 应用路由导航
- 创建明亮工业控制风格的主题配置 AppTheme
This commit is contained in:
Developer
2026-06-04 11:19:44 +08:00
commit 5d28bf631b
85 changed files with 21423 additions and 0 deletions

View 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;
});