From 6c6368fd81ead49b764c0024836f019aa28a8d99 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 15 Jul 2020 01:21:57 -0700 Subject: [PATCH] Reduce usage of delegation --- .../magisk/model/entity/recycler/LogRvItem.kt | 10 +- .../model/entity/recycler/ModuleRvItem.kt | 24 ++-- .../model/entity/recycler/SettingsItem.kt | 26 +++-- .../topjohnwu/magisk/ui/base/BaseViewModel.kt | 8 +- .../magisk/ui/flash/FlashViewModel.kt | 9 +- .../topjohnwu/magisk/ui/hide/HideViewModel.kt | 16 +-- .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 26 +++-- .../magisk/ui/install/InstallViewModel.kt | 37 +++--- .../topjohnwu/magisk/ui/log/LogViewModel.kt | 5 +- .../magisk/ui/module/ModuleViewModel.kt | 20 ++-- .../magisk/ui/safetynet/SafetynetViewModel.kt | 20 +++- .../magisk/ui/settings/SettingsItems.kt | 98 +++++++++------- .../magisk/ui/surequest/SuRequestViewModel.kt | 29 +++-- .../topjohnwu/magisk/utils/ObservableHost.kt | 109 +++--------------- build.gradle.kts | 2 +- 15 files changed, 226 insertions(+), 213 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt index 5059ad34c..270072aa6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt @@ -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() { 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 diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt index 2fa90a0f9..ae60ba776 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt @@ -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() { 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() { 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(), 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 diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/SettingsItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/SettingsItem.kt index 21060cf9f..36b3820c6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/SettingsItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/SettingsItem.kt @@ -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() { 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() { @get:Bindable abstract var value: T - protected inline fun value( - initialValue: T, - vararg fieldIds: Int, - crossinline setter: (T) -> Unit = {} - ) = observable(initialValue, BR.value, *fieldIds, afterChanged = setter) + protected inline fun setV( + new: T, old: T, setter: (T) -> Unit, vararg fieldIds: Int) { + set(new, old, setter, BR.value, *fieldIds) + } + protected inline fun setV( + new: T, old: T, setter: (T) -> Unit, afterChanged: (T) -> Unit = {}) { + set(new, old, setter, BR.value, afterChanged = afterChanged) + } } abstract class Toggle : Value() { @@ -142,10 +146,10 @@ sealed class SettingsItem : ObservableItem() { 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 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 = runCatching { getStringArray(id) }.getOrDefault(emptyArray()) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt index 34cd92da5..310657499 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseViewModel.kt @@ -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 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() private var runningJob: Job? = null diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt index ed33bfeb0..6069c758b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt @@ -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() val items = diffListOf() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt index 3f7368b53..ba9d23f40 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt @@ -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() val itemBinding = itemBindingOf { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index 763ba293d..afd6f90ff 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -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 { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt index 902b1a605..327768e15 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt @@ -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() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt index be5608d17..04746b219 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt @@ -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() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt index f016d6ab8..ea0c256b7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt @@ -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() val itemSearchBinding = itemBindingOf { it.bindExtra(BR.viewModel, this) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt index 7278ce3f6..4ee467cf6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt @@ -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 { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt index 95d0c495e..fcd1824f9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt @@ -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() @@ -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().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() + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt index d6b372684..f14a51da7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt @@ -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(1).apply { diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ObservableHost.kt b/app/src/main/java/com/topjohnwu/magisk/utils/ObservableHost.kt index 39b3cbcca..d0da419fe 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/ObservableHost.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/ObservableHost.kt @@ -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 ObservableHost.observable( - initialValue: T, - fieldId: Int -) = object : ReadWriteProperty { - 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 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 ObservableHost.observable( - initialValue: T, - vararg fieldIds: Int -) = object : ReadWriteProperty { - 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 ObservableHost.observable( - initialValue: T, - vararg fieldIds: Int, - crossinline afterChanged: (T) -> Unit -) = object : ReadWriteProperty { - 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 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) } } diff --git a/build.gradle.kts b/build.gradle.kts index 723186ddc..9f05fbf14 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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}")