From 46d4708386fe8ad5f730d4f926dceeefc8488e21 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Fri, 10 Jun 2022 02:13:25 -0700 Subject: [PATCH] Decouple state from BaseViewModel --- .../topjohnwu/magisk/arch/BaseViewModel.kt | 17 -------- .../magisk/ui/deny/DenyListViewModel.kt | 15 +++---- .../magisk/ui/flash/FlashFragment.kt | 2 +- .../magisk/ui/flash/FlashViewModel.kt | 8 ++-- .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 41 +++++++++---------- .../magisk/ui/install/InstallViewModel.kt | 1 - .../magisk/ui/module/ModuleViewModel.kt | 14 ++++--- .../magisk/ui/superuser/SuperuserViewModel.kt | 16 ++++---- app/src/main/res/layout/fragment_deny_md2.xml | 20 +-------- app/src/main/res/layout/fragment_home_md2.xml | 2 - .../res/layout/fragment_superuser_md2.xml | 22 +--------- .../main/res/layout/include_home_magisk.xml | 6 +-- .../main/res/layout/include_home_manager.xml | 6 +-- 13 files changed, 57 insertions(+), 113 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt index 8d2c59d58..752d5a130 100644 --- a/app/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt @@ -4,17 +4,14 @@ import android.Manifest.permission.REQUEST_INSTALL_PACKAGES import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.annotation.SuppressLint import android.os.Bundle -import androidx.databinding.Bindable import androidx.databinding.PropertyChangeRegistry import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.NavDirections -import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ObservableHost -import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.events.BackPressEvent import com.topjohnwu.magisk.events.NavigationEvent import com.topjohnwu.magisk.events.PermissionEvent @@ -25,22 +22,8 @@ abstract class BaseViewModel : ViewModel(), ObservableHost { override var callbacks: PropertyChangeRegistry? = null - enum class State { - LOADED, LOADING, LOADING_FAILED - } - - @get:Bindable - val loading get() = state == State.LOADING - @get:Bindable - val loaded get() = state == State.LOADED - @get:Bindable - val loadFailed get() = state == State.LOADING_FAILED - val viewEvents: LiveData get() = _viewEvents - var state = State.LOADING - 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/deny/DenyListViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt index fd346b620..4d82c2325 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt @@ -2,14 +2,15 @@ package com.topjohnwu.magisk.ui.deny import android.annotation.SuppressLint import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES +import androidx.databinding.Bindable import androidx.lifecycle.viewModelScope import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.arch.BaseViewModel import com.topjohnwu.magisk.core.di.AppContext import com.topjohnwu.magisk.databinding.bindExtra import com.topjohnwu.magisk.databinding.filterableListOf +import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.ktx.concurrentMap -import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.superuser.Shell import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.asFlow @@ -43,13 +44,13 @@ class DenyListViewModel : BaseViewModel() { it.put(BR.viewModel, this) } + @get:Bindable + var loading = true + private set(value) = set(value, field, { field = it }, BR.loading) + @SuppressLint("InlinedApi") override fun refresh() = viewModelScope.launch { - if (!Utils.showSuperUser()) { - state = State.LOADING_FAILED - return@launch - } - state = State.LOADING + loading = true val (apps, diff) = withContext(Dispatchers.Default) { val pm = AppContext.packageManager val denyList = Shell.cmd("magisk --denylist ls").exec().out @@ -84,6 +85,6 @@ class DenyListViewModel : BaseViewModel() { (it.isChecked || (filterSystem() && filterOS())) && filterQuery() } - state = State.LOADED + loading = false } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt index c9c3873cd..816b0815b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt @@ -35,7 +35,7 @@ class FlashFragment : BaseFragment() { setHasOptionsMenu(true) activity?.setTitle(R.string.flash_screen_title) - viewModel.flashState.observe(this) { + viewModel.state.observe(this) { activity?.supportActionBar?.setSubtitle( when (it) { FlashViewModel.State.FLASHING -> R.string.flashing 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 7eeeb5fbb..cf3517481 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 @@ -32,9 +32,9 @@ class FlashViewModel : BaseViewModel() { FLASHING, SUCCESS, FAILED } - private val _flashState = MutableLiveData(State.FLASHING) - val flashState: LiveData get() = _flashState - val flashing = Transformations.map(flashState) { it == State.FLASHING } + private val _state = MutableLiveData(State.FLASHING) + val state: LiveData get() = _state + val flashing = Transformations.map(state) { it == State.FLASHING } @get:Bindable var showReboot = Info.isRooted @@ -89,7 +89,7 @@ class FlashViewModel : BaseViewModel() { } private fun onResult(success: Boolean) { - _flashState.value = if (success) State.SUCCESS else State.FAILED + _state.value = if (success) State.SUCCESS else State.FAILED } fun onMenuItemClicked(item: MenuItem): Boolean { 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 34b110b95..3947d1086 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 @@ -26,14 +26,14 @@ import com.topjohnwu.superuser.Shell import kotlinx.coroutines.launch import kotlin.math.roundToInt -enum class MagiskState { - NOT_INSTALLED, UP_TO_DATE, OBSOLETE, LOADING -} - class HomeViewModel( private val svc: NetworkService ) : BaseViewModel() { + enum class State { + LOADING, INVALID, OUTDATED, UP_TO_DATE + } + val magiskTitleBarrierIds = intArrayOf(R.id.home_magisk_icon, R.id.home_magisk_title, R.id.home_magisk_button) val appTitleBarrierIds = @@ -43,16 +43,16 @@ class HomeViewModel( var isNoticeVisible = Config.safetyNotice set(value) = set(value, field, { field = it }, BR.noticeVisible) - val stateMagisk + val magiskState get() = when { - !Info.env.isActive -> MagiskState.NOT_INSTALLED - Info.env.versionCode < BuildConfig.VERSION_CODE -> MagiskState.OBSOLETE - else -> MagiskState.UP_TO_DATE + !Info.env.isActive -> State.INVALID + Info.env.versionCode < BuildConfig.VERSION_CODE -> State.OUTDATED + else -> State.UP_TO_DATE } @get:Bindable - var stateManager = MagiskState.LOADING - set(value) = set(value, field, { field = it }, BR.stateManager) + var appState = State.LOADING + set(value) = set(value, field, { field = it }, BR.appState) val magiskInstalledVersion get() = Info.env.run { @@ -84,13 +84,11 @@ class HomeViewModel( } override fun refresh() = viewModelScope.launch { - state = State.LOADING + appState = State.LOADING Info.getRemote(svc)?.apply { - state = State.LOADED - - stateManager = when { - BuildConfig.VERSION_CODE < magisk.versionCode -> MagiskState.OBSOLETE - else -> MagiskState.UP_TO_DATE + appState = when { + BuildConfig.VERSION_CODE < magisk.versionCode -> State.OUTDATED + else -> State.UP_TO_DATE } val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL @@ -98,7 +96,6 @@ class HomeViewModel( ("${magisk.version} (${magisk.versionCode}) (${stub.versionCode})" + if (isDebug) " (D)" else "").asText() } ?: run { - state = State.LOADING_FAILED managerRemoteVersion = R.string.not_available.asText() } ensureEnv() @@ -119,14 +116,14 @@ class HomeViewModel( fun onDeletePressed() = UninstallDialog().publish() - fun onManagerPressed() = when (state) { - State.LOADED -> withExternalRW { + fun onManagerPressed() = when (magiskState) { + State.LOADING -> SnackbarEvent(R.string.loading).publish() + State.INVALID -> SnackbarEvent(R.string.no_connection).publish() + else -> withExternalRW { withInstallPermission { ManagerInstallDialog().publish() } } - State.LOADING -> SnackbarEvent(R.string.loading).publish() - else -> SnackbarEvent(R.string.no_connection).publish() } fun onMagiskPressed() = withExternalRW { @@ -139,7 +136,7 @@ class HomeViewModel( } private suspend fun ensureEnv() { - if (MagiskState.NOT_INSTALLED == stateMagisk || checkedEnv) return + if (magiskState == State.INVALID || checkedEnv) return val cmd = "env_check ${Info.env.versionString} ${Info.env.versionCode}" if (!Shell.cmd(cmd).await().isSuccess) { EnvFixDialog(this).publish() 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 f96307ec2..2c571dc9f 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 @@ -95,7 +95,6 @@ class InstallViewModel( R.id.method_inactive_slot -> FlashFragment.flash(true).navigate(true) else -> error("Unknown value") } - state = State.LOADING } override fun onSaveState(state: Bundle) { 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 057d01901..fbe40ea31 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 @@ -1,6 +1,7 @@ package com.topjohnwu.magisk.ui.module import android.net.Uri +import androidx.databinding.Bindable import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.topjohnwu.magisk.BR @@ -10,10 +11,7 @@ import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.base.ContentResultCallback import com.topjohnwu.magisk.core.model.module.LocalModule import com.topjohnwu.magisk.core.model.module.OnlineModule -import com.topjohnwu.magisk.databinding.MergeObservableList -import com.topjohnwu.magisk.databinding.RvItem -import com.topjohnwu.magisk.databinding.bindExtra -import com.topjohnwu.magisk.databinding.diffListOf +import com.topjohnwu.magisk.databinding.* import com.topjohnwu.magisk.events.GetContentEvent import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog @@ -36,6 +34,10 @@ class ModuleViewModel : BaseViewModel() { val data get() = uri + @get:Bindable + var loading = true + private set(value) = set(value, field, { field = it }, BR.loading) + init { if (Info.env.isActive && LocalModule.loaded()) { items.insertItem(InstallModule) @@ -45,9 +47,9 @@ class ModuleViewModel : BaseViewModel() { override fun refresh(): Job { return viewModelScope.launch { - state = State.LOADING + loading = true loadInstalled() - state = State.LOADED + loading = false loadUpdateInfo() } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt index 87c3bbd4e..af7155a69 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.pm.PackageManager import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES import android.os.Process +import androidx.databinding.Bindable import androidx.databinding.ObservableArrayList import androidx.lifecycle.viewModelScope import com.topjohnwu.magisk.BR @@ -14,10 +15,7 @@ import com.topjohnwu.magisk.core.di.AppContext import com.topjohnwu.magisk.core.model.su.SuPolicy import com.topjohnwu.magisk.core.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.currentLocale -import com.topjohnwu.magisk.databinding.AnyDiffRvItem -import com.topjohnwu.magisk.databinding.MergeObservableList -import com.topjohnwu.magisk.databinding.bindExtra -import com.topjohnwu.magisk.databinding.diffListOf +import com.topjohnwu.magisk.databinding.* import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.dialog.BiometricEvent import com.topjohnwu.magisk.events.dialog.SuperuserRevokeDialog @@ -45,15 +43,17 @@ class SuperuserViewModel( it.put(BR.listener, this) } - // --- + @get:Bindable + var loading = true + private set(value) = set(value, field, { field = it }, BR.loading) @SuppressLint("InlinedApi") override fun refresh() = viewModelScope.launch { if (!Utils.showSuperUser()) { - state = State.LOADING_FAILED + loading = false return@launch } - state = State.LOADING + loading = true val (policies, diff) = withContext(Dispatchers.IO) { db.deleteOutdated() db.delete(AppContext.applicationInfo.uid) @@ -98,7 +98,7 @@ class SuperuserViewModel( itemsHelpers.clear() else if (itemsHelpers.isEmpty()) itemsHelpers.add(itemNoData) - state = State.LOADED + loading = false } // --- diff --git a/app/src/main/res/layout/fragment_deny_md2.xml b/app/src/main/res/layout/fragment_deny_md2.xml index 62a1cc031..89a202a08 100644 --- a/app/src/main/res/layout/fragment_deny_md2.xml +++ b/app/src/main/res/layout/fragment_deny_md2.xml @@ -24,7 +24,7 @@ android:paddingTop="@dimen/internal_action_bar_size" app:fitsSystemWindowsInsets="top|bottom" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:invisibleUnless="@{viewModel.loaded}" + app:invisible="@{viewModel.loading}" app:items="@{viewModel.items}" app:extraBindings="@{viewModel.extraBindings}" tools:listitem="@layout/item_hide_md2" @@ -52,24 +52,6 @@ - - - - - - diff --git a/app/src/main/res/layout/fragment_home_md2.xml b/app/src/main/res/layout/fragment_home_md2.xml index d1479da19..66e31d5de 100644 --- a/app/src/main/res/layout/fragment_home_md2.xml +++ b/app/src/main/res/layout/fragment_home_md2.xml @@ -7,8 +7,6 @@ - - diff --git a/app/src/main/res/layout/fragment_superuser_md2.xml b/app/src/main/res/layout/fragment_superuser_md2.xml index 825f49064..48de9a9fd 100644 --- a/app/src/main/res/layout/fragment_superuser_md2.xml +++ b/app/src/main/res/layout/fragment_superuser_md2.xml @@ -19,7 +19,7 @@ - - - - - - diff --git a/app/src/main/res/layout/include_home_magisk.xml b/app/src/main/res/layout/include_home_magisk.xml index 343d869b8..e71b5ce58 100644 --- a/app/src/main/res/layout/include_home_magisk.xml +++ b/app/src/main/res/layout/include_home_magisk.xml @@ -7,7 +7,7 @@ - + - +