Show detail descriptions in settings

This commit is contained in:
topjohnwu 2020-01-17 17:02:40 +08:00
parent e6f443cb24
commit b95cf9b9a3
3 changed files with 62 additions and 61 deletions

View File

@ -19,19 +19,14 @@ import kotlin.reflect.KProperty
sealed class SettingsItem : ObservableItem<SettingsItem>() {
@Bindable
open val icon: Int = 0
@Bindable
open val title: TransitiveText = TransitiveText.empty
@Bindable
open val description: TransitiveText = TransitiveText.empty
open val icon: Int get() = 0
open val title: TransitiveText get() = TransitiveText.EMPTY
var isEnabled = true
@Bindable get
set(value) {
field = value
notifyChange(BR.enabled)
}
@get:Bindable
open val description: TransitiveText get() = TransitiveText.EMPTY
@get:Bindable
var isEnabled by bindable(true, BR.enabled)
protected open val isFullSpan: Boolean = false
@ -41,8 +36,6 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
// notify only after the callback invocation; callback can invalidate the backing data,
// which wouldn't be recognized with reverse approach
notifyChange(BR.icon)
notifyChange(BR.title)
notifyChange(BR.description)
}
@ -59,6 +52,17 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
override fun itemSameAs(other: SettingsItem) = this === other
override fun contentSameAs(other: SettingsItem) = itemSameAs(other)
protected inline fun <T> bindable(
initialValue: T,
fieldId: Int,
crossinline setter: (T) -> Unit = {}
) = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
setter(newValue)
notifyChange(fieldId)
}
}
// ---
interface Callback {
@ -70,18 +74,13 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
abstract class Value<T> : SettingsItem() {
@get:Bindable
abstract var value: T
@Bindable get
protected inline fun dataObservable(
protected inline fun bindableValue(
initialValue: T,
crossinline setter: (T) -> Unit
) = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
setter(newValue)
notifyChange(BR.value)
}
}
) = bindable(initialValue, BR.value, setter)
}
@ -146,15 +145,15 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
protected val resources get() = get<Resources>()
@Bindable
var entries: Array<out CharSequence> = arrayOf()
private set
@Bindable
var entryValues: Array<out CharSequence> = arrayOf()
private set
@get:Bindable
val selectedEntry
@Bindable get() = entries.getOrNull(value)
get() = entries.getOrNull(value)
fun setValues(
entries: Array<out CharSequence>,
@ -165,8 +164,6 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
this.entries = entries
this.entryValues = values
notifyChange(BR.entries)
notifyChange(BR.entryValues)
notifyChange(BR.selectedEntry)
}
@ -206,4 +203,4 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
}
}
}

View File

