Don't hold resources in Settings objects

This commit is contained in:
topjohnwu 2021-04-18 04:14:43 -07:00
parent 1418bc454d
commit 649b49ff45
3 changed files with 39 additions and 49 deletions

View File

@ -3,18 +3,14 @@ package com.topjohnwu.magisk.ui.settings
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.view.View import android.view.View
import androidx.annotation.ArrayRes
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.databinding.Bindable import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ObservableItem import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.utils.TextHolder import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import org.koin.core.component.KoinComponent
sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() { sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() {
@ -141,34 +137,29 @@ sealed class BaseSettingsItem : ObservableItem<BaseSettingsItem>() {
abstract fun getView(context: Context): View abstract fun getView(context: Context): View
} }
abstract class Selector : Value<Int>(), KoinComponent { abstract class Selector : Value<Int>() {
protected val resources get() = get<Resources>() open val entryRes get() = -1
open val descriptionRes get() = entryRes
open fun entries(res: Resources) = res.getArrayOrEmpty(entryRes)
open fun descriptions(res: Resources) = res.getArrayOrEmpty(descriptionRes)
@ArrayRes open val entryRes = -1 override val description = object : TextHolder() {
@ArrayRes open val entryValRes = -1 override fun getText(resources: Resources): CharSequence {
return descriptions(resources).getOrElse(value) { "" }
open val entries get() = resources.getArrayOrEmpty(entryRes) }
open val entryValues get() = resources.getArrayOrEmpty(entryValRes) }
override val description: TextHolder
get() = entries.getOrNull(value)?.asText() ?: TextHolder.EMPTY
private fun Resources.getArrayOrEmpty(id: Int): Array<String> = private fun Resources.getArrayOrEmpty(id: Int): Array<String> =
runCatching { getStringArray(id) }.getOrDefault(emptyArray()) runCatching { getStringArray(id) }.getOrDefault(emptyArray())
override fun onPressed(view: View, callback: Callback) {
if (entries.isEmpty()) return
super.onPressed(view, callback)
}
override fun onPressed(view: View) { override fun onPressed(view: View) {
MagiskDialog(view.context) MagiskDialog(view.context)
.applyTitle(title.getText(resources)) .applyTitle(title.getText(view.resources))
.applyButton(MagiskDialog.ButtonType.NEGATIVE) { .applyButton(MagiskDialog.ButtonType.NEGATIVE) {
titleRes = android.R.string.cancel titleRes = android.R.string.cancel
} }
.applyAdapter(entries) { .applyAdapter(entries(view.resources)) {
value = it value = it
} }
.reveal() .reveal()

View File

@ -1,8 +1,10 @@
package com.topjohnwu.magisk.ui.settings package com.topjohnwu.magisk.ui.settings
import android.content.Context import android.content.Context
import android.content.res.Resources
import android.os.Build import android.os.Build
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import androidx.databinding.Bindable import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
@ -20,7 +22,6 @@ import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.asText import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.utils.set import com.topjohnwu.magisk.utils.set
@ -41,8 +42,17 @@ object Language : BaseSettingsItem.Selector() {
} }
override val title = R.string.language.asText() override val title = R.string.language.asText()
override var entries = emptyArray<String>()
override var entryValues = emptyArray<String>() private var entries = emptyArray<String>()
private var entryValues = emptyArray<String>()
override fun entries(res: Resources) = entries
override fun descriptions(res: Resources) = entries
override fun onPressed(view: View, callback: Callback) {
if (entries.isEmpty()) return
super.onPressed(view, callback)
}
suspend fun loadLanguages(scope: CoroutineScope) { suspend fun loadLanguages(scope: CoroutineScope) {
scope.launch { scope.launch {
@ -137,20 +147,22 @@ object DownloadPath : BaseSettingsItem.Input() {
} }
object UpdateChannel : BaseSettingsItem.Selector() { object UpdateChannel : BaseSettingsItem.Selector() {
override var value = Config.updateChannel override var value = Config.updateChannel.let { if (it < 0) 0 else it }
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.updateChannel = it Config.updateChannel = it
Info.remote = Info.EMPTY_REMOTE Info.remote = Info.EMPTY_REMOTE
} }
override val title = R.string.settings_update_channel_title.asText() override val title = R.string.settings_update_channel_title.asText()
override val entries: Array<String> = resources.getStringArray(R.array.update_channel).let {
if (BuildConfig.VERSION_CODE % 100 == 0) override val entryRes = R.array.update_channel
it.toMutableList().apply { removeAt(Config.Value.CANARY_CHANNEL) }.toTypedArray() override fun entries(res: Resources): Array<String> {
else it return super.entries(res).let {
if (!BuildConfig.DEBUG)
it.copyOfRange(0, Config.Value.CANARY_CHANNEL)
else it
}
} }
override val description
get() = entries.getOrNull(value)?.asText() ?: TextHolder.String(entries[0])
} }
object UpdateChannelUrl : BaseSettingsItem.Input() { object UpdateChannelUrl : BaseSettingsItem.Input() {
@ -272,15 +284,13 @@ object AccessMode : BaseSettingsItem.Selector() {
object MultiuserMode : BaseSettingsItem.Selector() { object MultiuserMode : BaseSettingsItem.Selector() {
override val title = R.string.multiuser_mode.asText() override val title = R.string.multiuser_mode.asText()
override val entryRes = R.array.multiuser_mode override val entryRes = R.array.multiuser_mode
override val descriptionRes = R.array.multiuser_summary
override var value = Config.suMultiuserMode override var value = Config.suMultiuserMode
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suMultiuserMode = it Config.suMultiuserMode = it
} }
override val description
get() = resources.getStringArray(R.array.multiuser_summary)[value].asText()
override fun refresh() { override fun refresh() {
isEnabled = Const.USER_ID == 0 isEnabled = Const.USER_ID == 0
} }
@ -289,14 +299,12 @@ object MultiuserMode : BaseSettingsItem.Selector() {
object MountNamespaceMode : BaseSettingsItem.Selector() { object MountNamespaceMode : BaseSettingsItem.Selector() {
override val title = R.string.mount_namespace_mode.asText() override val title = R.string.mount_namespace_mode.asText()
override val entryRes = R.array.namespace override val entryRes = R.array.namespace
override val descriptionRes = R.array.namespace_summary
override var value = Config.suMntNamespaceMode override var value = Config.suMntNamespaceMode
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suMntNamespaceMode = it Config.suMntNamespaceMode = it
} }
override val description
get() = resources.getStringArray(R.array.namespace_summary)[value].asText()
} }
object AutomaticResponse : BaseSettingsItem.Selector() { object AutomaticResponse : BaseSettingsItem.Selector() {
@ -312,15 +320,15 @@ object AutomaticResponse : BaseSettingsItem.Selector() {
object RequestTimeout : BaseSettingsItem.Selector() { object RequestTimeout : BaseSettingsItem.Selector() {
override val title = R.string.request_timeout.asText() override val title = R.string.request_timeout.asText()
override val entryRes = R.array.request_timeout override val entryRes = R.array.request_timeout
override val entryValRes = R.array.request_timeout_value
private val entryValues = listOf(10, 15, 20, 30, 45, 60)
override var value = selected override var value = selected
set(value) = setV(value, field, { field = it }) { set(value) = setV(value, field, { field = it }) {
Config.suDefaultTimeout = entryValues[it].toInt() Config.suDefaultTimeout = entryValues[it]
} }
private val selected: Int private val selected: Int
get() = entryValues.indexOfFirst { it.toInt() == Config.suDefaultTimeout } get() = entryValues.indexOfFirst { it == Config.suDefaultTimeout }
} }
object SUNotification : BaseSettingsItem.Selector() { object SUNotification : BaseSettingsItem.Selector() {

View File

@ -25,15 +25,6 @@
<item>@string/settings_su_request_60</item> <item>@string/settings_su_request_60</item>
</string-array> </string-array>
<string-array name="request_timeout_value">
<item>10</item>
<item>15</item>
<item>20</item>
<item>30</item>
<item>45</item>
<item>60</item>
</string-array>
<string-array name="auto_response"> <string-array name="auto_response">
<item>@string/prompt</item> <item>@string/prompt</item>
<item>@string/deny</item> <item>@string/deny</item>