Guidelines
Use case
Currently, Aves moves images by writing the source bytes to the new file stream. This works, but takes a long time when moving a lot of images. When using the "preserve dates" option, which currently works by modifying Exif metadata, it takes even longer.
Proposal
Android apparently provides a way to update the RELATIVE_PATH field of a media file directly, which moves it to the new location instantly and doesn't change the modification date.
I am not very knowledgeable about this, but here is the AI output from analyzing https://github.com/IacobIonut01/ReFra which uses this method, which could provide some guidance:
Slop explanation
Here's how it works:
The trick: using MediaStore.RELATIVE_PATH instead of copy+delete
The critical code is in MediaRepositoryImpl.kt:
override suspend fun <T : Media> moveMedia(
media: T,
newPath: String
): Boolean {
val (destVolume, destRelPath) = resolveMediaStoreVolume(newPath)
val sourceVolume = media.mediaStoreVolumeName
if (destVolume == sourceVolume) {
return context.updateMedia(
media = media,
contentValues = relativePath(destRelPath)
)
}
return crossVolumeMove(media, destVolume, destRelPath)
}
The relativePath helper (same file, bottom) just creates:
private fun relativePath(newPath: String) = ContentValues().apply {
put(MediaStore.MediaColumns.RELATIVE_PATH, newPath)
}
This is the key. On Android 10+ (API 29+, scoped storage), RELATIVE_PATH is a virtual column in MediaStore. When you call ContentResolver.update() with just RELATIVE_PATH set to a new directory, Android itself moves the file on disk — without ever opening, reading, or writing the file's contents. The file's mtime (last-modified timestamp) is left untouched because it's just a filesystem-level rename/move, not a copy.
Contrast this with naive gallery apps that do a manual "read source → write to destination → delete source" pipeline. That creates a brand new file at the destination, which gets the current time as its modification date.
The cross-volume exception
For moves between different storage volumes (e.g., internal storage → SD card), the app does fall back to a copy+delete in crossVolumeMove(), and it explicitly sets DATE_MODIFIED to current time there. This is unavoidable — you can't do a zero-cost rename across volumes. But for the common case of moving photos between albums on the same storage device, the RELATIVE_PATH trick preserves the original date perfectly.
Alternatives
Changing the modification date via Exif does have major advantages over this method, since it also preserves the date during file synchronization, etc.
However, even if you want to keep the Exif method of automatically preserving dates, using this API would still make the file moving much faster and would greatly improve the user experience
Additional context
No response
Guidelines
Use case
Currently, Aves moves images by writing the source bytes to the new file stream. This works, but takes a long time when moving a lot of images. When using the "preserve dates" option, which currently works by modifying Exif metadata, it takes even longer.
Proposal
Android apparently provides a way to update the
RELATIVE_PATHfield of a media file directly, which moves it to the new location instantly and doesn't change the modification date.I am not very knowledgeable about this, but here is the AI output from analyzing https://github.com/IacobIonut01/ReFra which uses this method, which could provide some guidance:
Slop explanation
Here's how it works:The trick: using
MediaStore.RELATIVE_PATHinstead of copy+deleteThe critical code is in
MediaRepositoryImpl.kt:The
relativePathhelper (same file, bottom) just creates:This is the key. On Android 10+ (API 29+, scoped storage),
RELATIVE_PATHis a virtual column in MediaStore. When you callContentResolver.update()with justRELATIVE_PATHset to a new directory, Android itself moves the file on disk — without ever opening, reading, or writing the file's contents. The file'smtime(last-modified timestamp) is left untouched because it's just a filesystem-level rename/move, not a copy.Contrast this with naive gallery apps that do a manual "read source → write to destination → delete source" pipeline. That creates a brand new file at the destination, which gets the current time as its modification date.
The cross-volume exception
For moves between different storage volumes (e.g., internal storage → SD card), the app does fall back to a copy+delete in
crossVolumeMove(), and it explicitly setsDATE_MODIFIEDto current time there. This is unavoidable — you can't do a zero-cost rename across volumes. But for the common case of moving photos between albums on the same storage device, theRELATIVE_PATHtrick preserves the original date perfectly.Alternatives
Changing the modification date via Exif does have major advantages over this method, since it also preserves the date during file synchronization, etc.
However, even if you want to keep the Exif method of automatically preserving dates, using this API would still make the file moving much faster and would greatly improve the user experience
Additional context
No response