@ -12,17 +12,13 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.utils.availableLocales
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.core.utils.refreshLocale
import com.topjohnwu.magisk.core.utils.*
import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.recycler.SettingsItem
import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.superuser.Shell
import java.io.File
@ -36,8 +32,8 @@ object Customization : SettingsItem.Section() {
}
object Language : SettingsItem.Selector() {
override var value by dataObservable(0) {
Config.locale = entryValues.getOrNull(it)?.toString() ?: return@dataObservable
override var value by bindableValue(0) {
Config.locale = entryValues.getOrNull(it)?.toString() ?: return@bindableValue
refreshLocale()
}
@ -108,7 +104,7 @@ fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
object DownloadPath : SettingsItem.Input() {
override var value: String by dataObservable(Config.downloadPath) { Config.downloadPath = it }
override var value: String by bindableValue(Config.downloadPath) { Config.downloadPath = it }
override val title = R.string.settings_download_path_title.asTransitive()
override val intermediate: String?
get() = if (Utils.ensureDownloadPath(result) != null) result else null
@ -130,7 +126,7 @@ object DownloadPath : SettingsItem.Input() {
}
object GridSize : SettingsItem.Selector() {
override var value by dataObservable(Config.listSpanCount - 1) {
override var value by bindableValue(Config.listSpanCount - 1) {
Config.listSpanCount = max(1, min(3, it + 1))
}
@ -146,7 +142,7 @@ object GridSize : SettingsItem.Selector() {
}
object UpdateChannel : SettingsItem.Selector() {
override var value by dataObservable(Config.updateChannel) { Config.updateChannel = it }
override var value by bindableValue(Config.updateChannel) { Config.updateChannel = it }
override val title = R.string.settings_update_channel_title.asTransitive()
init {
@ -163,7 +159,7 @@ object UpdateChannel : SettingsItem.Selector() {
object UpdateChannelUrl : SettingsItem.Input() {
override val title = R.string.settings_update_custom.asTransitive()
override var value: String by dataObservable(Config.customChannelUrl) {
override var value: String by bindableValue(Config.customChannelUrl) {
Config.customChannelUrl = it
}
override val intermediate: String? get() = result
@ -186,7 +182,7 @@ object UpdateChannelUrl : SettingsItem.Input() {
object UpdateChecker : SettingsItem.Toggle() {
override val title = R.string.settings_check_update_title.asTransitive()
override val description = R.string.settings_check_update_summary.asTransitive()
override var value by dataObservable(Config.checkUpdate) {
override var value by bindableValue(Config.checkUpdate) {
Config.checkUpdate = it
Utils.scheduleUpdateCheck(get())
}
@ -204,13 +200,14 @@ object SystemlessHosts : SettingsItem.Blank() {
object Biometrics : SettingsItem.Toggle() {
override val title = R.string.settings_su_biometric_title.asTransitive()
override val description = R.string.settings_su_biometric_summary.asTransitive()
override var value by dataObservable(Config.suBiometric) { Config.suBiometric = it }
override var value by bindableValue(Config.suBiometric) { Config.suBiometric = it }
override var description = R.string.settings_su_biometric_summary.asTransitive()
override fun refresh() {
isEnabled = BiometricHelper.isSupported && Utils.showSuperUser()
if (!isEnabled) {
value = false
description = R.string.no_biometric.asTransitive()
}
}
}
@ -218,7 +215,7 @@ object Biometrics : SettingsItem.Toggle() {
object Reauthenticate : SettingsItem.Toggle() {
override val title = R.string.settings_su_reauth_title.asTransitive()
override val description = R.string.settings_su_reauth_summary.asTransitive()
override var value by dataObservable(Config.suReAuth) { Config.suReAuth = it }
override var value by bindableValue(Config.suReAuth) { Config.suReAuth = it }
override fun refresh() {
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Utils.showSuperUser()
@ -233,9 +230,10 @@ object Magisk : SettingsItem.Section() {
object SafeMode : SettingsItem.Toggle() {
override val title = R.string.settings_safe_mode_title.asTransitive()
override val description = R.string.settings_safe_mode_summary.asTransitive()
override var value by dataObservable(Config.coreOnly) {
if (Config.coreOnly == it) return@dataObservable
// Use old placeholder for now, will update text once native implementation is changed
override val description = R.string.settings_core_only_summary.asTransitive()
override var value by bindableValue(Config.coreOnly) {
if (Config.coreOnly == it) return@bindableValue
Config.coreOnly = it
when {
it -> runCatching { Const.MAGISK_DISABLE_FILE.createNewFile() }
@ -252,7 +250,7 @@ object SafeMode : SettingsItem.Toggle() {
object MagiskHide : SettingsItem.Toggle() {
override val title = R.string.magiskhide.asTransitive()
override val description = R.string.settings_magiskhide_summary.asTransitive()
override var value by dataObservable(Config.magiskHide) {
override var value by bindableValue(Config.magiskHide) {
Config.magiskHide = it
when {
it -> Shell.su("magiskhide --enable").submit()
@ -273,10 +271,10 @@ object Superuser : SettingsItem.Section() {
object AccessMode : SettingsItem.Selector() {
override val title = R.string.superuser_access.asTransitive()
override var value by dataObservable(Config.rootMode) {
override var value by bindableValue(Config.rootMode) {
Config.rootMode = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
?.toInt() ?: return@bindableValue
}
init {
@ -293,11 +291,14 @@ object AccessMode : SettingsItem.Selector() {
object MultiuserMode : SettingsItem.Selector() {
override val title = R.string.multiuser_mode.asTransitive()
override var value by dataObservable(Config.suMultiuserMode) {
override var value by bindableValue(Config.suMultiuserMode) {
Config.suMultiuserMode = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
?.toInt() ?: return@bindableValue
}
private val descArray = resources.getStringArray(R.array.multiuser_summary)
override val description
get() = descArray[value].asTransitive()
init {
setValues(
@ -313,11 +314,14 @@ object MultiuserMode : SettingsItem.Selector() {
object MountNamespaceMode : SettingsItem.Selector() {
override val title = R.string.mount_namespace_mode.asTransitive()
override var value by dataObservable(Config.suMntNamespaceMode) {
override var value by bindableValue(Config.suMntNamespaceMode) {
Config.suMntNamespaceMode = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
?.toInt() ?: return@bindableValue
}
private val descArray = resources.getStringArray(R.array.namespace_summary)
override val description
get() = descArray[value].asTransitive()
init {
setValues(
@ -333,10 +337,10 @@ object MountNamespaceMode : SettingsItem.Selector() {
object AutomaticResponse : SettingsItem.Selector() {
override val title = R.string.auto_response.asTransitive()
override var value by dataObservable(Config.suAutoReponse) {
override var value by bindableValue(Config.suAutoReponse) {
Config.suAutoReponse = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
?.toInt() ?: return@bindableValue
}
init {
@ -353,10 +357,10 @@ object AutomaticResponse : SettingsItem.Selector() {
object RequestTimeout : SettingsItem.Selector() {
override val title = R.string.request_timeout.asTransitive()
override var value by dataObservable(-1) {
override var value by bindableValue(-1) {
Config.suDefaultTimeout = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
?.toInt() ?: return@bindableValue
}
init {
@ -375,10 +379,10 @@ object RequestTimeout : SettingsItem.Selector() {
object SUNotification : SettingsItem.Selector() {
override val title = R.string.superuser_notification.asTransitive()
override var value by dataObservable(Config.suNotification) {
override var value by bindableValue(Config.suNotification) {
Config.suNotification = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
?.toInt() ?: return@bindableValue
}
init {

View File

@ -35,7 +35,7 @@ sealed class TransitiveText {
// ---
companion object {
val empty = String("")
val EMPTY = String("")
}
}
@ -51,4 +51,4 @@ fun TextView.setText(text: TransitiveText) {
}
@InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
fun TextView.getTransitiveText() = text.asTransitive()
fun TextView.getTransitiveText() = text.asTransitive()