2021-10-02 11:12:54 +02:00
|
|
|
import 'dart:async';
|
|
|
|
|
2021-09-28 22:56:44 +02:00
|
|
|
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';
|
|
|
|
import 'package:nc_photos/exception.dart';
|
|
|
|
import 'package:nc_photos/exception_util.dart' as exception_util;
|
2021-10-02 11:12:54 +02:00
|
|
|
import 'package:nc_photos/iterable_extension.dart';
|
2021-09-28 22:56:44 +02:00
|
|
|
import 'package:nc_photos/k.dart' as k;
|
2021-10-02 11:12:54 +02:00
|
|
|
import 'package:nc_photos/mobile/android/download.dart';
|
2021-09-28 22:56:44 +02:00
|
|
|
import 'package:nc_photos/mobile/notification.dart';
|
|
|
|
import 'package:nc_photos/platform/k.dart' as platform_k;
|
|
|
|
import 'package:nc_photos/snack_bar_manager.dart';
|
|
|
|
import 'package:nc_photos/use_case/download_file.dart';
|
|
|
|
import 'package:tuple/tuple.dart';
|
|
|
|
|
|
|
|
class DownloadHandler {
|
2021-09-29 16:34:56 +02:00
|
|
|
Future<void> downloadFiles(
|
|
|
|
Account account,
|
|
|
|
List<File> files, {
|
|
|
|
String? parentDir,
|
2021-10-02 11:12:54 +02:00
|
|
|
}) {
|
|
|
|
final _DownloadHandlerBase handler;
|
|
|
|
if (platform_k.isAndroid) {
|
|
|
|
handler = _DownlaodHandlerAndroid();
|
|
|
|
} else {
|
|
|
|
handler = _DownloadHandlerWeb();
|
|
|
|
}
|
|
|
|
return handler.downloadFiles(
|
|
|
|
account,
|
|
|
|
files,
|
|
|
|
parentDir: parentDir,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract class _DownloadHandlerBase {
|
|
|
|
Future<void> downloadFiles(
|
|
|
|
Account account,
|
|
|
|
List<File> files, {
|
|
|
|
String? parentDir,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
class _DownlaodHandlerAndroid extends _DownloadHandlerBase {
|
|
|
|
@override
|
|
|
|
downloadFiles(
|
|
|
|
Account account,
|
|
|
|
List<File> files, {
|
|
|
|
String? parentDir,
|
|
|
|
}) async {
|
|
|
|
_log.info("[downloadFiles] Downloading ${files.length} file");
|
|
|
|
final notif = AndroidDownloadProgressNotification(
|
|
|
|
0,
|
|
|
|
files.length,
|
|
|
|
currentItemTitle: files.firstOrNull?.filename,
|
|
|
|
);
|
|
|
|
await notif.notify();
|
|
|
|
|
|
|
|
final successes = <Tuple2<File, dynamic>>[];
|
|
|
|
StreamSubscription<DownloadCancelEvent>? subscription;
|
|
|
|
try {
|
|
|
|
bool isCancel = false;
|
|
|
|
subscription = DownloadEvent.listenDownloadCancel()
|
|
|
|
..onData((data) {
|
|
|
|
if (data.notificationId == notif.notificationId) {
|
|
|
|
isCancel = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
for (final f in files) {
|
|
|
|
if (isCancel == true) {
|
|
|
|
_log.info("[downloadFiles] User canceled remaining files");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
notif.update(
|
|
|
|
count++,
|
|
|
|
currentItemTitle: f.filename,
|
|
|
|
);
|
|
|
|
|
|
|
|
StreamSubscription<DownloadCancelEvent>? itemSubscription;
|
|
|
|
try {
|
|
|
|
final download = DownloadFile().build(
|
|
|
|
account,
|
|
|
|
f,
|
|
|
|
parentDir: parentDir,
|
|
|
|
shouldNotify: false,
|
|
|
|
);
|
|
|
|
itemSubscription = DownloadEvent.listenDownloadCancel()
|
|
|
|
..onData((data) {
|
|
|
|
if (data.notificationId == notif.notificationId) {
|
|
|
|
_log.info("[downloadFiles] Cancel requested");
|
|
|
|
download.cancel();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
final result = await download();
|
|
|
|
successes.add(Tuple2(f, result));
|
|
|
|
} on PermissionException catch (_) {
|
|
|
|
_log.warning("[downloadFiles] Permission not granted");
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content:
|
|
|
|
Text(L10n.global().downloadFailureNoPermissionNotification),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
break;
|
|
|
|
} on JobCanceledException catch (_) {
|
|
|
|
_log.info("[downloadFiles] User canceled");
|
|
|
|
break;
|
|
|
|
} catch (e, stackTrace) {
|
|
|
|
_log.shout(
|
|
|
|
"[downloadFiles] Failed while DownloadFile", e, stackTrace);
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text("${L10n.global().downloadFailureNotification}: "
|
|
|
|
"${exception_util.toUserString(e)}"),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
} finally {
|
|
|
|
itemSubscription?.cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
subscription?.cancel();
|
|
|
|
if (successes.isNotEmpty) {
|
|
|
|
await _onDownloadSuccessful(successes.map((e) => e.item1).toList(),
|
|
|
|
successes.map((e) => e.item2).toList(), notif.notificationId);
|
|
|
|
} else {
|
|
|
|
await notif.dismiss();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _onDownloadSuccessful(
|
|
|
|
List<File> files, List<dynamic> results, int? notificationId) async {
|
|
|
|
final notif = AndroidDownloadSuccessfulNotification(
|
|
|
|
results.cast<String>(),
|
|
|
|
files.map((e) => e.contentType).toList(),
|
|
|
|
notificationId: notificationId,
|
|
|
|
);
|
|
|
|
await notif.notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
static final _log = Logger("download_handler._DownloadHandlerAndroid");
|
|
|
|
}
|
|
|
|
|
|
|
|
class _DownloadHandlerWeb extends _DownloadHandlerBase {
|
|
|
|
@override
|
|
|
|
downloadFiles(
|
|
|
|
Account account,
|
|
|
|
List<File> files, {
|
|
|
|
String? parentDir,
|
2021-09-29 16:34:56 +02:00
|
|
|
}) async {
|
2021-09-28 22:56:44 +02:00
|
|
|
_log.info("[downloadFiles] Downloading ${files.length} file");
|
|
|
|
var controller = SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(L10n.global().downloadProcessingNotification),
|
|
|
|
duration: k.snackBarDurationShort,
|
|
|
|
));
|
|
|
|
controller?.closed.whenComplete(() {
|
|
|
|
controller = null;
|
|
|
|
});
|
2021-10-02 11:12:54 +02:00
|
|
|
int successCount = 0;
|
2021-09-28 22:56:44 +02:00
|
|
|
for (final f in files) {
|
|
|
|
try {
|
2021-10-02 11:12:54 +02:00
|
|
|
await DownloadFile()(
|
2021-09-29 16:34:56 +02:00
|
|
|
account,
|
|
|
|
f,
|
|
|
|
parentDir: parentDir,
|
|
|
|
);
|
2021-10-02 11:12:54 +02:00
|
|
|
++successCount;
|
2021-09-28 22:56:44 +02:00
|
|
|
} on PermissionException catch (_) {
|
|
|
|
_log.warning("[downloadFiles] Permission not granted");
|
|
|
|
controller?.close();
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(L10n.global().downloadFailureNoPermissionNotification),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
break;
|
|
|
|
} on JobCanceledException catch (_) {
|
|
|
|
_log.info("[downloadFiles] User canceled");
|
|
|
|
break;
|
|
|
|
} catch (e, stackTrace) {
|
|
|
|
_log.shout("[downloadFiles] Failed while DownloadFile", e, stackTrace);
|
|
|
|
controller?.close();
|
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text("${L10n.global().downloadFailureNotification}: "
|
|
|
|
"${exception_util.toUserString(e)}"),
|
|
|
|
duration: k.snackBarDurationNormal,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
2021-10-02 11:12:54 +02:00
|
|
|
if (successCount > 0) {
|
2021-09-28 22:56:44 +02:00
|
|
|
controller?.close();
|
2021-10-02 11:12:54 +02:00
|
|
|
SnackBarManager().showSnackBar(SnackBar(
|
|
|
|
content: Text(L10n.global().downloadSuccessNotification),
|
|
|
|
duration: k.snackBarDurationShort,
|
|
|
|
));
|
2021-09-28 22:56:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-02 11:12:54 +02:00
|
|
|
static final _log = Logger("download_handler._DownloadHandlerWeb");
|
2021-09-28 22:56:44 +02:00
|
|
|
}
|