#251 #119 clean obsolete Media Store entry when trying to move to bin entry backed by a file that no longer exists
This commit is contained in:
parent
4f5664a80a
commit
13bac7937b
6 changed files with 46 additions and 30 deletions
|
@ -1045,6 +1045,9 @@ abstract class ImageProvider {
|
|||
// used when skipping a move/creation op because the target file already exists
|
||||
val skippedFieldMap: HashMap<String, Any?> = hashMapOf("skipped" to true)
|
||||
|
||||
// used when deleting instead of moving to bin because the target file no longer exists
|
||||
val deletedFieldMap: HashMap<String, Any?> = hashMapOf("deleted" to true)
|
||||
|
||||
fun isMediaUriPermissionGranted(context: Context, uri: Uri, mimeType: String): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val safeUri = StorageUtils.getMediaStoreScopedStorageSafeUri(uri, mimeType)
|
||||
|
|
|
@ -443,6 +443,10 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
if (effectiveTargetDir != null) {
|
||||
val newFields = if (isCancelledOp()) skippedFieldMap else {
|
||||
val sourceFile = File(sourcePath)
|
||||
if (!sourceFile.exists() && toBin) {
|
||||
delete(activity, sourceUri, sourcePath, mimeType = mimeType)
|
||||
deletedFieldMap
|
||||
} else {
|
||||
moveSingle(
|
||||
activity = activity,
|
||||
sourceFile = sourceFile,
|
||||
|
@ -456,6 +460,7 @@ class MediaStoreImageProvider : ImageProvider() {
|
|||
toBin = toBin,
|
||||
)
|
||||
}
|
||||
}
|
||||
result["newFields"] = newFields
|
||||
result["success"] = true
|
||||
}
|
||||
|
|
|
@ -28,29 +28,29 @@ class ImageOpEvent extends Equatable {
|
|||
@immutable
|
||||
class MoveOpEvent extends ImageOpEvent {
|
||||
final Map newFields;
|
||||
final bool deleted;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [success, skipped, uri, newFields];
|
||||
List<Object?> get props => [success, skipped, uri, newFields, deleted];
|
||||
|
||||
const MoveOpEvent({
|
||||
required bool success,
|
||||
required bool skipped,
|
||||
required String uri,
|
||||
required super.success,
|
||||
required super.skipped,
|
||||
required super.uri,
|
||||
required this.newFields,
|
||||
}) : super(
|
||||
success: success,
|
||||
skipped: skipped,
|
||||
uri: uri,
|
||||
);
|
||||
required this.deleted,
|
||||
});
|
||||
|
||||
factory MoveOpEvent.fromMap(Map map) {
|
||||
final newFields = map['newFields'] ?? {};
|
||||
final skipped = (map['skipped'] ?? false) || (newFields['skipped'] ?? false);
|
||||
final deleted = (map['deleted'] ?? false) || (newFields['deleted'] ?? false);
|
||||
return MoveOpEvent(
|
||||
success: (map['success'] ?? false) || skipped,
|
||||
skipped: skipped,
|
||||
uri: map['uri'],
|
||||
newFields: newFields,
|
||||
deleted: deleted,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -63,16 +63,13 @@ class ExportOpEvent extends MoveOpEvent {
|
|||
List<Object?> get props => [success, skipped, uri, pageId, newFields];
|
||||
|
||||
const ExportOpEvent({
|
||||
required bool success,
|
||||
required bool skipped,
|
||||
required String uri,
|
||||
required super.success,
|
||||
required super.skipped,
|
||||
required super.uri,
|
||||
this.pageId,
|
||||
required Map newFields,
|
||||
required super.newFields,
|
||||
}) : super(
|
||||
success: success,
|
||||
skipped: skipped,
|
||||
uri: uri,
|
||||
newFields: newFields,
|
||||
deleted: false,
|
||||
);
|
||||
|
||||
factory ExportOpEvent.fromMap(Map map) {
|
||||
|
|
|
@ -132,7 +132,9 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
|
|||
onCancel: () => mediaFileService.cancelFileOp(opId),
|
||||
onDone: (processed) async {
|
||||
final successOps = processed.where((v) => v.success).toSet();
|
||||
final movedOps = successOps.where((v) => !v.skipped).toSet();
|
||||
|
||||
// move
|
||||
final movedOps = successOps.where((v) => !v.skipped && !v.deleted).toSet();
|
||||
final movedEntries = movedOps.map((v) => v.uri).map((uri) => entries.firstWhereOrNull((entry) => entry.uri == uri)).whereNotNull().toSet();
|
||||
await source.updateAfterMove(
|
||||
todoEntries: entries,
|
||||
|
@ -140,6 +142,12 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
|
|||
destinationAlbums: destinationAlbums,
|
||||
movedOps: movedOps,
|
||||
);
|
||||
|
||||
// delete (when trying to move to bin obsolete entries)
|
||||
final deletedOps = successOps.where((v) => v.deleted).toSet();
|
||||
final deletedUris = deletedOps.map((event) => event.uri).toSet();
|
||||
await source.removeEntries(deletedUris, includeTrash: true);
|
||||
|
||||
source.resumeMonitoring();
|
||||
|
||||
// cleanup
|
||||
|
|
|
@ -25,6 +25,7 @@ class FakeMediaFileService extends Fake implements MediaFileService {
|
|||
'path': '${entry.directory}/$newName',
|
||||
'dateModifiedSecs': FakeMediaStoreService.dateSecs,
|
||||
},
|
||||
deleted: false,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ class FakeMediaStoreService extends Fake implements MediaStoreService {
|
|||
'path': entry.path!.replaceFirst(sourceAlbum, destinationAlbum),
|
||||
'dateModifiedSecs': FakeMediaStoreService.dateSecs,
|
||||
},
|
||||
deleted: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -73,6 +74,7 @@ class FakeMediaStoreService extends Fake implements MediaStoreService {
|
|||
'path': entry.path!.replaceFirst(oldName, newName),
|
||||
'dateModifiedSecs': FakeMediaStoreService.dateSecs,
|
||||
},
|
||||
deleted: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue