2023-08-03 19:23:33 +02:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
import 'package:nc_photos/account.dart';
|
|
|
|
import 'package:nc_photos/app_localizations.dart';
|
|
|
|
import 'package:nc_photos/entity/file.dart';
|
2023-09-03 11:12:57 +02:00
|
|
|
import 'package:nc_photos/entity/file_descriptor.dart';
|
2023-08-03 19:23:33 +02:00
|
|
|
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
2023-09-03 11:12:57 +02:00
|
|
|
import 'package:nc_photos/exception.dart';
|
2023-08-03 19:23:33 +02:00
|
|
|
import 'package:nc_photos/k.dart' as k;
|
2023-09-03 11:12:57 +02:00
|
|
|
import 'package:nc_photos/platform/download.dart';
|
2023-08-03 19:23:33 +02:00
|
|
|
import 'package:nc_photos/snack_bar_manager.dart';
|
2023-09-03 11:12:57 +02:00
|
|
|
import 'package:nc_photos/stream_util.dart';
|
2023-08-03 19:23:33 +02:00
|
|
|
import 'package:nc_photos/use_case/download_file.dart';
|
|
|
|
import 'package:nc_photos/use_case/download_preview.dart';
|
2023-09-03 11:12:57 +02:00
|
|
|
import 'package:nc_photos/widget/download_progress_dialog.dart';
|
2023-08-03 19:23:33 +02:00
|
|
|
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
|
|
|
|
import 'package:np_codegen/np_codegen.dart';
|
2023-08-25 19:31:06 +02:00
|
|
|
import 'package:np_collection/np_collection.dart';
|
2023-09-03 11:12:57 +02:00
|
|
|
import 'package:rxdart/rxdart.dart';
|
2023-08-03 19:23:33 +02:00
|
|
|
|
|
|
|
part 'internal_download_handler.g.dart';
|
|
|
|
|
|
|
|
/// Download file to internal dir
|
|
|
|
@npLog
|
|
|
|
class InternalDownloadHandler {
|
|
|
|
const InternalDownloadHandler(this.account);
|
|
|
|
|
|
|
|
Future<Map<File, dynamic>> downloadPreviews(
|
|
|
|
BuildContext context, List<File> files) async {
|
2023-09-03 11:12:57 +02:00
|
|
|
if (files.isEmpty) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
final controller =
|
|
|
|
BehaviorSubject.seeded(const _DownloadProgress(current: 0));
|
|
|
|
bool shouldRun = true;
|
|
|
|
Download? download;
|
2023-08-03 19:23:33 +02:00
|
|
|
unawaited(
|
|
|
|
showDialog(
|
|
|
|
context: context,
|
2023-09-03 11:12:57 +02:00
|
|
|
builder: (context) => ValueStreamBuilder<_DownloadProgress>(
|
2023-08-03 19:23:33 +02:00
|
|
|
stream: controller.stream,
|
2023-09-03 11:12:57 +02:00
|
|
|
builder: (_, snapshot) => DownloadProgressDialog(
|
|
|
|
max: files.length,
|
|
|
|
current: snapshot.requireData.current,
|
|
|
|
progress: snapshot.requireData.progress,
|
|
|
|
label: files[snapshot.requireData.current].filename,
|
|
|
|
onCancel: () {
|
|
|
|
download?.cancel();
|
|
|
|
shouldRun = false;
|
|
|
|
},
|
2023-08-03 19:23:33 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
try {
|
|
|
|
final results = <MapEntry<File, dynamic>>[];
|
2024-06-30 21:00:11 +02:00
|
|
|
for (final (:i, e: f) in files.withIndex()) {
|
2023-09-03 11:12:57 +02:00
|
|
|
controller.add(_DownloadProgress(current: i));
|
2023-08-03 19:23:33 +02:00
|
|
|
try {
|
2023-09-03 11:12:57 +02:00
|
|
|
final dynamic result;
|
2023-08-03 19:23:33 +02:00
|
|
|
if (file_util.isSupportedImageFormat(f) &&
|
|
|
|
f.contentType != "image/gif") {
|
2023-09-03 11:12:57 +02:00
|
|
|
result = await DownloadPreview()(account, f);
|
2023-08-03 19:23:33 +02:00
|
|
|
} else {
|
2023-09-03 11:12:57 +02:00
|
|
|
download = DownloadFile().build(
|
|
|
|
account,
|
|
|
|
f,
|
|
|
|
shouldNotify: false,
|
|
|
|
onProgress: (progress) {
|
|
|
|
controller
|
|
|
|
.add(_DownloadProgress(current: i, progress: progress));
|
|
|
|
},
|
|
|
|
);
|
|
|
|
result = await download();
|
|
|
|
}
|
|
|
|
if (!shouldRun) {
|
|
|
|
throw const JobCanceledException();
|
2023-08-03 19:23:33 +02:00
|
|
|
}
|
2023-09-03 11:12:57 +02:00
|
|
|
results.add(MapEntry(f, result));
|
2023-08-03 19:23:33 +02:00
|
|
|
} catch (e, stacktrace) {
|
|
|
|
_log.shout(
|
|
|
|
"[downloadPreviews] Failed while DownloadPreview", e, stacktrace);
|
2024-06-19 08:58:08 +02:00
|
|
|
SnackBarManager().showSnackBarForException(e);
|
2023-08-03 19:23:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return results.toMap();
|
|
|
|
} finally {
|
|
|
|
// dismiss the dialog
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Map<File, dynamic>> downloadFiles(
|
|
|
|
BuildContext context, List<File> files) async {
|
2023-09-03 11:12:57 +02:00
|
|
|
if (files.isEmpty) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
final controller =
|
|
|
|
BehaviorSubject.seeded(const _DownloadProgress(current: 0));
|
|
|
|
bool shouldRun = true;
|
|
|
|
Download? download;
|
2023-08-03 19:23:33 +02:00
|
|
|
unawaited(
|
|
|
|
showDialog(
|
|
|
|
context: context,
|
2023-09-03 11:12:57 +02:00
|
|
|
builder: (context) => ValueStreamBuilder<_DownloadProgress>(
|
2023-08-03 19:23:33 +02:00
|
|
|
stream: controller.stream,
|
2023-09-03 11:12:57 +02:00
|
|
|
builder: (_, snapshot) => DownloadProgressDialog(
|
|
|
|
max: files.length,
|
|
|
|
current: snapshot.requireData.current,
|
|
|
|
progress: snapshot.requireData.progress,
|
|
|
|
label: files[snapshot.requireData.current].filename,
|
|
|
|
onCancel: () {
|
|
|
|
download?.cancel();
|
|
|
|
shouldRun = false;
|
|
|
|
},
|
2023-08-03 19:23:33 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
try {
|
|
|
|
final results = <MapEntry<File, dynamic>>[];
|
2024-06-30 21:00:11 +02:00
|
|
|
for (final (:i, e: f) in files.withIndex()) {
|
2023-09-03 11:12:57 +02:00
|
|
|
controller.add(_DownloadProgress(current: i));
|
2023-08-03 19:23:33 +02:00
|
|
|
try {
|
2023-09-03 11:12:57 +02:00
|
|
|
download = DownloadFile().build(
|
|
|
|
account,
|
|
|
|
f,
|
|
|
|
shouldNotify: false,
|
|
|
|
onProgress: (progress) {
|
|
|
|
controller.add(_DownloadProgress(current: i, progress: progress));
|
|
|
|
},
|
|
|
|
);
|
|
|
|
final result = await download();
|
|
|
|
if (!shouldRun) {
|
|
|
|
throw const JobCanceledException();
|
|
|
|
}
|
|
|
|
results.add(MapEntry(f, result));
|
2023-08-03 19:23:33 +02:00
|
|
|
} on PermissionException catch (_) {
|
|
|
|
_log.warning("[downloadFiles] Permission not granted");
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(L10n.global().errorNoStoragePermission),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
rethrow;
|
2023-09-03 11:12:57 +02:00
|
|
|
} on JobCanceledException catch (_) {
|
|
|
|
_log.info("[downloadFiles] Job canceled");
|
|
|
|
return {};
|
2023-08-03 19:23:33 +02:00
|
|
|
} catch (e, stacktrace) {
|
|
|
|
_log.shout(
|
|
|
|
"[downloadFiles] Failed while downloadFile", e, stacktrace);
|
2024-06-19 08:58:08 +02:00
|
|
|
SnackBarManager().showSnackBarForException(e);
|
2023-08-03 19:23:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return results.toMap();
|
|
|
|
} finally {
|
|
|
|
// dismiss the dialog
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
final Account account;
|
|
|
|
}
|
2023-09-03 11:12:57 +02:00
|
|
|
|
|
|
|
class _DownloadProgress {
|
|
|
|
const _DownloadProgress({
|
|
|
|
required this.current,
|
|
|
|
this.progress,
|
|
|
|
});
|
|
|
|
|
|
|
|
final int current;
|
|
|
|
final double? progress;
|
|
|
|
}
|