mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-13 00:44:16 +01:00
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.
This commit is contained in:
parent
1cdaa761b7
commit
6ab8e1e73d
8 changed files with 38 additions and 97 deletions
|
@ -32,7 +32,6 @@ import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.RestoreOptions
|
import eu.kanade.tachiyomi.data.backup.restore.RestoreOptions
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import tachiyomi.core.util.lang.anyEnabled
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||||
import tachiyomi.presentation.core.components.LazyColumnWithAction
|
import tachiyomi.presentation.core.components.LazyColumnWithAction
|
||||||
|
|
|
@ -24,8 +24,6 @@ import eu.kanade.tachiyomi.util.system.isRunning
|
||||||
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
||||||
import eu.kanade.tachiyomi.util.system.workManager
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.util.lang.asBooleanArray
|
|
||||||
import tachiyomi.core.util.lang.asDataClass
|
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.backup.service.BackupPreferences
|
import tachiyomi.domain.backup.service.BackupPreferences
|
||||||
import tachiyomi.domain.storage.service.StorageManager
|
import tachiyomi.domain.storage.service.StorageManager
|
||||||
|
@ -49,7 +47,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
||||||
|
|
||||||
setForegroundSafely()
|
setForegroundSafely()
|
||||||
|
|
||||||
val options: BackupOptions = inputData.getBooleanArray(OPTIONS_KEY)?.asDataClass()
|
val options = inputData.getBooleanArray(OPTIONS_KEY)?.let { BackupOptions.fromBooleanArray(it) }
|
||||||
?: BackupOptions()
|
?: BackupOptions()
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
|
|
|
@ -15,6 +15,17 @@ data class BackupOptions(
|
||||||
val privateSettings: Boolean = false,
|
val privateSettings: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
fun asBooleanArray() = booleanArrayOf(
|
||||||
|
libraryEntries,
|
||||||
|
categories,
|
||||||
|
chapters,
|
||||||
|
tracking,
|
||||||
|
history,
|
||||||
|
appSettings,
|
||||||
|
sourceSettings,
|
||||||
|
privateSettings,
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val libraryOptions = persistentListOf(
|
val libraryOptions = persistentListOf(
|
||||||
Entry(
|
Entry(
|
||||||
|
@ -66,6 +77,17 @@ data class BackupOptions(
|
||||||
enabled = { it.appSettings || it.sourceSettings },
|
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],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Entry(
|
data class Entry(
|
||||||
|
|
|
@ -20,8 +20,6 @@ import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.i18n.stringResource
|
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.core.util.system.logcat
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
|
|
||||||
|
@ -32,7 +30,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
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) {
|
if (uri == null || options == null) {
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
|
|
|
@ -10,6 +10,14 @@ data class RestoreOptions(
|
||||||
val sourceSettings: Boolean = true,
|
val sourceSettings: Boolean = true,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
fun asBooleanArray() = booleanArrayOf(
|
||||||
|
library,
|
||||||
|
appSettings,
|
||||||
|
sourceSettings,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun anyEnabled() = library || appSettings || sourceSettings
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val options = persistentListOf(
|
val options = persistentListOf(
|
||||||
Entry(
|
Entry(
|
||||||
|
@ -28,6 +36,12 @@ data class RestoreOptions(
|
||||||
setter = { options, enabled -> options.copy(sourceSettings = enabled) },
|
setter = { options, enabled -> options.copy(sourceSettings = enabled) },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun fromBooleanArray(array: BooleanArray) = RestoreOptions(
|
||||||
|
library = array[0],
|
||||||
|
appSettings = array[1],
|
||||||
|
sourceSettings = array[2],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Entry(
|
data class Entry(
|
||||||
|
|
|
@ -33,7 +33,6 @@ dependencies {
|
||||||
|
|
||||||
implementation(libs.unifile)
|
implementation(libs.unifile)
|
||||||
|
|
||||||
implementation(kotlinx.reflect)
|
|
||||||
api(kotlinx.coroutines.core)
|
api(kotlinx.coroutines.core)
|
||||||
api(kotlinx.serialization.json)
|
api(kotlinx.serialization.json)
|
||||||
api(kotlinx.serialization.json.okio)
|
api(kotlinx.serialization.json.okio)
|
||||||
|
|
|
@ -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 : Any> T.asBooleanArray(): BooleanArray {
|
|
||||||
val constructorParams = this::class.primaryConstructor!!.parameters.map { it.name }
|
|
||||||
val properties = this::class.declaredMemberProperties
|
|
||||||
.filterIsInstance<KProperty1<T, Boolean>>()
|
|
||||||
return constructorParams
|
|
||||||
.map { param -> properties.find { it.name == param }!!.get(this) }
|
|
||||||
.toBooleanArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : Any> BooleanArray.asDataClass(): T {
|
|
||||||
val properties = T::class.declaredMemberProperties.filterIsInstance<KProperty1<T, Boolean>>()
|
|
||||||
require(properties.size == this.size) { "Boolean array size does not match data class property count" }
|
|
||||||
return T::class.primaryConstructor!!.call(*this.toTypedArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> T.anyEnabled(): Boolean {
|
|
||||||
return this::class.declaredMemberProperties
|
|
||||||
.filterIsInstance<KProperty1<T, Boolean>>()
|
|
||||||
.any { it.get(this) }
|
|
||||||
}
|
|
|
@ -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<ClassCastException> {
|
|
||||||
InvalidTestClass(foo = true, bar = "").asBooleanArray()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `asDataClass converts from boolean array`() {
|
|
||||||
assertEquals(booleanArrayOf(true, false).asDataClass<TestClass>(), TestClass(foo = true, bar = false))
|
|
||||||
assertEquals(booleanArrayOf(false, true).asDataClass<TestClass>(), TestClass(foo = false, bar = true))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `asDataClass throws error for invalid boolean array`() {
|
|
||||||
assertThrows<IllegalArgumentException> {
|
|
||||||
booleanArrayOf(true).asDataClass<TestClass>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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<ClassCastException> {
|
|
||||||
InvalidTestClass(foo = true, bar = "").anyEnabled()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class TestClass(
|
|
||||||
val foo: Boolean,
|
|
||||||
val bar: Boolean,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class InvalidTestClass(
|
|
||||||
val foo: Boolean,
|
|
||||||
val bar: String,
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in a new issue