Merge branch 'develop'
This commit is contained in:
commit
12a89782cd
12 changed files with 65 additions and 12 deletions
|
@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <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
|
## <a id="v1.12.5"></a>[v1.12.5] - 2025-03-07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -92,6 +92,7 @@ object PixyMetaHelper {
|
||||||
|
|
||||||
fun getXmp(input: InputStream): XMP? = Metadata.readMetadata(input)[MetadataType.XMP] as XMP?
|
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(
|
fun setXmp(
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
output: OutputStream,
|
output: OutputStream,
|
||||||
|
|
|
@ -680,18 +680,19 @@ abstract class ImageProvider {
|
||||||
try {
|
try {
|
||||||
edit(ExifInterface(editableFile))
|
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)
|
val editedMimeType = detectMimeType(context, Uri.fromFile(editableFile), mimeType)
|
||||||
if (editedMimeType != mimeType) {
|
if (editedMimeType != mimeType) {
|
||||||
throw Exception("editing Exif changes mimeType=$mimeType -> $editedMimeType for uri=$uri path=$path")
|
throw Exception("editing Exif changes mimeType=$mimeType -> $editedMimeType for uri=$uri path=$path")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
// 1) as of androidx.exifinterface:exifinterface:1.3.6, editing some specific WEBP
|
// editing may corrupt the file for various reasons,
|
||||||
// makes them undecodable by some decoders (including Android's and Chrome's)
|
|
||||||
// even though `BitmapFactory` successfully decodes their bounds,
|
|
||||||
// so we check whether decoding it throws an exception
|
// 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))
|
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) {
|
if (trailerVideoBytes != null) {
|
||||||
// append trailer video, if any
|
// append trailer video, if any
|
||||||
editableFile.appendBytes(trailerVideoBytes!!)
|
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 {
|
try {
|
||||||
// copy the edited temporary file back to the original
|
// copy the edited temporary file back to the original
|
||||||
editableFile.transferTo(outputStream(context, mimeType, uri, path))
|
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 {
|
try {
|
||||||
// copy the edited temporary file back to the original
|
// copy the edited temporary file back to the original
|
||||||
editableFile.transferTo(outputStream(context, mimeType, uri, path))
|
editableFile.transferTo(outputStream(context, mimeType, uri, path))
|
||||||
|
|
4
fastlane/metadata/android/en-US/changelogs/146.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/146.txt
Normal 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
|
4
fastlane/metadata/android/en-US/changelogs/14601.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/14601.txt
Normal 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
|
|
@ -117,7 +117,7 @@ class SqfliteLocalMediaDb implements LocalMediaDb {
|
||||||
')');
|
')');
|
||||||
},
|
},
|
||||||
onUpgrade: LocalMediaDbUpgrader.upgradeDb,
|
onUpgrade: LocalMediaDbUpgrader.upgradeDb,
|
||||||
version: 14,
|
version: 15,
|
||||||
);
|
);
|
||||||
|
|
||||||
final maxIdRows = await _db.rawQuery('SELECT MAX(id) AS maxId FROM $entryTable');
|
final maxIdRows = await _db.rawQuery('SELECT MAX(id) AS maxId FROM $entryTable');
|
||||||
|
|
|
@ -50,6 +50,8 @@ class LocalMediaDbUpgrader {
|
||||||
await _upgradeFrom12(db);
|
await _upgradeFrom12(db);
|
||||||
case 13:
|
case 13:
|
||||||
await _upgradeFrom13(db);
|
await _upgradeFrom13(db);
|
||||||
|
case 14:
|
||||||
|
await _upgradeFrom14(db);
|
||||||
}
|
}
|
||||||
oldVersion++;
|
oldVersion++;
|
||||||
}
|
}
|
||||||
|
@ -479,4 +481,23 @@ class LocalMediaDbUpgrader {
|
||||||
await db.execute('ALTER TABLE $newEntryTable RENAME TO $entryTable;');
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
case EntrySetAction.stats:
|
case EntrySetAction.stats:
|
||||||
return isMain;
|
return isMain;
|
||||||
case EntrySetAction.rescan:
|
case EntrySetAction.rescan:
|
||||||
return isMain && isSelecting && !isTrash && !useTvLayout;
|
return isMain && isSelecting && !useTvLayout;
|
||||||
// selecting
|
// selecting
|
||||||
case EntrySetAction.share:
|
case EntrySetAction.share:
|
||||||
case EntrySetAction.toggleFavourite:
|
case EntrySetAction.toggleFavourite:
|
||||||
|
|
|
@ -61,7 +61,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
case EntryAction.restore:
|
case EntryAction.restore:
|
||||||
return true;
|
return true;
|
||||||
case EntryAction.debug:
|
case EntryAction.debug:
|
||||||
return kDebugMode;
|
return !kReleaseMode;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
action: action,
|
action: action,
|
||||||
);
|
);
|
||||||
case EntryAction.debug:
|
case EntryAction.debug:
|
||||||
return kDebugMode;
|
return !kReleaseMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,8 +144,8 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getMetadata() async {
|
Future<void> _getMetadata() async {
|
||||||
if (!mounted) return;
|
|
||||||
final titledDirectories = await entry.getMetadataDirectories(context);
|
final titledDirectories = await entry.getMetadataDirectories(context);
|
||||||
|
if (!mounted) return;
|
||||||
metadataNotifier.value = Map.fromEntries(titledDirectories);
|
metadataNotifier.value = Map.fromEntries(titledDirectories);
|
||||||
_expandedDirectoryNotifier.value = null;
|
_expandedDirectoryNotifier.value = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ repository: https://github.com/deckerst/aves
|
||||||
# - play changelog: /whatsnew/whatsnew-en-US
|
# - play changelog: /whatsnew/whatsnew-en-US
|
||||||
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/XXX01.txt
|
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/XXX01.txt
|
||||||
# - libre changelog: /fastlane/metadata/android/en-US/changelogs/XXX.txt
|
# - libre changelog: /fastlane/metadata/android/en-US/changelogs/XXX.txt
|
||||||
version: 1.12.5+145
|
version: 1.12.6+146
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
In v1.12.5:
|
In v1.12.6:
|
||||||
- play more kinds of motion photos
|
- play more kinds of motion photos
|
||||||
- enjoy the app in Galician
|
- enjoy the app in Galician
|
||||||
Full changelog available on GitHub
|
Full changelog available on GitHub
|
Loading…
Reference in a new issue