Reduce usage of delegation

This commit is contained in:
topjohnwu 2020-07-15 01:21:57 -07:00
parent ba31c6b625
commit 6c6368fd81
15 changed files with 226 additions and 213 deletions

View File

@ -7,17 +7,21 @@ import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ktx.timeDateFormat
import com.topjohnwu.magisk.ktx.toTime
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
class LogItem(val item: MagiskLog) : ObservableItem<LogItem>() {
override val layoutRes = R.layout.item_log_access_md2
val date = item.time.toTime(timeDateFormat)
@get:Bindable
var isTop by observable(false, BR.top)
var isTop = false
set(value) = set(value, field, { field = it }, BR.top)
@get:Bindable
var isBottom by observable(false, BR.bottom)
var isBottom = false
set(value) = set(value, field, { field = it }, BR.bottom)
override fun itemSameAs(other: LogItem) = item.appName == other.item.appName

View File

@ -11,7 +11,7 @@ import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.ui.module.ModuleViewModel
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
object InstallModule : ComparableRvItem<InstallModule>() {
override val layoutRes = R.layout.item_module_download
@ -34,11 +34,16 @@ class SectionTitle(
override val layoutRes = R.layout.item_section_md2
@get:Bindable
var button by observable(_button, BR.button)
var button = _button
set(value) = set(value, field, { field = it }, BR.button)
@get:Bindable
var icon by observable(_icon, BR.icon)
var icon = _icon
set(value) = set(value, field, { field = it }, BR.icon)
@get:Bindable
var hasButton by observable(_button != 0 && _icon != 0, BR.hasButton)
var hasButton = _button != 0 && _icon != 0
set(value) = set(value, field, { field = it }, BR.hasButton)
override fun onBindingBound(binding: ViewDataBinding) {
super.onBindingBound(binding)
@ -54,9 +59,13 @@ sealed class RepoItem(val item: Repo) : ObservableItem<RepoItem>() {
override val layoutRes: Int = R.layout.item_repo_md2
@get:Bindable
var progress by observable(0, BR.progress)
var progress = 0
set(value) = set(value, field, { field = it }, BR.progress)
@get:Bindable
var isUpdate by observable(false, BR.update)
var isUpdate = false
set(value) = set(value, field, { field = it }, BR.update)
override fun contentSameAs(other: RepoItem): Boolean = item == other.item
override fun itemSameAs(other: RepoItem): Boolean = item.id == other.item.id
@ -75,7 +84,8 @@ class ModuleItem(val item: Module) : ObservableItem<ModuleItem>(), Observable {
override val layoutRes = R.layout.item_module_md2
@get:Bindable
var repo: Repo? by observable(null, BR.repo)
var repo: Repo? = null
set(value) = set(value, field, { field = it }, BR.repo)
@get:Bindable
var isEnabled

View File

@ -13,7 +13,7 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ObservableItem
import com.topjohnwu.magisk.utils.TransitiveText
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.magisk.view.MagiskDialog
import org.koin.core.KoinComponent
import org.koin.core.get
@ -27,7 +27,8 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
open val description: TransitiveText get() = TransitiveText.EMPTY
@get:Bindable
var isEnabled by observable(true, BR.enabled)
var isEnabled = true
set(value) = set(value, field, { field = it }, BR.enabled)
protected open val isFullSpan get() = false
@ -63,12 +64,15 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
@get:Bindable
abstract var value: T
protected inline fun <reified T> value(
initialValue: T,
vararg fieldIds: Int,
crossinline setter: (T) -> Unit = {}
) = observable(initialValue, BR.value, *fieldIds, afterChanged = setter)
protected inline fun <reified T> setV(
new: T, old: T, setter: (T) -> Unit, vararg fieldIds: Int) {
set(new, old, setter, BR.value, *fieldIds)
}
protected inline fun <reified T> setV(
new: T, old: T, setter: (T) -> Unit, afterChanged: (T) -> Unit = {}) {
set(new, old, setter, BR.value, afterChanged = afterChanged)
}
}
abstract class Toggle : Value<Boolean>() {
@ -142,10 +146,10 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
val selectedEntry
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)
protected inline fun <reified T> setS(
new: T, old: T, setter: (T) -> Unit, afterChanged: (T) -> Unit = {}) {
set(new, old, setter, BR.value, BR.selectedEntry, BR.description, afterChanged = afterChanged)
}
private fun Resources.getArrayOrEmpty(id: Int): Array<String> =
runCatching { getStringArray(id) }.getOrDefault(emptyArray())

View File

@ -17,7 +17,7 @@ import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.model.navigation.NavigationWrapper
import com.topjohnwu.magisk.utils.ObservableHost
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Job
import org.koin.core.KoinComponent
@ -42,9 +42,11 @@ abstract class BaseViewModel(
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
@get:Bindable
var insets by observable(Insets.NONE, BR.insets)
var insets = Insets.NONE
set(value) = set(value, field, { field = it }, BR.insets)
var state by observable(initialState, BR.loading, BR.loaded, BR.loadFailed)
var state= initialState
set(value) = set(value, field, { field = it }, BR.loading, BR.loaded, BR.loadFailed)
private val _viewEvents = MutableLiveData<ViewEvent>()
private var runningJob: Job? = null

View File

@ -20,7 +20,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.ui.base.diffListOf
import com.topjohnwu.magisk.ui.base.itemBindingOf
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -34,9 +34,12 @@ class FlashViewModel(
) : BaseViewModel() {
@get:Bindable
var showReboot by observable(Shell.rootAccess(), BR.showReboot)
var showReboot = Shell.rootAccess()
set(value) = set(value, field, { field = it }, BR.showReboot)
@get:Bindable
var behaviorText by observable(resources.getString(R.string.flashing), BR.behaviorText)
var behaviorText = resources.getString(R.string.flashing)
set(value) = set(value, field, { field = it }, BR.behaviorText)
val adapter = BindingAdapter<ConsoleItem>()
val items = diffListOf<ConsoleItem>()

View File

@ -17,7 +17,7 @@ import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.ui.base.Queryable
import com.topjohnwu.magisk.ui.base.filterableListOf
import com.topjohnwu.magisk.ui.base.itemBindingOf
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -29,14 +29,16 @@ class HideViewModel(
override val queryDelay = 1000L
@get:Bindable
var isShowSystem by observable(false, BR.showSystem) {
submitQuery()
}
var isShowSystem = false
set(value) = set(value, field, { field = it }, BR.showSystem){
submitQuery()
}
@get:Bindable
var query by observable("", BR.query) {
submitQuery()
}
var query = ""
set(value) = set(value, field, { field = it }, BR.query){
submitQuery()
}
val items = filterableListOf<HideItem>()
val itemBinding = itemBindingOf<HideItem> {

View File

@ -27,7 +27,7 @@ import com.topjohnwu.magisk.model.events.dialog.ManagerInstallDialog
import com.topjohnwu.magisk.model.events.dialog.UninstallDialog
import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.ui.base.itemBindingOf
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch
import me.tatarka.bindingcollectionadapter2.BR
@ -42,25 +42,37 @@ class HomeViewModel(
) : BaseViewModel() {
@get:Bindable
var isNoticeVisible by observable(Config.safetyNotice, BR.noticeVisible)
var isNoticeVisible = Config.safetyNotice
set(value) = set(value, field, { field = it }, BR.noticeVisible)
@get:Bindable
var stateMagisk by observable(MagiskState.LOADING, BR.stateMagisk)
var stateMagisk = MagiskState.LOADING
set(value) = set(value, field, { field = it }, BR.stateMagisk)
@get:Bindable
var stateManager by observable(MagiskState.LOADING, BR.stateManager)
var stateManager = MagiskState.LOADING
set(value) = set(value, field, { field = it }, BR.stateManager)
@get:Bindable
var magiskRemoteVersion by observable(R.string.loading.res(), BR.magiskRemoteVersion)
var magiskRemoteVersion = R.string.loading.res()
set(value) = set(value, field, { field = it }, BR.magiskRemoteVersion)
val magiskInstalledVersion get() =
"${Info.env.magiskVersionString} (${Info.env.magiskVersionCode})"
val magiskMode get() = R.string.home_status_normal.res()
@get:Bindable
var managerRemoteVersion by observable(R.string.loading.res(), BR.managerRemoteVersion)
var managerRemoteVersion = R.string.loading.res()
set(value) = set(value, field, { field = it }, BR.managerRemoteVersion)
val managerInstalledVersion = Info.stub?.let {
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) (${it.version})"
} ?: "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
val statePackageName = packageName
@get:Bindable
var stateManagerProgress by observable(0, BR.stateManagerProgress)
var stateManagerProgress = 0
set(value) = set(value, field, { field = it }, BR.stateManagerProgress)
val items = listOf(DeveloperItem.Mainline, DeveloperItem.App, DeveloperItem.Project)
val itemBinding = itemBindingOf<HomeItem> {

View File

@ -16,7 +16,7 @@ import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.events.RequestFileEvent
import com.topjohnwu.magisk.model.events.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch
import org.koin.core.get
@ -30,25 +30,34 @@ class InstallViewModel(
val isAB get() = Info.isAB
@get:Bindable
var step by observable(0, BR.step)
var step = 0
set(value) = set(value, field, { field = it }, BR.step)
@get:Bindable
var method by observable(-1, BR.method) {
when (it) {
R.id.method_patch -> {
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
RequestFileEvent().publish()
}
R.id.method_inactive_slot -> {
SecondSlotWarningDialog().publish()
var method = -1
set(value) = set(value, field, { field = it }, BR.method) {
when (it) {
R.id.method_patch -> {
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
RequestFileEvent().publish()
}
R.id.method_inactive_slot -> {
SecondSlotWarningDialog().publish()
}
}
}
}
@get:Bindable
var progress by observable(0, BR.progress)
var progress = 0
set(value) = set(value, field, { field = it }, BR.progress)
@get:Bindable
var data by observable(null as Uri?, BR.data)
var data: Uri? = null
set(value) = set(value, field, { field = it }, BR.data)
@get:Bindable
var notes by observable("", BR.notes)
var notes = ""
set(value) = set(value, field, { field = it }, BR.notes)
init {
RemoteFileService.reset()

View File

@ -13,7 +13,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.ui.base.diffListOf
import com.topjohnwu.magisk.ui.base.itemBindingOf
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -41,7 +41,8 @@ class LogViewModel(
// --- magisk log
@get:Bindable
var consoleText by observable(" ", BR.consoleText)
var consoleText= " "
set(value) = set(value, field, { field = it }, BR.consoleText)
override fun refresh() = viewModelScope.launch {
consoleText = repo.fetchMagiskLogs()

View File

@ -23,7 +23,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.model.events.dialog.ModuleInstallDialog
import com.topjohnwu.magisk.ui.base.*
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.*
import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
import kotlin.math.roundToInt
@ -53,17 +53,21 @@ class ModuleViewModel(
private var remoteJob: Job? = null
@get:Bindable
var isRemoteLoading by observable(false, BR.remoteLoading)
var isRemoteLoading = false
set(value) = set(value, field, { field = it }, BR.remoteLoading)
@get:Bindable
var query by observable("", BR.query) {
submitQuery()
// Yes we do lie about the search being loaded
searchLoading = true
}
var query = ""
set(value) = set(value, field, { field = it }, BR.query) {
submitQuery()
// Yes we do lie about the search being loaded
searchLoading = true
}
@get:Bindable
var searchLoading by observable(false, BR.searchLoading)
var searchLoading = false
set(value) = set(value, field, { field = it }, BR.searchLoading)
val itemsSearch = diffListOf<RepoItem>()
val itemSearchBinding = itemBindingOf<RepoItem> {
it.bindExtra(BR.viewModel, this)

View File

@ -6,7 +6,7 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.model.events.CheckSafetyNetEvent
import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import org.json.JSONObject
enum class SafetyNetState {
@ -21,13 +21,20 @@ data class SafetyNetResult(
class SafetynetViewModel : BaseViewModel() {
@get:Bindable
var safetyNetTitle by observable(R.string.empty, BR.safetyNetTitle)
var safetyNetTitle = R.string.empty
set(value) = set(value, field, { field = it }, BR.safetyNetTitle)
@get:Bindable
var ctsState by observable(false, BR.ctsState)
var ctsState = false
set(value) = set(value, field, { field = it }, BR.ctsState)
@get:Bindable
var basicIntegrityState by observable(false, BR.basicIntegrityState)
var basicIntegrityState = false
set(value) = set(value, field, { field = it }, BR.basicIntegrityState)
@get:Bindable
var evalType by observable("")
var evalType = ""
set(value) = set(value, field, { field = it }, BR.evalType)
@get:Bindable
val isChecking get() = currentState == LOADING
@ -36,7 +43,8 @@ class SafetynetViewModel : BaseViewModel() {
@get:Bindable
val isSuccess get() = currentState == PASS
private var currentState by observable(IDLE, BR.checking, BR.failed, BR.success)
private var currentState = IDLE
set(value) = set(value, field, { field = it }, BR.checking, BR.failed, BR.success)
init {
cachedResult?.also {

View File

@ -21,7 +21,7 @@ import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.model.entity.recycler.SettingsItem
import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@ -34,9 +34,10 @@ object Customization : SettingsItem.Section() {
}
object Language : SettingsItem.Selector() {
override var value by value(-1) {
Config.locale = entryValues[it]
}
override var value = -1
set(value) = setS(value, field, { field = it }) {
Config.locale = entryValues[it]
}
override val title = R.string.language.asTransitive()
override var entries = emptyArray<String>()
@ -49,7 +50,6 @@ object Language : SettingsItem.Selector() {
entryValues = values
val selectedLocale = currentLocale.getDisplayName(currentLocale)
value = names.indexOfFirst { it == selectedLocale }.let { if (it == -1) 0 else it }
notifyPropertyChanged(BR.selectedEntry)
}
}
}
@ -79,7 +79,8 @@ object Hide : SettingsItem.Input() {
override val title = R.string.settings_hide_manager_title.asTransitive()
override val description = R.string.settings_hide_manager_summary.asTransitive()
override val showStrip = false
override var value by value(resources.getString(R.string.re_app_name), BR.error)
override var value = resources.getString(R.string.re_app_name)
set(value) = setV(value, field, { field = it }, BR.error)
@get:Bindable
val isError get() = value.length > 14 || value.isBlank()
@ -101,13 +102,15 @@ fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
object DownloadPath : SettingsItem.Input() {
override var value: String by value(Config.downloadPath) { Config.downloadPath = it }
override var value = Config.downloadPath
set(value) = setV(value, field, { field = it }) { 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
@get:Bindable
var result by observable(value, BR.result, BR.path)
var result = value
set(value) = set(value, field, { field = it }, BR.result, BR.path)
@get:Bindable
val path get() = File(Environment.getExternalStorageDirectory(), result).absolutePath.orEmpty()
@ -117,7 +120,8 @@ object DownloadPath : SettingsItem.Input() {
}
object UpdateChannel : SettingsItem.Selector() {
override var value by value(Config.updateChannel) { Config.updateChannel = it }
override var value = Config.updateChannel
set(value) = setS(value, field, { field = it }) { Config.updateChannel = it }
override val title = R.string.settings_update_channel_title.asTransitive()
override val entries get() = resources.getStringArray(R.array.update_channel).let {
@ -128,11 +132,13 @@ object UpdateChannel : SettingsItem.Selector() {
object UpdateChannelUrl : SettingsItem.Input() {
override val title = R.string.settings_update_custom.asTransitive()
override var value by value(Config.customChannelUrl) { Config.customChannelUrl = it }
override var value = Config.customChannelUrl
set(value) = setV(value, field, { field = it }) { Config.customChannelUrl = it }
override val intermediate: String? get() = result
@get:Bindable
var result by observable(value, BR.result)
var result = value
set(value) = set(value, field, { field = it }, BR.result)
override fun refresh() {
isEnabled = UpdateChannel.value == Config.Value.CUSTOM_CHANNEL
@ -145,10 +151,11 @@ 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 value(Config.checkUpdate) {
Config.checkUpdate = it
Utils.scheduleUpdateCheck(get())
}
override var value = Config.checkUpdate
set(value) = setV(value, field, { field = it }) {
Config.checkUpdate = it
Utils.scheduleUpdateCheck(get())
}
}
// check whether is module already installed beforehand?
@ -159,7 +166,8 @@ object SystemlessHosts : SettingsItem.Blank() {
object Biometrics : SettingsItem.Toggle() {
override val title = R.string.settings_su_biometric_title.asTransitive()
override var value by value(Config.suBiometric) { Config.suBiometric = it }
override var value = Config.suBiometric
set(value) = setV(value, field, { field = it }) { Config.suBiometric = it }
override var description = R.string.settings_su_biometric_summary.asTransitive()
override fun refresh() {
@ -174,7 +182,8 @@ 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 value(Config.suReAuth) { Config.suReAuth = it }
override var value = Config.suReAuth
set(value) = setV(value, field, { field = it }) { Config.suReAuth = it }
override fun refresh() {
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Utils.showSuperUser()
@ -190,13 +199,14 @@ object Magisk : SettingsItem.Section() {
object MagiskHide : SettingsItem.Toggle() {
override val title = R.string.magiskhide.asTransitive()
override val description = R.string.settings_magiskhide_summary.asTransitive()
override var value by value(Config.magiskHide) {
Config.magiskHide = it
when {
it -> Shell.su("magiskhide --enable").submit()
else -> Shell.su("magiskhide --disable").submit()
override var value = Config.magiskHide
set(value) = setV(value, field, { field = it }) {
Config.magiskHide = it
when {
it -> Shell.su("magiskhide --enable").submit()
else -> Shell.su("magiskhide --disable").submit()
}
}
}
}
// --- Superuser
@ -210,9 +220,10 @@ object AccessMode : SettingsItem.Selector() {
override val entryRes = R.array.su_access
override val entryValRes = R.array.value_array
override var value by value(Config.rootMode) {
Config.rootMode = entryValues[it].toInt()
}
override var value = Config.rootMode
set(value) = setS(value, field, { field = it }) {
Config.rootMode = entryValues[it].toInt()
}
}
object MultiuserMode : SettingsItem.Selector() {
@ -220,9 +231,10 @@ object MultiuserMode : SettingsItem.Selector() {
override val entryRes = R.array.multiuser_mode
override val entryValRes = R.array.value_array
override var value by value(Config.suMultiuserMode) {
Config.suMultiuserMode = entryValues[it].toInt()
}
override var value = Config.suMultiuserMode
set(value) = setS(value, field, { field = it }) {
Config.suMultiuserMode = entryValues[it].toInt()
}
override val description
get() = resources.getStringArray(R.array.multiuser_summary)[value].asTransitive()
@ -237,9 +249,10 @@ object MountNamespaceMode : SettingsItem.Selector() {
override val entryRes = R.array.namespace
override val entryValRes = R.array.value_array
override var value by value(Config.suMntNamespaceMode) {
Config.suMntNamespaceMode = entryValues[it].toInt()
}
override var value = Config.suMntNamespaceMode
set(value) = setS(value, field, { field = it }) {
Config.suMntNamespaceMode = entryValues[it].toInt()
}
override val description
get() = resources.getStringArray(R.array.namespace_summary)[value].asTransitive()
@ -250,9 +263,10 @@ object AutomaticResponse : SettingsItem.Selector() {
override val entryRes = R.array.auto_response
override val entryValRes = R.array.value_array
override var value by value(Config.suAutoReponse) {
Config.suAutoReponse = entryValues[it].toInt()
}
override var value = Config.suAutoReponse
set(value) = setS(value, field, { field = it }) {
Config.suAutoReponse = entryValues[it].toInt()
}
}
object RequestTimeout : SettingsItem.Selector() {
@ -260,9 +274,10 @@ object RequestTimeout : SettingsItem.Selector() {
override val entryRes = R.array.request_timeout
override val entryValRes = R.array.request_timeout_value
override var value by value(selected) {
Config.suDefaultTimeout = entryValues[it].toInt()
}
override var value = selected
set(value) = setS(value, field, { field = it }) {
Config.suDefaultTimeout = entryValues[it].toInt()
}
private val selected: Int
get() = entryValues.indexOfFirst { it.toInt() == Config.suDefaultTimeout }
@ -273,7 +288,8 @@ object SUNotification : SettingsItem.Selector() {
override val entryRes = R.array.su_notification
override val entryValRes = R.array.value_array
override var value by value(Config.suNotification) {
Config.suNotification = entryValues[it].toInt()
}
override var value = Config.suNotification
set(value) = setS(value, field, { field = it }) {
Config.suNotification = entryValues[it].toInt()
}
}

View File

@ -19,7 +19,7 @@ import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem
import com.topjohnwu.magisk.model.events.DieEvent
import com.topjohnwu.magisk.ui.base.BaseViewModel
import com.topjohnwu.magisk.utils.observable
import com.topjohnwu.magisk.utils.set
import com.topjohnwu.superuser.internal.UiThreadHandler
import kotlinx.coroutines.launch
import me.tatarka.bindingcollectionadapter2.BindingListViewAdapter
@ -34,19 +34,32 @@ class SuRequestViewModel(
) : BaseViewModel() {
@get:Bindable
var icon by observable(null as Drawable?, BR.icon)
var icon: Drawable? = null
set(value) = set(value, field, { field = it }, BR.icon)
@get:Bindable
var title by observable("", BR.title)
var title = ""
set(value) = set(value, field, { field = it }, BR.title)
@get:Bindable
var packageName by observable("", BR.packageName)
var packageName = ""
set(value) = set(value, field, { field = it }, BR.packageName)
@get:Bindable
var denyText by observable(res.getString(R.string.deny), BR.denyText)
var denyText = res.getString(R.string.deny)
set(value) = set(value, field, { field = it }, BR.denyText)
@get:Bindable
var warningText by observable(res.getString(R.string.su_warning), BR.warningText)
var warningText = res.getString(R.string.su_warning)
set(value) = set(value, field, { field = it }, BR.warningText)
@get:Bindable
var selectedItemPosition by observable(0, BR.selectedItemPosition)
var selectedItemPosition = 0
set(value) = set(value, field, { field = it }, BR.selectedItemPosition)
@get:Bindable
var grantEnabled by observable(false, BR.grantEnabled)
var grantEnabled = false
set(value) = set(value, field, { field = it }, BR.grantEnabled)
private val items = res.getStringArray(R.array.allow_timeout).map { SpinnerRvItem(it) }
val adapter = BindingListViewAdapter<SpinnerRvItem>(1).apply {

View File

@ -2,8 +2,6 @@ package com.topjohnwu.magisk.utils
import androidx.databinding.Observable
import androidx.databinding.PropertyChangeRegistry
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* Modified from https://github.com/skoumalcz/teanity/blob/1.2/core/src/main/java/com/skoumal/teanity/observable/Notifyable.kt
@ -52,105 +50,32 @@ interface ObservableHost : Observable {
}
/**
* Declares delegated property in [ObservableHost] parent. This property is available for DataBinding
* to be observed as usual. The only caveat is that in order for binding to generate the [fieldId]
* it has to be annotated accordingly.
*
* The annotation however give very strict control over your internal fields and overall reduce
* overhead in notifying observers. (In comparison to [androidx.databinding.ObservableField])
* It helps the kotlin code to feel more,... _native_, while respecting the original functionality.
* Injects boilerplate implementation for {@literal @}[androidx.databinding.Bindable] field setters.
*
* # Examples:
*
* ## The most basic usage would probably be:
* ```kotlin
* @get:Bindable
* var myField by observable(defaultValue, BR.myField)
* private set
* var myField = defaultValue
* set(value) = set(value, field, { field = it }, BR.myField) {
* doSomething(it)
* }
* ```
*
* ## You can use the field as public read/write, of course:
* ```kotlin
* @get:Bindable
* var myField by observable(defaultValue, BR.myField)
* ```
*
* ## Please beware that delegated property instantiates one class per property
* We discourage using simple getters via delegated properties. Instead you can do something like
* this:
*
* ```kotlin
* @get:Bindable
* var myField by observable(defaultValue, BR.myField, BR.myTransformedField)
*
* var myTransformedField
* @Bindable get() {
* return myField.transform()
* }
* set(value) {
* myField = value.transform()
* }
* ```
*
* */
// Optimize for the most common use case
// Generic type is reified to optimize primitive types
inline fun <reified T> ObservableHost.observable(
initialValue: T,
fieldId: Int
) = object : ReadWriteProperty<ObservableHost, T> {
private var field = initialValue
override fun getValue(thisRef: ObservableHost, property: KProperty<*>): T {
return field
}
@Synchronized
override fun setValue(thisRef: ObservableHost, property: KProperty<*>, value: T) {
if (field != value) {
field = value
notifyPropertyChanged(fieldId)
}
inline fun <reified T> ObservableHost.set(
new: T, old: T, setter: (T) -> Unit, fieldId: Int, afterChanged: (T) -> Unit = {}) {
if (old != new) {
setter(new)
notifyPropertyChanged(fieldId)
afterChanged(new)
}
}
inline fun <reified T> ObservableHost.observable(
initialValue: T,
vararg fieldIds: Int
) = object : ReadWriteProperty<ObservableHost, T> {
private var field = initialValue
override fun getValue(thisRef: ObservableHost, property: KProperty<*>): T {
return field
}
@Synchronized
override fun setValue(thisRef: ObservableHost, property: KProperty<*>, value: T) {
if (field != value) {
field = value
fieldIds.forEach { notifyPropertyChanged(it) }
}
}
}
inline fun <reified T> ObservableHost.observable(
initialValue: T,
vararg fieldIds: Int,
crossinline afterChanged: (T) -> Unit
) = object : ReadWriteProperty<ObservableHost, T> {
private var field = initialValue
override fun getValue(thisRef: ObservableHost, property: KProperty<*>): T {
return field
}
@Synchronized
override fun setValue(thisRef: ObservableHost, property: KProperty<*>, value: T) {
if (field != value) {
field = value
fieldIds.forEach { notifyPropertyChanged(it) }
afterChanged(value)
}
inline fun <reified T> ObservableHost.set(
new: T, old: T, setter: (T) -> Unit, vararg fieldIds: Int, afterChanged: (T) -> Unit = {}) {
if (old != new) {
setter(new)
fieldIds.forEach { notifyPropertyChanged(it) }
afterChanged(new)
}
}

View File

@ -16,7 +16,7 @@ buildscript {
}
dependencies {
classpath("com.android.tools.build:gradle:4.0.0")
classpath("com.android.tools.build:gradle:4.0.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${Deps.vNav}")