added support for simultan downloads in files and talk, support for background downloads, enhanced loading in files with retry

This commit is contained in:
2026-07-06 15:43:17 +02:00
parent 614ab159af
commit 124b1a5177
34 changed files with 1866 additions and 409 deletions
+78
View File
@@ -0,0 +1,78 @@
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);
/// 0100, 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<DownloadStatus> 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();
}