Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
deckerst committed Aug 20, 2023
2 parents cf64527 + 246dbd6 commit fb8a97c
Show file tree
Hide file tree
Showing 339 changed files with 9,945 additions and 4,753 deletions.
2 changes: 1 addition & 1 deletion .flutter
Submodule .flutter updated 1857 files
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file.

## <a id="unreleased"></a>[Unreleased]

## <a id="v1.9.0"></a>[v1.9.0] - 2023-08-21

### Added

- Video: improved seek accuracy, HDR support, AV1 support, playback speed from x0.25 to x4
- support for animated AVIF (requires rescan)
- Collection: filtering by rating range
- Viewer: optionally show histogram on overlay
- Viewer: external export actions available as quick actions
- About: data usage

### Changed

- Accessibility: removing animations also removes the overscroll stretch effect
- target Android 14 (API 34)
- upgraded Flutter to stable v3.13.0

### Fixed

- flickering when starting videos

## <a id="v1.8.9"></a>[v1.8.9] - 2023-06-04

### Changed
Expand Down
19 changes: 10 additions & 9 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id 'com.android.application'
id 'com.google.devtools.ksp' version "$ksp_version"
id 'kotlin-android'
id 'kotlin-kapt'
}
Expand Down Expand Up @@ -48,7 +49,7 @@ if (keystorePropertiesFile.exists()) {

android {
namespace 'deckers.thibault.aves'
compileSdk 33
compileSdk 34
ndkVersion flutter.ndkVersion

compileOptions {
Expand All @@ -75,7 +76,7 @@ android {
// which implementation `DocumentBuilderImpl` is provided by the OS and is not customizable on Android,
// but the implementation on API <19 is not robust enough and fails to build XMP documents
minSdkVersion 19
targetSdkVersion 33
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
manifestPlaceholders = [googleApiKey: keystoreProperties["googleApiKey"] ?: "<NONE>",
Expand Down Expand Up @@ -175,10 +176,10 @@ android {
tasks.withType(KotlinCompile).configureEach {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}
kotlin {
jvmToolchain(8)
}

flutter {
Expand All @@ -202,7 +203,7 @@ repositories {
}

dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

implementation "androidx.appcompat:appcompat:1.6.1"
implementation 'androidx.core:core-ktx:1.10.1'
Expand All @@ -224,18 +225,18 @@ dependencies {
// - https://jitpack.io/p/deckerst/Android-TiffBitmapFactory
// - https://jitpack.io/p/deckerst/mp4parser
// - https://jitpack.io/p/deckerst/pixymeta-android
implementation 'com.github.deckerst:Android-TiffBitmapFactory:876e53870a'
implementation 'com.github.deckerst:Android-TiffBitmapFactory:90c06eebf4'
implementation 'com.github.deckerst.mp4parser:isoparser:4cc0c5d06c'
implementation 'com.github.deckerst.mp4parser:muxer:4cc0c5d06c'
implementation 'com.github.deckerst:pixymeta-android:706bd73d6e'

// huawei flavor only
huaweiImplementation "com.huawei.agconnect:agconnect-core:$huawei_agconnect_version"

testImplementation "org.junit.jupiter:junit-jupiter-engine:5.9.2"
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0'

kapt 'androidx.annotation:annotation:1.6.0'
kapt "com.github.bumptech.glide:compiler:$glide_version"
ksp "com.github.bumptech.glide:ksp:$glide_version"

compileOnly rootProject.findProject(':streams_channel')
}
Expand Down
7 changes: 5 additions & 2 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
TODO TLAD [Android 14 (API 34)] request/handle READ_MEDIA_VISUAL_USER_SELECTED permission
cf https://developer.android.com/about/versions/14/changes/partial-photo-video-access
-->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission
Expand Down Expand Up @@ -56,8 +57,9 @@
allow install on API 19, despite the `minSdkVersion` declared in dependencies:
- Google Maps is from API 20
- the Security library is from API 21
- FFmpegKit for Flutter is from API 24
-->
<uses-sdk tools:overrideLibrary="io.flutter.plugins.googlemaps, androidx.security:security-crypto" />
<uses-sdk tools:overrideLibrary="io.flutter.plugins.googlemaps, androidx.security:security-crypto, com.arthenica.ffmpegkit.flutter" />

<!-- from Android 11, we should define <queries> to make other apps visible to this app -->
<queries>
Expand Down Expand Up @@ -295,7 +297,8 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<!-- as of Flutter v3.10.1, Impeller badly renders text, fails to render videos, and crashes with Google Maps -->
<!-- as of Flutter v3.10.1 (stable) / v3.12.0-15.0.pre.105 (master),
Impeller badly renders text, fails to render videos, and crashes with Google Maps -->
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
import deckers.thibault.aves.model.FieldMap
import deckers.thibault.aves.utils.PermissionManager
import deckers.thibault.aves.utils.StorageUtils
import deckers.thibault.aves.utils.StorageUtils.getFolderSize
import deckers.thibault.aves.utils.StorageUtils.getPrimaryVolumePath
import deckers.thibault.aves.utils.StorageUtils.getVolumePaths
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.util.PathUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
Expand All @@ -25,6 +27,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {

override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"getDataUsage" -> ioScope.launch { safe(call, result, ::getDataUsage) }
"getStorageVolumes" -> ioScope.launch { safe(call, result, ::getStorageVolumes) }
"getVaultRoot" -> ioScope.launch { safe(call, result, ::getVaultRoot) }
"getFreeSpace" -> ioScope.launch { safe(call, result, ::getFreeSpace) }
Expand All @@ -39,6 +42,37 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
}
}

private fun getDataUsage(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
var internalCache = getFolderSize(context.cacheDir)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
internalCache += getFolderSize(context.codeCacheDir)
}
val externalCache = context.externalCacheDirs.map(::getFolderSize).sum()

val dataDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) context.dataDir else File(context.applicationInfo.dataDir)

val database = getFolderSize(File(dataDir, "databases"))
val flutter = getFolderSize(File(PathUtils.getDataDirectory(context)))
val vaults = getFolderSize(File(StorageUtils.getVaultRoot(context)))
val trash = context.getExternalFilesDirs(null).mapNotNull { StorageUtils.trashDirFor(context, it.path) }.map(::getFolderSize).sum()

val internalData = getFolderSize(dataDir) - internalCache
val externalData = context.getExternalFilesDirs(null).map(::getFolderSize).sum()
val miscData = internalData + externalData - (database + flutter + vaults + trash)

result.success(
hashMapOf(
"database" to database,
"flutter" to flutter,
"vaults" to vaults,
"trash" to trash,
"miscData" to miscData,
"internalCache" to internalCache,
"externalCache" to externalCache,
)
)
}

private fun getStorageVolumes(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
val volumes = ArrayList<Map<String, Any>>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,7 @@ class SvgRegionFetcher internal constructor(
svg.renderToCanvas(canvas, renderOptions)

bitmap = Bitmap.createBitmap(bitmap, bleedX, bleedY, targetBitmapWidth, targetBitmapHeight)

if (bitmap != null) {
result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} else {
result.error("fetch-null", "failed to decode region for uri=$uri regionRect=$regionRect", null)
}
result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} catch (e: Exception) {
result.error("fetch-read-exception", "failed to initialize region decoder for uri=$uri regionRect=$regionRect", e.message)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,12 @@ class ImageByteStreamHandler(private val context: Context, private val arguments
var len: Int
while (inputStream.read(buffer).also { len = it } != -1) {
// cannot decode image on Flutter side when using `buffer` directly
success(buffer.copyOf(len))
if (MemoryUtils.canAllocate(len)) {
success(buffer.copyOf(len))
} else {
error("streamBytes-memory", "not enough memory to allocate $len bytes", null)
return
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,15 @@ internal class TiffFetcher(val model: TiffImage, val width: Int, val height: Int
inDirectoryNumber = page
inSampleSize = sampleSize
}
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
if (bitmap == null) {
callback.onLoadFailed(Exception("null bitmap"))
} else {
callback.onDataReady(bitmap)
try {
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
if (bitmap == null) {
callback.onLoadFailed(Exception("Decoding full TIFF yielded null bitmap"))
} else {
callback.onDataReady(bitmap)
}
} catch (e: Exception) {
callback.onLoadFailed(e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ object Mp4ParserHelper {
}
// creating `IsoFile` with a `File` or a `File.inputStream()` yields `No such device`
IsoFile(channel, boxParser).use { isoFile ->
val fragmented = isoFile.boxes.any { box -> box is MovieFragmentBox || box is SegmentIndexBox }
if (fragmented) throw Exception("editing fragmented movies is not supported")

val lastContentBox = isoFile.boxes.reversed().firstOrNull { box ->
when {
box == isoFile.movieBox -> false
Expand All @@ -60,7 +63,7 @@ object Mp4ParserHelper {
else -> true
}
}
lastContentBox ?: throw Exception("failed to find last context box")
lastContentBox ?: throw Exception("failed to find last content box")
val oldFileSize = isoFile.size
var appendOffset = (isoFile.getBoxOffset { box -> box == lastContentBox })!! + lastContentBox.size

Expand Down Expand Up @@ -97,7 +100,6 @@ object Mp4ParserHelper {
if (trailing > 0) {
addFreeBoxEdit(appendOffset, trailing)
}

return edits
}
}
Expand Down Expand Up @@ -277,7 +279,9 @@ object Mp4ParserHelper {
// creating `IsoFile` with a `File` or a `File.inputStream()` yields `No such device`
IsoFile(channel, metadataBoxParser()).use { isoFile ->
val userDataBox = Path.getPath<UserDataBox>(isoFile.movieBox, UserDataBox.TYPE)
fields.putAll(extractBoxFields(userDataBox))
if (userDataBox != null) {
fields.putAll(extractBoxFields(userDataBox))
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): Ap
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong()))
} else {
@Suppress("deprecation")
getApplicationInfo(packageName, flags)
}
}
Expand All @@ -45,7 +44,6 @@ fun PackageManager.queryIntentActivitiesCompat(intent: Intent, flags: Int): List
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(flags.toLong()))
} else {
@Suppress("deprecation")
queryIntentActivities(intent, flags)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package deckers.thibault.aves.utils

import android.app.ActivityManager
import android.app.Service
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.util.Log
import deckers.thibault.aves.utils.UriUtils.tryParseId
Expand All @@ -24,19 +21,6 @@ object ContextUtils {
.build()
}

fun Context.isMyServiceRunning(serviceClass: Class<out Service>): Boolean {
val am = this.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
am ?: return false
@Suppress("deprecation")
return am.getRunningServices(Integer.MAX_VALUE).any { it.service.className == serviceClass.name }
}

// `flag`: `DocumentsContract.Document.FLAG_SUPPORTS_COPY`, etc.
fun Context.queryDocumentProviderFlag(docUri: Uri, flag: Int): Boolean {
val flags = queryContentPropValue(docUri, "", DocumentsContract.Document.COLUMN_FLAGS) as Long?
return if (flags != null) (flags.toInt() and flag) == flag else false
}

fun Context.queryContentPropValue(uri: Uri, mimeType: String, column: String): Any? {
var contentUri: Uri = uri
if (StorageUtils.isMediaStoreContentUri(uri)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.embedding.engine.loader.FlutterLoader
import io.flutter.view.FlutterCallbackInformation
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

Expand Down Expand Up @@ -60,7 +61,7 @@ object FlutterUtils {
suspend fun runOnUiThread(r: Runnable) {
val mainLooper = Looper.getMainLooper()
if (Looper.myLooper() != mainLooper) {
suspendCoroutine<Boolean> { cont ->
suspendCoroutine { cont: Continuation<Boolean> ->
Handler(mainLooper).post {
r.run()
cont.resume(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,18 @@ object StorageUtils {

// convenience methods

fun getFolderSize(f: File): Long {
var size: Long = 0
if (f.isDirectory) {
for (file in f.listFiles()!!) {
size += getFolderSize(file)
}
} else {
size = f.length()
}
return size
}

fun ensureTrailingSeparator(dirPath: String): String {
return if (dirPath.endsWith(File.separator)) dirPath else dirPath + File.separator
}
Expand Down
12 changes: 11 additions & 1 deletion android/app/src/main/res/values-be/strings.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="analysis_channel_name">Сканаванне носьбітаў</string>
<string name="videos_shortcut_short_label">Відэа</string>
<string name="wallpaper">Шпалеры</string>
<string name="analysis_notification_default_title">Сканаванне носьбітаў</string>
<string name="app_name">Aves</string>
<string name="app_widget_label">Фотарамка</string>
<string name="safe_mode_shortcut_short_label">Бяспечны рэжым</string>
<string name="search_shortcut_short_label">Пошук</string>
<string name="analysis_notification_action_stop">Стоп</string>
</resources>
2 changes: 1 addition & 1 deletion android/app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<string name="app_name">Aves</string>
<string name="app_widget_label">Marco de foto</string>
<string name="wallpaper">Fondo de pantalla</string>
<string name="search_shortcut_short_label">Búsqueda</string>
<string name="search_shortcut_short_label">Buscar</string>
<string name="videos_shortcut_short_label">Vídeos</string>
<string name="analysis_channel_name">Explorar medios</string>
<string name="analysis_notification_default_title">Explorando medios</string>
Expand Down
Loading

0 comments on commit fb8a97c

Please sign in to comment.