mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-13 18:58:53 +01:00
Delete local files
This commit is contained in:
parent
d33e3af806
commit
c38ace893d
5 changed files with 123 additions and 1 deletions
|
@ -86,7 +86,7 @@ class LocalUriFile with EquatableMixin implements LocalFile {
|
|||
final DateTime? dateTaken;
|
||||
}
|
||||
|
||||
typedef LocalFileOnDeleteFailureListener = void Function(
|
||||
typedef LocalFileOnFailureListener = void Function(
|
||||
LocalFile file, Object? error, StackTrace? stackTrace);
|
||||
|
||||
class LocalFileRepo {
|
||||
|
@ -95,10 +95,23 @@ class LocalFileRepo {
|
|||
/// See [LocalFileDataSource.listDir]
|
||||
Future<List<LocalFile>> listDir(String path) => dataSrc.listDir(path);
|
||||
|
||||
/// See [LocalFileDataSource.deleteFiles]
|
||||
Future<void> deleteFiles(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
}) =>
|
||||
dataSrc.deleteFiles(files, onFailure: onFailure);
|
||||
|
||||
final LocalFileDataSource dataSrc;
|
||||
}
|
||||
|
||||
abstract class LocalFileDataSource {
|
||||
/// List all files under [path]
|
||||
Future<List<LocalFile>> listDir(String path);
|
||||
|
||||
/// Delete files
|
||||
Future<void> deleteFiles(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||
import 'package:nc_photos/entity/local_file.dart';
|
||||
import 'package:nc_photos/iterable_extension.dart';
|
||||
import 'package:nc_photos/mobile/android/android_info.dart';
|
||||
import 'package:nc_photos/mobile/android/k.dart' as android;
|
||||
import 'package:nc_photos/object_extension.dart';
|
||||
import 'package:nc_photos/stream_extension.dart';
|
||||
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
|
||||
|
||||
class LocalFileMediaStoreDataSource implements LocalFileDataSource {
|
||||
|
@ -17,6 +22,63 @@ class LocalFileMediaStoreDataSource implements LocalFileDataSource {
|
|||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
deleteFiles(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
}) async {
|
||||
_log.info("[deleteFiles] ${files.map((f) => f.logTag).toReadableString()}");
|
||||
final uriFiles = files
|
||||
.where((f) {
|
||||
if (f is! LocalUriFile) {
|
||||
_log.warning(
|
||||
"[deleteFiles] Can't remove file not returned by this data source: $f");
|
||||
onFailure?.call(f, ArgumentError("File not supported"), null);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.cast<LocalUriFile>()
|
||||
.toList();
|
||||
if (AndroidInfo().sdkInt >= AndroidVersion.R) {
|
||||
await _deleteFiles30(uriFiles, onFailure);
|
||||
} else {
|
||||
await _deleteFiles0(uriFiles, onFailure);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _deleteFiles30(
|
||||
List<LocalUriFile> files, LocalFileOnFailureListener? onFailure) async {
|
||||
assert(AndroidInfo().sdkInt >= AndroidVersion.R);
|
||||
int? resultCode;
|
||||
final resultFuture = MediaStore.stream
|
||||
.whereType<MediaStoreDeleteRequestResultEvent>()
|
||||
.first
|
||||
.then((ev) => resultCode = ev.resultCode);
|
||||
await MediaStore.deleteFiles(files.map((f) => f.uri).toList());
|
||||
await resultFuture;
|
||||
if (resultCode != android.resultOk) {
|
||||
_log.warning("[_deleteFiles30] result != OK: $resultCode");
|
||||
for (final f in files) {
|
||||
onFailure?.call(f, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _deleteFiles0(
|
||||
List<LocalUriFile> files, LocalFileOnFailureListener? onFailure) async {
|
||||
assert(AndroidInfo().sdkInt < AndroidVersion.R);
|
||||
final failedUris =
|
||||
await MediaStore.deleteFiles(files.map((f) => f.uri).toList());
|
||||
final failedFilesIt = failedUris!
|
||||
.map((uri) => files.firstWhereOrNull((f) => f.uri == uri))
|
||||
.whereNotNull();
|
||||
for (final f in failedFilesIt) {
|
||||
onFailure?.call(f, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
static LocalFile _toLocalFile(MediaStoreQueryResult r) => LocalUriFile(
|
||||
uri: r.uri,
|
||||
displayName: r.displayName,
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:logging/logging.dart';
|
|||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/entity/album.dart';
|
||||
import 'package:nc_photos/entity/file.dart';
|
||||
import 'package:nc_photos/entity/local_file.dart';
|
||||
import 'package:nc_photos/entity/share.dart';
|
||||
import 'package:nc_photos/pref.dart';
|
||||
|
||||
|
@ -148,6 +149,12 @@ class PrefUpdatedEvent {
|
|||
final dynamic value;
|
||||
}
|
||||
|
||||
class LocalFileDeletedEvent {
|
||||
const LocalFileDeletedEvent(this.files);
|
||||
|
||||
final List<LocalFile> files;
|
||||
}
|
||||
|
||||
extension FilePropertyUpdatedEventExtension on FilePropertyUpdatedEvent {
|
||||
bool hasAnyProperties(List<int> properties) =>
|
||||
properties.any((p) => this.properties & p != 0);
|
||||
|
|
8
app/lib/mobile/android/k.dart
Normal file
8
app/lib/mobile/android/k.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
/// Standard activity result: operation canceled.
|
||||
const resultCanceled = 0;
|
||||
|
||||
/// Standard activity result: operation succeeded.
|
||||
const resultOk = -1;
|
||||
|
||||
/// Start of user-defined activity results.
|
||||
const resultFirstUser = 1;
|
32
app/lib/use_case/delete_local.dart
Normal file
32
app/lib/use_case/delete_local.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:kiwi/kiwi.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/local_file.dart';
|
||||
import 'package:nc_photos/event/event.dart';
|
||||
|
||||
class DeleteLocal {
|
||||
DeleteLocal(this._c) : assert(require(_c));
|
||||
|
||||
static bool require(DiContainer c) =>
|
||||
DiContainer.has(c, DiType.localFileRepo);
|
||||
|
||||
Future<void> call(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
}) async {
|
||||
final deleted = List.of(files);
|
||||
await _c.localFileRepo.deleteFiles(files, onFailure: (f, e, stackTrace) {
|
||||
deleted.removeWhere((d) => d.compareIdentity(f));
|
||||
onFailure?.call(f, e, stackTrace);
|
||||
});
|
||||
if (deleted.isNotEmpty) {
|
||||
_log.info("[call] Deleted ${deleted.length} files successfully");
|
||||
KiwiContainer().resolve<EventBus>().fire(LocalFileDeletedEvent(deleted));
|
||||
}
|
||||
}
|
||||
|
||||
final DiContainer _c;
|
||||
|
||||
static final _log = Logger("use_case.delete_local.DeleteLocal");
|
||||
}
|
Loading…
Reference in a new issue