import 'dart:async'; import '../../l10n/tr.dart'; /// 무거운 작업 (AI 자막 · 자막 번역 · MKV 만들기 - CPU · 메모리를 많이 써서 하나씩) 의 대기열. /// 약속: [enqueue] 는 작업 중이면 대기열에 넣고 아니면 바로 실행한다. 끝나면 다음 작업을 이어서 실행. /// 돌려주는 Future 는 그 작업이 실제로 끝날 때 (대기 중에 [cancelPending] 으로 빠지면 바로) 끝난다. /// 상태가 바뀔 때마다 [onChanged], 대기열에 넣을 때 [log]. class JobQueue { final void Function() onChanged; final void Function(String msg) log; JobQueue({required this.onChanged, required this.log}); /// 작업 중인지 (화면 시험은 직접 정하기도 한다) bool busy = false; /// 실행 중인 작업 이름 (없으면 null) String? current; /// 대기 중인 작업 이름 (차례대로) final List pending = []; final List<(Future Function(), Completer)> _runs = []; Future enqueue(String label, Future Function() job) { if (busy) { final done = Completer(); pending.add(label); _runs.add((job, done)); log(trf('대기열에 추가: {0} (대기 {1}개)', [label, pending.length])); onChanged(); return done.future; } return _run(label, job); } Future _run(String label, Future Function() job) async { busy = true; current = label; onChanged(); try { await job(); } finally { busy = false; current = null; onChanged(); if (_runs.isNotEmpty) { final (next, done) = _runs.removeAt(0); final nextLabel = pending.removeAt(0); unawaited(_run(nextLabel, next).then((_) => done.complete(), onError: done.completeError)); } } } /// 대기 중인 작업을 모두 뺀다 (지금 작업은 그대로). 뺀 수 int cancelPending() { final n = pending.length; pending.clear(); for (final (_, done) in _runs) { done.complete(); } _runs.clear(); return n; } }