From f27b8b2dedc89c2182a9ae25a68f25e82e174840 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 30 Dec 2023 20:29:12 -0500 Subject: [PATCH] Don't use reflection for handling backup options as boolean array Wasn't working correctly in release build, _probably_ because of R8 despite kotlin-reflect shipping with Proguard rules and us already keeping all Tachiyomi classes. (cherry picked from commit 6ab8e1e73dbcc65d693dd2ed2680c950139dadde) --- .../screen/data/RestoreBackupScreen.kt | 1 - .../data/backup/create/BackupCreateJob.kt | 4 +- .../data/backup/create/BackupOptions.kt | 30 +++++++++ .../data/backup/restore/BackupRestoreJob.kt | 4 +- .../data/backup/restore/RestoreOptions.kt | 20 ++++++ core/build.gradle.kts | 1 - .../util/lang/BooleanDataClassExtensions.kt | 26 -------- .../lang/BooleanDataClassExtensionsTest.kt | 63 ------------------- 8 files changed, 52 insertions(+), 97 deletions(-) delete mode 100644 core/src/main/java/tachiyomi/core/util/lang/BooleanDataClassExtensions.kt delete mode 100644 core/src/test/kotlin/tachiyomi/core/util/lang/BooleanDataClassExtensionsTest.kt diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt index f5fe02973..1e5e36169 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt @@ -32,7 +32,6 @@ import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob import eu.kanade.tachiyomi.data.backup.restore.RestoreOptions import eu.kanade.tachiyomi.util.system.DeviceUtil import kotlinx.coroutines.flow.update -import tachiyomi.core.util.lang.anyEnabled import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.LabeledCheckbox import tachiyomi.presentation.core.components.LazyColumnWithAction diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt index 3d9af6403..cd607480d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt @@ -24,8 +24,6 @@ import eu.kanade.tachiyomi.util.system.isRunning import eu.kanade.tachiyomi.util.system.setForegroundSafely import eu.kanade.tachiyomi.util.system.workManager import logcat.LogPriority -import tachiyomi.core.util.lang.asBooleanArray -import tachiyomi.core.util.lang.asDataClass import tachiyomi.core.util.system.logcat import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.storage.service.StorageManager @@ -49,7 +47,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete setForegroundSafely() - val options: BackupOptions = inputData.getBooleanArray(OPTIONS_KEY)?.asDataClass() + val options = inputData.getBooleanArray(OPTIONS_KEY)?.let { BackupOptions.fromBooleanArray(it) } ?: BackupOptions() return try { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt index 9e1d8631f..c5bfdad1b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt @@ -20,6 +20,21 @@ data class BackupOptions( // SY <-- ) { + fun asBooleanArray() = booleanArrayOf( + libraryEntries, + categories, + chapters, + tracking, + history, + appSettings, + sourceSettings, + privateSettings, + // SY --> + customInfo, + readEntries, + // SY <-- + ) + companion object { val libraryOptions = persistentListOf( Entry( @@ -85,6 +100,21 @@ data class BackupOptions( enabled = { it.appSettings || it.sourceSettings }, ), ) + + fun fromBooleanArray(array: BooleanArray) = BackupOptions( + libraryEntries = array[0], + categories = array[1], + chapters = array[2], + tracking = array[3], + history = array[4], + appSettings = array[5], + sourceSettings = array[6], + privateSettings = array[7], + // SY --> + customInfo = array[8], + readEntries = array[9], + // SY <-- + ) } data class Entry( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt index 5d24e9fa6..180e8f055 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestoreJob.kt @@ -20,8 +20,6 @@ import eu.kanade.tachiyomi.util.system.workManager import kotlinx.coroutines.CancellationException import logcat.LogPriority import tachiyomi.core.i18n.stringResource -import tachiyomi.core.util.lang.asBooleanArray -import tachiyomi.core.util.lang.asDataClass import tachiyomi.core.util.system.logcat import tachiyomi.i18n.MR @@ -32,7 +30,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet override suspend fun doWork(): Result { val uri = inputData.getString(LOCATION_URI_KEY)?.toUri() - val options: RestoreOptions? = inputData.getBooleanArray(OPTIONS_KEY)?.asDataClass() + val options = inputData.getBooleanArray(OPTIONS_KEY)?.let { RestoreOptions.fromBooleanArray(it) } if (uri == null || options == null) { return Result.failure() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt index b17c99bcf..a7e0771ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/RestoreOptions.kt @@ -14,6 +14,17 @@ data class RestoreOptions( // SY <-- ) { + fun asBooleanArray() = booleanArrayOf( + library, + appSettings, + sourceSettings, + // SY --> + savedSearches + // SY <-- + ) + + fun anyEnabled() = library || appSettings || sourceSettings /* SY --> */ || savedSearches /* SY <-- */ + companion object { val options = persistentListOf( Entry( @@ -39,6 +50,15 @@ data class RestoreOptions( ), // SY <-- ) + + fun fromBooleanArray(array: BooleanArray) = RestoreOptions( + library = array[0], + appSettings = array[1], + sourceSettings = array[2], + // SY --> + savedSearches = array[3] + // SY <-- + ) } data class Entry( diff --git a/core/build.gradle.kts b/core/build.gradle.kts index cde3bd964..91ea7997f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -37,7 +37,6 @@ dependencies { implementation(libs.unifile) - implementation(kotlinx.reflect) api(kotlinx.coroutines.core) api(kotlinx.serialization.json) api(kotlinx.serialization.json.okio) diff --git a/core/src/main/java/tachiyomi/core/util/lang/BooleanDataClassExtensions.kt b/core/src/main/java/tachiyomi/core/util/lang/BooleanDataClassExtensions.kt deleted file mode 100644 index d781c678f..000000000 --- a/core/src/main/java/tachiyomi/core/util/lang/BooleanDataClassExtensions.kt +++ /dev/null @@ -1,26 +0,0 @@ -package tachiyomi.core.util.lang - -import kotlin.reflect.KProperty1 -import kotlin.reflect.full.declaredMemberProperties -import kotlin.reflect.full.primaryConstructor - -fun T.asBooleanArray(): BooleanArray { - val constructorParams = this::class.primaryConstructor!!.parameters.map { it.name } - val properties = this::class.declaredMemberProperties - .filterIsInstance>() - return constructorParams - .map { param -> properties.find { it.name == param }!!.get(this) } - .toBooleanArray() -} - -inline fun BooleanArray.asDataClass(): T { - val properties = T::class.declaredMemberProperties.filterIsInstance>() - require(properties.size == this.size) { "Boolean array size does not match data class property count" } - return T::class.primaryConstructor!!.call(*this.toTypedArray()) -} - -fun T.anyEnabled(): Boolean { - return this::class.declaredMemberProperties - .filterIsInstance>() - .any { it.get(this) } -} diff --git a/core/src/test/kotlin/tachiyomi/core/util/lang/BooleanDataClassExtensionsTest.kt b/core/src/test/kotlin/tachiyomi/core/util/lang/BooleanDataClassExtensionsTest.kt deleted file mode 100644 index d75e7b3f8..000000000 --- a/core/src/test/kotlin/tachiyomi/core/util/lang/BooleanDataClassExtensionsTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -package tachiyomi.core.util.lang - -import org.junit.jupiter.api.Assertions.assertArrayEquals -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.api.parallel.Execution -import org.junit.jupiter.api.parallel.ExecutionMode - -@Execution(ExecutionMode.CONCURRENT) -class BooleanDataClassExtensionsTest { - - @Test - fun `asBooleanArray converts data class to boolean array`() { - assertArrayEquals(booleanArrayOf(true, false), TestClass(foo = true, bar = false).asBooleanArray()) - assertArrayEquals(booleanArrayOf(false, true), TestClass(foo = false, bar = true).asBooleanArray()) - } - - @Test - fun `asBooleanArray throws error for invalid data classes`() { - assertThrows { - InvalidTestClass(foo = true, bar = "").asBooleanArray() - } - } - - @Test - fun `asDataClass converts from boolean array`() { - assertEquals(booleanArrayOf(true, false).asDataClass(), TestClass(foo = true, bar = false)) - assertEquals(booleanArrayOf(false, true).asDataClass(), TestClass(foo = false, bar = true)) - } - - @Test - fun `asDataClass throws error for invalid boolean array`() { - assertThrows { - booleanArrayOf(true).asDataClass() - } - } - - @Test - fun `anyEnabled returns based on if any boolean property is enabled`() { - assertTrue(TestClass(foo = false, bar = true).anyEnabled()) - assertFalse(TestClass(foo = false, bar = false).anyEnabled()) - } - - @Test - fun `anyEnabled throws error for invalid class`() { - assertThrows { - InvalidTestClass(foo = true, bar = "").anyEnabled() - } - } - - data class TestClass( - val foo: Boolean, - val bar: Boolean, - ) - - data class InvalidTestClass( - val foo: Boolean, - val bar: String, - ) -}