diff --git a/.flutter b/.flutter index 603104015..dec2ee5c1 160000 --- a/.flutter +++ b/.flutter @@ -1 +1 @@ -Subproject commit 603104015dd692ea3403755b55d07813d5cf8965 +Subproject commit dec2ee5c1f98f8e84a7d5380c05eb8a3d0a81668 diff --git a/.github/workflows/quality-check.yml b/.github/workflows/quality-check.yml index 3971f6bd7..4051df96a 100644 --- a/.github/workflows/quality-check.yml +++ b/.github/workflows/quality-check.yml @@ -69,7 +69,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -83,6 +83,6 @@ jobs: ./flutterw build apk --profile -t lib/main_play.dart --flavor play - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 657445e42..17147aa87 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,7 +75,7 @@ jobs: AVES_GOOGLE_API_KEY: ${{ secrets.AVES_GOOGLE_API_KEY }} - name: Generate artifact attestation - uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 with: subject-path: 'outputs/*' diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a88b1673d..a2291978f 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 with: sarif_file: results.sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b290ba4c..741cb66d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [v1.11.18] - 2024-11-18 + +### Changed + +- Albums: improved album creation feedback +- upgraded Flutter to stable v3.24.5 + +### Fixed + +- crash when playing video with DCL restriction enabled +- cataloguing images with wrong MPF offsets +- printing multi-page items containing some unprintable pages +- English (Shavian) locale tags for store listing + ## [v1.11.17] - 2024-10-30 ### Added diff --git a/android/app/build.gradle b/android/app/build.gradle index eb8171a4a..2eade1cc3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -154,12 +154,12 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1' implementation "androidx.appcompat:appcompat:1.7.0" - implementation 'androidx.core:core-ktx:1.13.1' - implementation 'androidx.lifecycle:lifecycle-process:2.8.6' + implementation 'androidx.core:core-ktx:1.15.0' + implementation 'androidx.lifecycle:lifecycle-process:2.8.7' implementation 'androidx.media:media:1.7.0' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.security:security-crypto:1.1.0-alpha06' - implementation 'androidx.work:work-runtime-ktx:2.9.1' + implementation 'androidx.work:work-runtime-ktx:2.10.0' implementation 'com.caverock:androidsvg-aar:1.4' implementation 'com.commonsware.cwac:document:0.5.0' @@ -181,7 +181,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3' - kapt 'androidx.annotation:annotation:1.8.2' + kapt 'androidx.annotation:annotation:1.9.1' ksp "com.github.bumptech.glide:ksp:$glide_version" compileOnly rootProject.findProject(':streams_channel') diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt index d1db4d173..98de3e4e0 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt @@ -792,7 +792,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { private fun hasAppleHdrGainMap(uri: Uri, sizeBytes: Long?): Boolean { val mpEntries = MultiPage.getJpegMpfEntries(context, uri, sizeBytes) ?: return false - mpEntries.filter { it.type == MpEntry.TYPE_UNDEFINED }.forEach { mpEntry -> + mpEntries.filter { it.type == MpEntry.TYPE_UNDEFINED }.forEachIndexed { mpIndex, mpEntry -> var dataOffset = mpEntry.dataOffset if (dataOffset > 0) { val baseOffset = MultiPage.getJpegMpfBaseOffset(context, uri, sizeBytes) @@ -802,9 +802,13 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { } StorageUtils.openInputStream(context, uri)?.let { input -> input.skip(dataOffset) - val pageMetadata = Helper.safeRead(input, sizeBytes) - if (pageMetadata.getDirectoriesOfType(XmpDirectory::class.java).any { it.xmpMeta.hasHdrGainMap() }) { - return true + try { + val pageMetadata = Helper.safeRead(input, sizeBytes) + if (pageMetadata.getDirectoriesOfType(XmpDirectory::class.java).any { it.xmpMeta.hasHdrGainMap() }) { + return true + } + } catch (e: Exception) { + Log.w(LOG_TAG, "failed to read metadata by metadata-extractor for uri=$uri mpIndex=$mpIndex mpEntry=$mpEntry", e) } } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt index e024acd72..8cc0aa52a 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt @@ -99,9 +99,12 @@ object MimeTypes { else -> true } - // as of `ExifInterface` v1.3.1, `isSupportedMimeType` reports - // no support for TIFF images, but it can actually open them (maybe other formats too) - fun canReadWithExifInterface(mimeType: String, strict: Boolean = true) = ExifInterface.isSupportedMimeType(mimeType) || !strict + // as of `ExifInterface` v1.4.0-alpha01, `isSupportedMimeType` reports + // no support for AVIF/TIFF images, but it can actually open them (maybe other formats too) + fun canReadWithExifInterface(mimeType: String, strict: Boolean = true): Boolean { + if (!strict) return true + return ExifInterface.isSupportedMimeType(mimeType) || mimeType == AVIF + } // as of latest PixyMeta fun canReadWithPixyMeta(mimeType: String) = when (mimeType) { @@ -143,7 +146,7 @@ object MimeTypes { return if (pageId != null && MultiPageImage.isSupported(mimeType)) { true } else when (mimeType) { - DNG, DNG_ADOBE, HEIC, HEIF, PNG, WEBP -> true + AVIF, DNG, DNG_ADOBE, HEIC, HEIF, PNG, WEBP -> true else -> false } } diff --git a/android/app/src/main/res/values-az/strings.xml b/android/app/src/main/res/values-az/strings.xml new file mode 100644 index 000000000..31f1b1c1d --- /dev/null +++ b/android/app/src/main/res/values-az/strings.xml @@ -0,0 +1,12 @@ + + + Aves + Şəkil Çərçivəsi + Divar kağızı + Xəritə + Axtarış + Videolar + Medianı yoxla + Media yoxlanılır + Dayandır + \ No newline at end of file diff --git a/android/app/src/main/res/values-b+en+Shaw/strings.xml b/android/app/src/main/res/values-b+zxx+Shaw/strings.xml similarity index 100% rename from android/app/src/main/res/values-b+en+Shaw/strings.xml rename to android/app/src/main/res/values-b+zxx+Shaw/strings.xml diff --git a/android/app/src/main/res/values-et/strings.xml b/android/app/src/main/res/values-et/strings.xml new file mode 100644 index 000000000..b596c8b41 --- /dev/null +++ b/android/app/src/main/res/values-et/strings.xml @@ -0,0 +1,12 @@ + + + Aves + Fotoraam + Taustapilt + Kaart + Otsi + Videod + Meedia tuvastamine + Tuvastame meediat + Peata + \ No newline at end of file diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml index 58e9cc54c..ca3cde898 100644 --- a/android/app/src/main/res/values-ru/strings.xml +++ b/android/app/src/main/res/values-ru/strings.xml @@ -8,4 +8,5 @@ Сканировать медия Сканирование медиа Стоп + Карта \ No newline at end of file diff --git a/android/exifinterface/build.gradle b/android/exifinterface/build.gradle index 46bfa54d8..7d83b50a2 100644 --- a/android/exifinterface/build.gradle +++ b/android/exifinterface/build.gradle @@ -26,5 +26,6 @@ android { } dependencies { - implementation 'androidx.annotation:annotation:1.8.2' + implementation 'androidx.annotation:annotation:1.9.1' + implementation 'org.jspecify:jspecify:1.0.0' } \ No newline at end of file diff --git a/android/exifinterface/src/main/AndroidManifest.xml b/android/exifinterface/src/main/AndroidManifest.xml index a5918e68a..568741e54 100644 --- a/android/exifinterface/src/main/AndroidManifest.xml +++ b/android/exifinterface/src/main/AndroidManifest.xml @@ -1,4 +1,2 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/android/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceFork.java b/android/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceFork.java index 934ee16b5..07bab0f4c 100644 --- a/android/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceFork.java +++ b/android/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceFork.java @@ -22,6 +22,8 @@ import static androidx.exifinterface.media.ExifInterfaceUtilsFork.convertToLongA import static androidx.exifinterface.media.ExifInterfaceUtilsFork.copy; import static androidx.exifinterface.media.ExifInterfaceUtilsFork.parseSubSeconds; import static androidx.exifinterface.media.ExifInterfaceUtilsFork.startsWith; + +import static java.lang.annotation.ElementType.TYPE_USE; import static java.nio.ByteOrder.BIG_ENDIAN; import static java.nio.ByteOrder.LITTLE_ENDIAN; @@ -33,17 +35,19 @@ import android.location.Location; import android.media.MediaDataSource; import android.media.MediaMetadataRetriever; import android.os.Build; +import android.system.Os; import android.system.OsConstants; import android.util.Log; import android.util.Pair; import androidx.annotation.IntDef; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; -import androidx.exifinterface.media.ExifInterfaceUtilsFork.Api21Impl; +import androidx.annotation.VisibleForTesting; import androidx.exifinterface.media.ExifInterfaceUtilsFork.Api23Impl; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -62,12 +66,14 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -83,20 +89,48 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; /* - * Forked from 'androidx.exifinterface:exifinterface:1.3.7' on 2024/02/21 + * Forked from 'androidx.exifinterface:exifinterface:1.4.0-alpha01' on 2024/11/17 * Named differently to let ExifInterface be loaded as subdependency. + * cf https://github.com/androidx/androidx/tree/androidx-main/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media */ /** * This is a class for reading and writing Exif tags in various image file formats. + * + *

