import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../programs/models/program.dart'; import '../../programs/models/step.dart'; import '../../programs/services/program_service.dart'; import '../services/runner_interface.dart'; import 'serial_provider.dart'; /// 运行状态枚举 enum RunStatus { idle, // 待机 running, // 运行中 paused, // 已暂停 completed, // 已完成 error, // 错误 } /// 运行状态 class RunState { final RunStatus status; final Program? currentProgram; final List steps; final int currentStepIndex; final int remainingSeconds; final double progress; final String? currentWell; final String? errorMessage; const RunState({ this.status = RunStatus.idle, this.currentProgram, this.steps = const [], this.currentStepIndex = 0, this.remainingSeconds = 0, this.progress = 0, this.currentWell, this.errorMessage, }); RunState copyWith({ RunStatus? status, Program? currentProgram, List? steps, int? currentStepIndex, int? remainingSeconds, double? progress, String? currentWell, String? errorMessage, bool clearProgram = false, bool clearWell = false, bool clearError = false, }) { return RunState( status: status ?? this.status, currentProgram: clearProgram ? null : (currentProgram ?? this.currentProgram), steps: steps ?? this.steps, currentStepIndex: currentStepIndex ?? this.currentStepIndex, remainingSeconds: remainingSeconds ?? this.remainingSeconds, progress: progress ?? this.progress, currentWell: clearWell ? null : (currentWell ?? this.currentWell), errorMessage: clearError ? null : (errorMessage ?? this.errorMessage), ); } /// 获取当前步骤 Step? get currentStep { if (steps.isEmpty || currentStepIndex >= steps.length) return null; return steps[currentStepIndex]; } /// 格式化剩余时间 (HH:MM:SS) String get formattedRemainingTime { final hours = remainingSeconds ~/ 3600; final minutes = (remainingSeconds % 3600) ~/ 60; final seconds = remainingSeconds % 60; return '${hours.toString().padLeft(2, '0')}:' '${minutes.toString().padLeft(2, '0')}:' '${seconds.toString().padLeft(2, '0')}'; } /// 格式化进度百分比 String get formattedProgress { return '${(progress * 100).toStringAsFixed(0)}%'; } } /// 运行状态 Notifier class RunStateNotifier extends StateNotifier { final Runner _runner; final ProgramService _programService; RunStateNotifier(this._runner, this._programService) : super(const RunState()); /// 开始运行程序 Future start(Program program) async { if (state.status == RunStatus.running || state.status == RunStatus.paused) { return; } final steps = await _programService.getStepsByProgramId(program.id!); if (steps.isEmpty) { state = state.copyWith( status: RunStatus.error, errorMessage: '程序步骤为空', ); return; } state = state.copyWith( status: RunStatus.running, currentProgram: program, steps: steps, currentStepIndex: 0, progress: 0, currentWell: steps.first.position, clearError: true, ); _runner.start( program, steps, RunnerCallbacks( onProgress: (stepIndex, remaining, progress, well) { state = state.copyWith( currentStepIndex: stepIndex, remainingSeconds: remaining, progress: progress, currentWell: well, ); }, onComplete: () { state = state.copyWith( status: RunStatus.completed, progress: 1, currentWell: steps.last.position, ); }, onError: (msg) { state = state.copyWith( status: RunStatus.error, errorMessage: msg, ); }, ), ); } /// 暂停运行 void pause() { if (state.status == RunStatus.running) { _runner.pause(); state = state.copyWith(status: RunStatus.paused); } } /// 继续运行 void resume() { if (state.status == RunStatus.paused) { _runner.resume(); state = state.copyWith(status: RunStatus.running); } } /// 停止运行 void stop() { if (state.status == RunStatus.running || state.status == RunStatus.paused) { _runner.stop(); } state = const RunState(status: RunStatus.idle); } /// 重置状态 void reset() => stop(); } /// ProgramService Provider final programServiceProvider = Provider((ref) { return ProgramService.instance; }); /// 运行状态 Provider final runStateProvider = StateNotifierProvider((ref) { final runner = ref.watch(runnerProvider); final programService = ref.watch(programServiceProvider); return RunStateNotifier(runner, programService); }); /// 是否正在运行 Provider final isRunningProvider = Provider((ref) { final status = ref.watch(runStateProvider).status; return status == RunStatus.running; }); /// 是否已暂停 Provider final isPausedProvider = Provider((ref) { final status = ref.watch(runStateProvider).status; return status == RunStatus.paused; });