nc-photos/app/lib/internal_download_handler.dart

184 lines
5.8 KiB
Dart
Raw Normal View History

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';
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';
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
2023-09-03 11:12:57 +02:00
import 'package:nc_photos/platform/download.dart';
import 'package:nc_photos/snack_bar_manager.dart';
2023-09-03 11:12:57 +02:00
import 'package:nc_photos/stream_util.dart';
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';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_collection/np_collection.dart';
2023-09-03 11:12:57 +02:00
import 'package:rxdart/rxdart.dart';
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;
unawaited(
showDialog(
context: context,
2023-09-03 11:12:57 +02:00
builder: (context) => ValueStreamBuilder<_DownloadProgress>(
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;
},
),
),
),
);
try {
final results = <MapEntry<File, dynamic>>[];
for (final pair in files.withIndex()) {
final i = pair.item1, f = pair.item2;
2023-09-03 11:12:57 +02:00
controller.add(_DownloadProgress(current: i));
try {
2023-09-03 11:12:57 +02:00
final dynamic result;
if (file_util.isSupportedImageFormat(f) &&
f.contentType != "image/gif") {
2023-09-03 11:12:57 +02:00
result = await DownloadPreview()(account, f);
} 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-09-03 11:12:57 +02:00
results.add(MapEntry(f, result));
} catch (e, stacktrace) {
_log.shout(
"[downloadPreviews] Failed while DownloadPreview", e, stacktrace);
SnackBarManager().showSnackBar(SnackBar(
content: Text(exception_util.toUserString(e)),
duration: k.snackBarDurationNormal,
));
}
}
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;
unawaited(
showDialog(
context: context,
2023-09-03 11:12:57 +02:00
builder: (context) => ValueStreamBuilder<_DownloadProgress>(
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;
},
),
),
),
);
try {
final results = <MapEntry<File, dynamic>>[];
for (final pair in files.withIndex()) {
final i = pair.item1, f = pair.item2;
2023-09-03 11:12:57 +02:00
controller.add(_DownloadProgress(current: i));
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));
} 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 {};
} catch (e, stacktrace) {
_log.shout(
"[downloadFiles] Failed while downloadFile", e, stacktrace);
SnackBarManager().showSnackBar(SnackBar(
content: Text(exception_util.toUserString(e)),
duration: k.snackBarDurationNormal,
));
}
}
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;
}