Update SettingsItems

This commit is contained in:
topjohnwu 2020-07-12 06:15:32 -07:00
parent 2c12fe6eb2
commit 45fabf8e03
3 changed files with 42 additions and 57 deletions

View File

@ -11,6 +11,7 @@ import com.topjohnwu.magisk.core.magiskdb.SettingsDao
import com.topjohnwu.magisk.core.magiskdb.StringDao import com.topjohnwu.magisk.core.magiskdb.StringDao
import com.topjohnwu.magisk.core.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.Utils import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.magisk.core.utils.refreshLocale
import com.topjohnwu.magisk.data.repository.DBConfig import com.topjohnwu.magisk.data.repository.DBConfig
import com.topjohnwu.magisk.di.Protected import com.topjohnwu.magisk.di.Protected
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
@ -125,7 +126,13 @@ object Config : PreferenceModel, DBConfig {
var showSystemApp by preference(Key.SHOW_SYSTEM_APP, false) var showSystemApp by preference(Key.SHOW_SYSTEM_APP, false)
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "") var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
var locale by preference(Key.LOCALE, "") private var localePrefs by preference(Key.LOCALE, "")
var locale
get() = localePrefs
set(value) {
localePrefs = value
refreshLocale()
}
var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB) var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB)
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER) var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER)

View File

@ -13,11 +13,10 @@ 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.utils.TransitiveText import com.topjohnwu.magisk.utils.TransitiveText
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.get import org.koin.core.get
import kotlin.properties.ObservableProperty
import kotlin.reflect.KProperty
sealed class SettingsItem : ObservableItem<SettingsItem>() { sealed class SettingsItem : ObservableItem<SettingsItem>() {
@ -28,17 +27,13 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
open val description: TransitiveText get() = TransitiveText.EMPTY open val description: TransitiveText get() = TransitiveText.EMPTY
@get:Bindable @get:Bindable
var isEnabled by bindable(true, BR.enabled) var isEnabled by observable(true, BR.enabled)
protected open val isFullSpan get() = false protected open val isFullSpan get() = false
@CallSuper @CallSuper
open fun onPressed(view: View, callback: Callback) { open fun onPressed(view: View, callback: Callback) {
callback.onItemChanged(view, this) callback.onItemChanged(view, this)
// notify only after the callback invocation; callback can invalidate the backing data,
// which wouldn't be recognized with reverse approach
notifyPropertyChanged(BR.description)
} }
open fun refresh() {} open fun refresh() {}
@ -54,17 +49,6 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
override fun itemSameAs(other: SettingsItem) = this === other override fun itemSameAs(other: SettingsItem) = this === other
override fun contentSameAs(other: SettingsItem) = itemSameAs(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)
notifyPropertyChanged(fieldId)
}
}
// --- // ---
interface Callback { interface Callback {
@ -79,10 +63,11 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
@get:Bindable @get:Bindable
abstract var value: T abstract var value: T
protected inline fun bindableValue( protected inline fun <reified T> value(
initialValue: T, initialValue: T,
crossinline setter: (T) -> Unit vararg fieldIds: Int,
) = bindable(initialValue, BR.value, setter) crossinline setter: (T) -> Unit = {}
) = observable(initialValue, BR.value, *fieldIds, afterChanged = setter)
} }
@ -157,6 +142,11 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
val selectedEntry val selectedEntry
get() = entries.getOrNull(value) get() = entries.getOrNull(value)
/* override */ protected inline fun value(
initialValue: Int,
crossinline setter: (Int) -> Unit
) = observable(initialValue, BR.value, BR.selectedEntry, BR.description, afterChanged = setter)
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())

View File

