import 'package:flutter/foundation.dart'; import '../../share_intent/remote_file_ref.dart'; /// Snapshot of a single download's lifecycle. UI widgets rebuild whenever the /// owning [DownloadJob.status] notifier emits a new instance. sealed class DownloadStatus { const DownloadStatus(); } class DownloadInProgress extends DownloadStatus { const DownloadInProgress(this.percent); /// 0–100, or a value `<= 0` while the total size is still unknown /// (indeterminate progress). final double percent; } class DownloadDone extends DownloadStatus { const DownloadDone(this.localPath); final String localPath; } class DownloadCancelled extends DownloadStatus { const DownloadCancelled(); } class DownloadFailed extends DownloadStatus { const DownloadFailed(this.message); final String message; } /// Tracks a single in-flight or finished download. Survives widget dispose so /// that re-entering a screen (or opening the downloads overview) reattaches to /// the same job. Kept engine-agnostic on purpose — the native /// `background_downloader` task lives entirely inside [DownloadManager]. class DownloadJob { DownloadJob({ required this.remotePath, required this.name, this.remoteFile, }); final String remotePath; final String name; /// Server-side reference so the viewer can offer "An Chat senden" / /// "In Cloud speichern" for downloads triggered from Files or Talk. final RemoteFileRef? remoteFile; /// Native task id, set by [DownloadManager] once the task is enqueued. String? taskId; /// True once the finished file has been opened (auto-open or from the /// overview). Opened jobs drop out of the downloads tray. bool opened = false; final ValueNotifier status = ValueNotifier( const DownloadInProgress(0), ); bool get isFinished => status.value is DownloadDone || status.value is DownloadFailed || status.value is DownloadCancelled; bool get isDone => status.value is DownloadDone; bool get isFailed => status.value is DownloadFailed; bool get isCancelled => status.value is DownloadCancelled; /// Local file path once finished, else null. String? get localPath { final value = status.value; return value is DownloadDone ? value.localPath : null; } void dispose() => status.dispose(); }