Supported for reading: JPEG, PNG, WebP, HEIC, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, + * RAF, AVIF (on API 31+). + * + *

Supported for writing: JPEG, PNG, WebP. + * *

- * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF. + * + *

XMP Support

*

- * Supported for writing: JPEG, PNG, WebP. - *

- * Note: JPEG and HEIF files may contain XMP data either inside the Exif data chunk or outside of - * it. This class will search both locations for XMP data, but if XMP data exist both inside and - * outside Exif, will favor the XMP data inside Exif over the one outside. + * This class can read raw XMP data from the supported image file formats. + * + *

XMP data can be stored within Exif data (under tag 700), but many of the formats also define a + * separate storage location for XMP. ExifInterface handles this ambiguity as follows: + * + *

*/ public class ExifInterfaceFork { // TLAD threshold for safer Exif attribute parsing @@ -882,29 +916,43 @@ public class ExifInterfaceFork { // G. Tags related to picture-taking condition /** - *

Exposure time, given in seconds.

+ * Exposure time, given in seconds. + * + *

Note: For backwards compatibility this attribute is returned from {@link + * #getAttribute(String)} in decimal form (i.e. the format produced by {@link + * Double#toString(double)}). It is accepted into {@link #setAttribute(String, String)} in both + * rational (e.g. {@code "1/3"}) and decimal forms. The decimal format is anything accepted by + * {@link Double#parseDouble(String)}, e.g. {@code "0.125"}. * *

*/ public static final String TAG_EXPOSURE_TIME = "ExposureTime"; + /** - *

The F number.

+ * The F number. + * + *

Note: For backwards compatibility this attribute is returned from {@link + * #getAttribute(String)} in decimal form (i.e. the format produced by {@link + * Double#toString(double)}). It is accepted into {@link #setAttribute(String, String)} in both + * rational (e.g. {@code "1/3"}) and decimal forms. The decimal format is anything accepted by + * {@link Double#parseDouble(String)}, e.g. {@code "0.125"}. * *

*/ public static final String TAG_F_NUMBER = "FNumber"; + /** - *

TThe class of the program used by the camera to set exposure when the picture is taken. + *

The class of the program used by the camera to set exposure when the picture is taken. * The tag values are as follows.

* * */ public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue"; + /** - *

The distance to the subject, given in meters. Note that if the numerator of the recorded - * value is 0xFFFFFFFF, Infinity shall be indicated; and if the numerator is 0, Distance - * unknown shall be indicated.

+ * The distance to the subject, given in meters. + * + *

Note that if the numerator of the recorded value is 0xFFFFFFFF, Infinity shall be + * indicated; and if the numerator is 0, Distance unknown shall be indicated. + * + *

Note: For backwards compatibility this attribute is returned from {@link + * #getAttribute(String)} in decimal form (i.e. the format produced by {@link + * Double#toString(double)}). It is accepted into {@link #setAttribute(String, String)} in both + * rational (e.g. {@code "1/3"}) and decimal forms. The decimal format is anything accepted by + * {@link Double#parseDouble(String)}, e.g. {@code "0.125"}. * *

*/ public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance"; + /** *

The metering mode.

* @@ -1451,18 +1508,26 @@ public class ExifInterfaceFork { * @see #WHITEBALANCE_MANUAL */ public static final String TAG_WHITE_BALANCE = "WhiteBalance"; + /** - *

This tag indicates the digital zoom ratio when the image was shot. If the numerator of - * the recorded value is 0, this indicates that digital zoom was not used.

+ * This tag indicates the digital zoom ratio when the image was shot. If the numerator of the + * recorded value is 0, this indicates that digital zoom was not used. + * + *

Note: For backwards compatibility this attribute is returned from {@link + * #getAttribute(String)} in decimal form (i.e. the format produced by {@link + * Double#toString(double)}). It is accepted into {@link #setAttribute(String, String)} in both + * rational (e.g. {@code "1/3"}) and decimal forms. The decimal format is anything accepted by + * {@link Double#parseDouble(String)}, e.g. {@code "0.125"}. * *

*/ public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio"; + /** *

This tag indicates the equivalent focal length assuming a 35mm film camera, in mm. * A value of 0 means the focal length is unknown. Note that this tag differs from @@ -1792,18 +1857,24 @@ public class ExifInterfaceFork { * */ public static final String TAG_GPS_ALTITUDE = "GPSAltitude"; + /** - *

Indicates the time as UTC (Coordinated Universal Time). TimeStamp is expressed as three - * unsigned rational values giving the hour, minute, and second.

+ * Indicates the time as UTC (Coordinated Universal Time). TimeStamp is expressed as three + * unsigned rational values giving the hour, minute, and second. + * + *

Note: This attribute is returned from {@link #getAttribute(String)} and accepted into + * {@link #setAttribute(String, String)} as 3 colon-separated integers, e.g. {@code "11:05:32"}. + * Decimal or rational hours, minutes or seconds parts are not supported. * *

*/ public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp"; + /** *

Indicates the GPS satellites used for measurements. This tag may be used to describe * the number of satellites, their ID number, angle of elevation, azimuth, SNR and other @@ -1876,7 +1947,8 @@ public class ExifInterfaceFork { */ public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef"; /** - *

Indicates the speed of GPS receiver movement.

+ * Indicates the speed of GPS receiver movement. The units are indicated by {@link + * #TAG_GPS_SPEED_REF}. * *