Merge branch 'develop'

This commit is contained in:
Thibault Deckers 2025-03-11 00:33:19 +01:00
commit 12a89782cd
12 changed files with 65 additions and 12 deletions

View file

@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
## <a id="unreleased"></a>[Unreleased]
## <a id="v1.12.6"></a>[v1.12.6] - 2025-03-11
### Fixed
- data loss when editing metadata of items with incorrect mime types
- metadata inconsistency in the DB due to v1.12.4 upgrade
## <a id="v1.12.5"></a>[v1.12.5] - 2025-03-07
### Added

View file

@ -92,6 +92,7 @@ object PixyMetaHelper {
fun getXmp(input: InputStream): XMP? = Metadata.readMetadata(input)[MetadataType.XMP] as XMP?
// PixyMeta may fail with just a log, and write nothing to the output
fun setXmp(
input: InputStream,
output: OutputStream,

View file

@ -680,18 +680,19 @@ abstract class ImageProvider {
try {
edit(ExifInterface(editableFile))
if (editableFile.length() == 0L) {
callback.onFailure(Exception("editing Exif yielded an empty file"))
return false
}
val editedMimeType = detectMimeType(context, Uri.fromFile(editableFile), mimeType)
if (editedMimeType != mimeType) {
throw Exception("editing Exif changes mimeType=$mimeType -> $editedMimeType for uri=$uri path=$path")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// 1) as of androidx.exifinterface:exifinterface:1.3.6, editing some specific WEBP
// makes them undecodable by some decoders (including Android's and Chrome's)
// even though `BitmapFactory` successfully decodes their bounds,
// editing may corrupt the file for various reasons,
// so we check whether decoding it throws an exception
// 2) some users have reported corruption when editing JPEG as well,
// but conditions are unknown (specific image, custom ROM, low storage, race condition, etc.)
ImageDecoder.decodeBitmap(ImageDecoder.createSource(editableFile))
}
@ -781,6 +782,11 @@ abstract class ImageProvider {
}
}
if (editableFile.length() == 0L) {
callback.onFailure(Exception("editing IPTC yielded an empty file"))
return false
}
if (trailerVideoBytes != null) {
// append trailer video, if any
editableFile.appendBytes(trailerVideoBytes!!)
@ -917,6 +923,11 @@ abstract class ImageProvider {
}
}
if (editableFile.length() == 0L) {
callback.onFailure(Exception("editing XMP yielded an empty file"))
return false
}
try {
// copy the edited temporary file back to the original
editableFile.transferTo(outputStream(context, mimeType, uri, path))
@ -1330,6 +1341,11 @@ abstract class ImageProvider {
}
}
if (editableFile.length() == 0L) {
callback.onFailure(Exception("removing metadata yielded an empty file"))
return
}
try {
// copy the edited temporary file back to the original
editableFile.transferTo(outputStream(context, mimeType, uri, path))

View file

@ -0,0 +1,4 @@
In v1.12.6:
- play more kinds of motion photos
- enjoy the app in Galician
Full changelog available on GitHub

View file

@ -0,0 +1,4 @@
In v1.12.6:
- play more kinds of motion photos
- enjoy the app in Galician
Full changelog available on GitHub

View file

@ -117,7 +117,7 @@ class SqfliteLocalMediaDb implements LocalMediaDb {
')');
},
onUpgrade: LocalMediaDbUpgrader.upgradeDb,
version: 14,
version: 15,
);
final maxIdRows = await _db.rawQuery('SELECT MAX(id) AS maxId FROM $entryTable');

View file

@ -50,6 +50,8 @@ class LocalMediaDbUpgrader {
await _upgradeFrom12(db);
case 13:
await _upgradeFrom13(db);
case 14:
await _upgradeFrom14(db);
}
oldVersion++;
}
@ -479,4 +481,23 @@ class LocalMediaDbUpgrader {
await db.execute('ALTER TABLE $newEntryTable RENAME TO $entryTable;');
});
}
static Future<void> _upgradeFrom14(Database db) async {
debugPrint('upgrading DB from v14');
// no schema changes, but v1.12.4 may have corrupted the DB, so we sanitize it
// clear rebuildable tables
await db.delete(dateTakenTable, where: '1');
await db.delete(metadataTable, where: '1');
await db.delete(addressTable, where: '1');
await db.delete(trashTable, where: '1');
await db.delete(videoPlaybackTable, where: '1');
// remove rows referencing future entry IDs
final maxIdRows = await db.rawQuery('SELECT MAX(id) AS maxId FROM $entryTable');
final lastId = (maxIdRows.firstOrNull?['maxId'] as int?) ?? 0;
await db.delete(favouriteTable, where: 'id > ?', whereArgs: [lastId]);
await db.delete(coverTable, where: 'entryId > ?', whereArgs: [lastId]);
}
}

View file

@ -97,7 +97,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
case EntrySetAction.stats:
return isMain;
case EntrySetAction.rescan:
return isMain && isSelecting && !isTrash && !useTvLayout;
return isMain && isSelecting && !useTvLayout;
// selecting
case EntrySetAction.share:
case EntrySetAction.toggleFavourite:

View file

@ -61,7 +61,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
case EntryAction.restore:
return true;
case EntryAction.debug:
return kDebugMode;
return !kReleaseMode;
default:
return false;
}
@ -138,7 +138,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
action: action,
);
case EntryAction.debug:
return kDebugMode;
return !kReleaseMode;
}
}
}

View file

@ -144,8 +144,8 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> {
}
Future<void> _getMetadata() async {
if (!mounted) return;
final titledDirectories = await entry.getMetadataDirectories(context);
if (!mounted) return;
metadataNotifier.value = Map.fromEntries(titledDirectories);
_expandedDirectoryNotifier.value = null;
}

View file

@ -7,7 +7,7 @@ repository: https://github.com/deckerst/aves
# - play changelog: /whatsnew/whatsnew-en-US
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/XXX01.txt
# - libre changelog: /fastlane/metadata/android/en-US/changelogs/XXX.txt
version: 1.12.5+145
version: 1.12.6+146
publish_to: none
environment:

View file

@ -1,4 +1,4 @@
In v1.12.5:
In v1.12.6:
- play more kinds of motion photos
- enjoy the app in Galician
Full changelog available on GitHub