@ -11,13 +11,17 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.utils.* import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.magisk.core.utils.availableLocales
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding 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.model.entity.recycler.SettingsItem import com.topjohnwu.magisk.model.entity.recycler.SettingsItem
import com.topjohnwu.magisk.utils.asTransitive import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -30,9 +34,8 @@ object Customization : SettingsItem.Section() {
} }
object Language : SettingsItem.Selector() { object Language : SettingsItem.Selector() {
override var value by bindableValue(0) { override var value by value(-1) {
Config.locale = entryValues[it] Config.locale = entryValues[it]
refreshLocale()
} }
override val title = R.string.language.asTransitive() override val title = R.string.language.asTransitive()
@ -76,12 +79,7 @@ object Hide : SettingsItem.Input() {
override val title = R.string.settings_hide_manager_title.asTransitive() override val title = R.string.settings_hide_manager_title.asTransitive()
override val description = R.string.settings_hide_manager_summary.asTransitive() override val description = R.string.settings_hide_manager_summary.asTransitive()
override val showStrip = false override val showStrip = false
override var value: String = resources.getString(R.string.re_app_name) override var value by value(resources.getString(R.string.re_app_name), BR.error)
set(value) {
field = value
notifyPropertyChanged(BR.value)
notifyPropertyChanged(BR.error)
}
@get:Bindable @get:Bindable
val isError get() = value.length > 14 || value.isBlank() val isError get() = value.length > 14 || value.isBlank()
@ -103,29 +101,23 @@ fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
object DownloadPath : SettingsItem.Input() { object DownloadPath : SettingsItem.Input() {
override var value: String by bindableValue(Config.downloadPath) { Config.downloadPath = it } override var value: String by value(Config.downloadPath) { Config.downloadPath = it }
override val title = R.string.settings_download_path_title.asTransitive() override val title = R.string.settings_download_path_title.asTransitive()
override val intermediate: String? override val intermediate: String?
get() = if (Utils.ensureDownloadPath(result) != null) result else null get() = if (Utils.ensureDownloadPath(result) != null) result else null
@get:Bindable @get:Bindable
var result = value var result by observable(value, BR.result, BR.path)
set(value) {
field = value
notifyPropertyChanged(BR.result)
notifyPropertyChanged(BR.path)
}
@get:Bindable @get:Bindable
val path val path get() = File(Environment.getExternalStorageDirectory(), result).absolutePath.orEmpty()
get() = File(Environment.getExternalStorageDirectory(), result).absolutePath.orEmpty()
override fun getView(context: Context) = DialogSettingsDownloadPathBinding override fun getView(context: Context) = DialogSettingsDownloadPathBinding
.inflate(LayoutInflater.from(context)).also { it.data = this }.root .inflate(LayoutInflater.from(context)).also { it.data = this }.root
} }
object UpdateChannel : SettingsItem.Selector() { object UpdateChannel : SettingsItem.Selector() {
override var value by bindableValue(Config.updateChannel) { Config.updateChannel = it } override var value by value(Config.updateChannel) { Config.updateChannel = it }
override val title = R.string.settings_update_channel_title.asTransitive() override val title = R.string.settings_update_channel_title.asTransitive()
override val entries get() = resources.getStringArray(R.array.update_channel).let { override val entries get() = resources.getStringArray(R.array.update_channel).let {
@ -136,15 +128,11 @@ object UpdateChannel : SettingsItem.Selector() {
object UpdateChannelUrl : SettingsItem.Input() { object UpdateChannelUrl : SettingsItem.Input() {
override val title = R.string.settings_update_custom.asTransitive() override val title = R.string.settings_update_custom.asTransitive()
override var value by bindableValue(Config.customChannelUrl) { Config.customChannelUrl = it } override var value by value(Config.customChannelUrl) { Config.customChannelUrl = it }
override val intermediate: String? get() = result override val intermediate: String? get() = result
@get:Bindable @get:Bindable
var result = value var result by observable(value, BR.result)
set(value) {
field = value
notifyPropertyChanged(BR.result)
}
override fun refresh() { override fun refresh() {
isEnabled = UpdateChannel.value == Config.Value.CUSTOM_CHANNEL isEnabled = UpdateChannel.value == Config.Value.CUSTOM_CHANNEL
@ -157,7 +145,7 @@ object UpdateChannelUrl : SettingsItem.Input() {
object UpdateChecker : SettingsItem.Toggle() { object UpdateChecker : SettingsItem.Toggle() {
override val title = R.string.settings_check_update_title.asTransitive() override val title = R.string.settings_check_update_title.asTransitive()
override val description = R.string.settings_check_update_summary.asTransitive() override val description = R.string.settings_check_update_summary.asTransitive()
override var value by bindableValue(Config.checkUpdate) { override var value by value(Config.checkUpdate) {
Config.checkUpdate = it Config.checkUpdate = it
Utils.scheduleUpdateCheck(get()) Utils.scheduleUpdateCheck(get())
} }
@ -171,7 +159,7 @@ object SystemlessHosts : SettingsItem.Blank() {
object Biometrics : SettingsItem.Toggle() { object Biometrics : SettingsItem.Toggle() {
override val title = R.string.settings_su_biometric_title.asTransitive() override val title = R.string.settings_su_biometric_title.asTransitive()
override var value by bindableValue(Config.suBiometric) { Config.suBiometric = it } override var value by value(Config.suBiometric) { Config.suBiometric = it }
override var description = R.string.settings_su_biometric_summary.asTransitive() override var description = R.string.settings_su_biometric_summary.asTransitive()
override fun refresh() { override fun refresh() {
@ -186,7 +174,7 @@ object Biometrics : SettingsItem.Toggle() {
object Reauthenticate : SettingsItem.Toggle() { object Reauthenticate : SettingsItem.Toggle() {
override val title = R.string.settings_su_reauth_title.asTransitive() override val title = R.string.settings_su_reauth_title.asTransitive()
override val description = R.string.settings_su_reauth_summary.asTransitive() override val description = R.string.settings_su_reauth_summary.asTransitive()
override var value by bindableValue(Config.suReAuth) { Config.suReAuth = it } override var value by value(Config.suReAuth) { Config.suReAuth = it }
override fun refresh() { override fun refresh() {
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Utils.showSuperUser() isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Utils.showSuperUser()
@ -202,7 +190,7 @@ object Magisk : SettingsItem.Section() {
object MagiskHide : SettingsItem.Toggle() { object MagiskHide : SettingsItem.Toggle() {
override val title = R.string.magiskhide.asTransitive() override val title = R.string.magiskhide.asTransitive()
override val description = R.string.settings_magiskhide_summary.asTransitive() override val description = R.string.settings_magiskhide_summary.asTransitive()
override var value by bindableValue(Config.magiskHide) { override var value by value(Config.magiskHide) {
Config.magiskHide = it Config.magiskHide = it
when { when {
it -> Shell.su("magiskhide --enable").submit() it -> Shell.su("magiskhide --enable").submit()
@ -222,7 +210,7 @@ object AccessMode : SettingsItem.Selector() {
override val entryRes = R.array.su_access override val entryRes = R.array.su_access
override val entryValRes = R.array.value_array override val entryValRes = R.array.value_array
override var value by bindableValue(Config.rootMode) { override var value by value(Config.rootMode) {
Config.rootMode = entryValues[it].toInt() Config.rootMode = entryValues[it].toInt()
} }
} }
@ -232,7 +220,7 @@ object MultiuserMode : SettingsItem.Selector() {
override val entryRes = R.array.multiuser_mode override val entryRes = R.array.multiuser_mode
override val entryValRes = R.array.value_array override val entryValRes = R.array.value_array
override var value by bindableValue(Config.suMultiuserMode) { override var value by value(Config.suMultiuserMode) {
Config.suMultiuserMode = entryValues[it].toInt() Config.suMultiuserMode = entryValues[it].toInt()
} }
@ -249,7 +237,7 @@ object MountNamespaceMode : SettingsItem.Selector() {
override val entryRes = R.array.namespace override val entryRes = R.array.namespace
override val entryValRes = R.array.value_array override val entryValRes = R.array.value_array
override var value by bindableValue(Config.suMntNamespaceMode) { override var value by value(Config.suMntNamespaceMode) {
Config.suMntNamespaceMode = entryValues[it].toInt() Config.suMntNamespaceMode = entryValues[it].toInt()
} }
@ -262,7 +250,7 @@ object AutomaticResponse : SettingsItem.Selector() {
override val entryRes = R.array.auto_response override val entryRes = R.array.auto_response
override val entryValRes = R.array.value_array override val entryValRes = R.array.value_array
override var value by bindableValue(Config.suAutoReponse) { override var value by value(Config.suAutoReponse) {
Config.suAutoReponse = entryValues[it].toInt() Config.suAutoReponse = entryValues[it].toInt()
} }
} }
@ -272,7 +260,7 @@ object RequestTimeout : SettingsItem.Selector() {
override val entryRes = R.array.request_timeout override val entryRes = R.array.request_timeout
override val entryValRes = R.array.request_timeout_value override val entryValRes = R.array.request_timeout_value
override var value by bindableValue(selected) { override var value by value(selected) {
Config.suDefaultTimeout = entryValues[it].toInt() Config.suDefaultTimeout = entryValues[it].toInt()
} }
@ -285,7 +273,7 @@ object SUNotification : SettingsItem.Selector() {
override val entryRes = R.array.su_notification override val entryRes = R.array.su_notification
override val entryValRes = R.array.value_array override val entryValRes = R.array.value_array
override var value by bindableValue(Config.suNotification) { override var value by value(Config.suNotification) {
Config.suNotification = entryValues[it].toInt() Config.suNotification = entryValues[it].toInt()
} }
} }