feat(mobile): UI-01 upload center, capture and auxiliary pages
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -20,31 +20,29 @@ import 'providers.dart';
|
||||
import 'task_state.dart';
|
||||
import 'task_store.dart';
|
||||
|
||||
/// 状态筛选分组(chip → 状态集合;「全部」= 不过滤)。
|
||||
/// 状态筛选分组(UI-01 §4.4:chip → 状态集合;「全部」= 不过滤)。
|
||||
enum QueueStateFilter {
|
||||
all,
|
||||
preparing,
|
||||
queued,
|
||||
uploading,
|
||||
waitingNetwork,
|
||||
failed,
|
||||
inProgress,
|
||||
needsAttention,
|
||||
completed;
|
||||
|
||||
/// 分组对应的状态集合(空 = 不过滤)。
|
||||
///
|
||||
/// - 进行中 = 引擎正在推进的活任务(准备/排队/传输/确认 + 等待网络
|
||||
/// ——网络等待自动恢复,属系统仍在推进的范畴,归入进行中而非需关注);
|
||||
/// - 需关注 = 需要用户动作的失败(准备失败需重新选图、上传失败需重试);
|
||||
/// - 已完成 = 服务端已受理的终态(cancelled 仅在「全部」可见)。
|
||||
Set<UploadTaskState> get states => switch (this) {
|
||||
QueueStateFilter.all => const <UploadTaskState>{},
|
||||
QueueStateFilter.preparing => const <UploadTaskState>{
|
||||
QueueStateFilter.inProgress => const <UploadTaskState>{
|
||||
UploadTaskState.preparing,
|
||||
},
|
||||
QueueStateFilter.queued => const <UploadTaskState>{UploadTaskState.queued},
|
||||
QueueStateFilter.uploading => const <UploadTaskState>{
|
||||
UploadTaskState.queued,
|
||||
UploadTaskState.uploading,
|
||||
UploadTaskState.uploadedConfirming,
|
||||
},
|
||||
QueueStateFilter.waitingNetwork => const <UploadTaskState>{
|
||||
UploadTaskState.waitingNetwork,
|
||||
},
|
||||
QueueStateFilter.failed => const <UploadTaskState>{
|
||||
QueueStateFilter.needsAttention => const <UploadTaskState>{
|
||||
UploadTaskState.preparationFailed,
|
||||
UploadTaskState.retryableFailed,
|
||||
},
|
||||
@@ -237,6 +235,60 @@ final taskCountsProvider =
|
||||
TaskCountsNotifier.new,
|
||||
);
|
||||
|
||||
/// 摘要计数(UI-01 §4.4):**当前筛选范围内**(相册 × 时间)的任务数聚合
|
||||
/// ——与列表同口径,范围标注由队列页摘要卡展示;仍走 SQL 聚合
|
||||
/// ([TaskStore.countsByState]),不整表载入内存。写通知防抖刷新。
|
||||
class QueueSummaryNotifier extends Notifier<Map<UploadTaskState, int>> {
|
||||
StreamSubscription<void>? _changesSub;
|
||||
Timer? _debounce;
|
||||
|
||||
@override
|
||||
Map<UploadTaskState, int> build() {
|
||||
final store = ref.watch(taskStoreProvider);
|
||||
// 会话与筛选变化(相册/时间维度改变摘要口径)都触发重建。
|
||||
ref.watch(sessionAccountProvider);
|
||||
ref.watch(queueFilterProvider);
|
||||
_changesSub?.cancel();
|
||||
_debounce?.cancel();
|
||||
_changesSub = store.changes.listen((_) => _scheduleReload());
|
||||
ref.onDispose(_dispose);
|
||||
Future<void>.microtask(_reload);
|
||||
return <UploadTaskState, int>{
|
||||
for (final state in UploadTaskState.values) state: 0,
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> _reload() async {
|
||||
final account = ref.read(sessionAccountProvider).value;
|
||||
if (account == null) return;
|
||||
final filter = ref.read(queueFilterProvider);
|
||||
final counts = await ref.read(taskStoreProvider).countsByState(
|
||||
account,
|
||||
albumId: filter.albumId,
|
||||
since: filter.time.since(DateTime.now()),
|
||||
);
|
||||
if (ref.mounted) state = counts;
|
||||
}
|
||||
|
||||
void _scheduleReload() {
|
||||
_debounce?.cancel();
|
||||
_debounce = Timer(kQueueRefreshDebounce, _reload);
|
||||
}
|
||||
|
||||
void _dispose() {
|
||||
_changesSub?.cancel();
|
||||
_changesSub = null;
|
||||
_debounce?.cancel();
|
||||
_debounce = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 摘要计数 Provider(当前筛选范围口径;键覆盖全部状态,无任务计 0)。
|
||||
final queueSummaryProvider =
|
||||
NotifierProvider<QueueSummaryNotifier, Map<UploadTaskState, int>>(
|
||||
QueueSummaryNotifier.new,
|
||||
);
|
||||
|
||||
/// 未完成(待传)计数:准备中/待传/上传中/确认中/等待网络之和。
|
||||
int pendingCountOf(Map<UploadTaskState, int> counts) =>
|
||||
counts[UploadTaskState.preparing]! +
|
||||
@@ -250,6 +302,23 @@ int failedCountOf(Map<UploadTaskState, int> counts) =>
|
||||
counts[UploadTaskState.preparationFailed]! +
|
||||
counts[UploadTaskState.retryableFailed]!;
|
||||
|
||||
// ── 摘要行计数(UI-01 §4.4:按任务数统计,不与字节进度混口径)──────────
|
||||
|
||||
/// 摘要「已完成」:服务端已受理的任务数(终态记录,不含已取消)。
|
||||
int completedSummaryOf(Map<UploadTaskState, int> counts) =>
|
||||
counts[UploadTaskState.completed]!;
|
||||
|
||||
/// 摘要「上传中」:正在传输/确认的任务数。
|
||||
int uploadingSummaryOf(Map<UploadTaskState, int> counts) =>
|
||||
counts[UploadTaskState.uploading]! +
|
||||
counts[UploadTaskState.uploadedConfirming]!;
|
||||
|
||||
/// 摘要「等待中」:准备/排队/等待网络的任务数(等待调度,非用户错误)。
|
||||
int waitingSummaryOf(Map<UploadTaskState, int> counts) =>
|
||||
counts[UploadTaskState.preparing]! +
|
||||
counts[UploadTaskState.queued]! +
|
||||
counts[UploadTaskState.waitingNetwork]!;
|
||||
|
||||
/// 「未结束」计数(底部导航「上传」角标,UI-01 §4.1):待传(
|
||||
/// [pendingCountOf])+ 可重试失败——均为引擎待推进或用户需关注的活任务;
|
||||
/// 准备失败/取消/完成不计入。账号隔离由 TaskStore.countsByState 硬守护。
|
||||
|
||||
Reference in New Issue
Block a user