nc-photos/app/lib/entity/local_file/data_source.dart

126 lines
4 KiB
Dart
Raw Normal View History

2022-05-05 20:34:30 +02:00
import 'package:collection/collection.dart';
2022-05-05 16:06:47 +02:00
import 'package:logging/logging.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/entity/local_file.dart';
2022-05-05 20:34:30 +02:00
import 'package:nc_photos/mobile/android/android_info.dart';
import 'package:nc_photos/mobile/android/k.dart' as android;
2022-05-07 12:27:26 +02:00
import 'package:nc_photos/mobile/share.dart';
2022-05-05 16:06:47 +02:00
import 'package:nc_photos/object_extension.dart';
2022-05-05 20:34:30 +02:00
import 'package:nc_photos/stream_extension.dart';
2022-05-05 16:06:47 +02:00
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
2022-12-16 16:01:04 +01:00
import 'package:np_codegen/np_codegen.dart';
import 'package:np_collection/np_collection.dart';
2022-05-05 16:06:47 +02:00
2022-12-16 16:01:04 +01:00
part 'data_source.g.dart';
@npLog
2022-05-05 16:06:47 +02:00
class LocalFileMediaStoreDataSource implements LocalFileDataSource {
const LocalFileMediaStoreDataSource();
@override
listDir(String path) async {
_log.info("[listDir] $path");
final results = await MediaStore.queryFiles(path);
return results
.where((r) => file_util.isSupportedMime(r.mimeType ?? ""))
.map(_toLocalFile)
.toList();
}
2022-05-05 20:34:30 +02:00
@override
deleteFiles(
List<LocalFile> files, {
LocalFileOnFailureListener? onFailure,
}) async {
_log.info("[deleteFiles] ${files.map((f) => f.logTag).toReadableString()}");
2022-05-07 12:27:26 +02:00
final uriFiles = _filterUriFiles(files, (f) {
onFailure?.call(f, ArgumentError("File not supported"), null);
});
2022-05-05 20:34:30 +02:00
if (AndroidInfo().sdkInt >= AndroidVersion.R) {
await _deleteFiles30(uriFiles, onFailure);
} else {
await _deleteFiles0(uriFiles, onFailure);
}
}
2022-05-07 12:27:26 +02:00
@override
shareFiles(
List<LocalFile> files, {
LocalFileOnFailureListener? onFailure,
}) async {
_log.info("[shareFiles] ${files.map((f) => f.logTag).toReadableString()}");
final uriFiles = _filterUriFiles(files, (f) {
onFailure?.call(f, ArgumentError("File not supported"), null);
});
final share = AndroidFileShare(
uriFiles.map((e) => AndroidFileShareFile(e.uri, e.mime)).toList());
2022-05-07 12:27:26 +02:00
try {
await share.share();
} catch (e, stackTrace) {
for (final f in uriFiles) {
onFailure?.call(f, e, stackTrace);
}
}
}
2022-05-05 20:34:30 +02:00
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);
}
}
2022-05-07 12:27:26 +02:00
List<LocalUriFile> _filterUriFiles(
List<LocalFile> files, [
void Function(LocalFile)? nonUriFileCallback,
]) {
return files
.where((f) {
if (f is! LocalUriFile) {
_log.warning(
"[deleteFiles] Can't remove file not returned by this data source: $f");
nonUriFileCallback?.call(f);
return false;
} else {
return true;
}
})
.cast<LocalUriFile>()
.toList();
}
2022-05-05 16:06:47 +02:00
static LocalFile _toLocalFile(MediaStoreQueryResult r) => LocalUriFile(
uri: r.uri,
displayName: r.displayName,
path: r.path,
lastModified: DateTime.fromMillisecondsSinceEpoch(r.dateModified),
mime: r.mimeType,
dateTaken: r.dateTaken?.run(DateTime.fromMillisecondsSinceEpoch),
);
}