mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 03:47:37 +00:00
Decouple state from BaseViewModel
This commit is contained in:
parent
aabc36f86b
commit
46d4708386
@ -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<ViewEvent> get() = _viewEvents
|
||||
|
||||
var state = State.LOADING
|
||||
set(value) = set(value, field, { field = it }, BR.loading, BR.loaded, BR.loadFailed)
|
||||
|
||||
private val _viewEvents = MutableLiveData<ViewEvent>()
|
||||
private var runningJob: Job? = null
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
|
||||
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
|
||||
|
@ -32,9 +32,9 @@ class FlashViewModel : BaseViewModel() {
|
||||
FLASHING, SUCCESS, FAILED
|
||||
}
|
||||
|
||||
private val _flashState = MutableLiveData(State.FLASHING)
|
||||
val flashState: LiveData<State> get() = _flashState
|
||||
val flashing = Transformations.map(flashState) { it == State.FLASHING }
|
||||
private val _state = MutableLiveData(State.FLASHING)
|
||||
val state: LiveData<State> 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 {
|
||||
|
@ -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()
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
// ---
|
||||
|
@ -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 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
goneUnless="@{viewModel.loadFailed}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
tools:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/not_available"
|
||||
android:textAppearance="@style/AppearanceFoundation.Title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</layout>
|
||||
|
@ -7,8 +7,6 @@
|
||||
|
||||
<import type="com.topjohnwu.magisk.core.Info" />
|
||||
|
||||
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
|
||||
|
||||
<import type="com.topjohnwu.magisk.ui.home.DeveloperItem" />
|
||||
|
||||
<import type="com.topjohnwu.magisk.ui.home.IconLink" />
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/superuser_list"
|
||||
goneUnless="@{viewModel.loaded || !viewModel.items.empty}"
|
||||
gone="@{viewModel.loading}"
|
||||
app:items="@{viewModel.items}"
|
||||
app:extraBindings="@{viewModel.extraBindings}"
|
||||
android:layout_width="match_parent"
|
||||
@ -33,7 +33,7 @@
|
||||
tools:listitem="@layout/item_policy_md2" />
|
||||
|
||||
<LinearLayout
|
||||
goneUnless="@{viewModel.loading && viewModel.items.empty}"
|
||||
goneUnless="@{viewModel.loading}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@ -54,24 +54,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
goneUnless="@{viewModel.loadFailed}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
tools:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/not_available"
|
||||
android:textAppearance="@style/AppearanceFoundation.Title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</layout>
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
<import type="com.topjohnwu.magisk.core.Info" />
|
||||
|
||||
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
|
||||
<import type="com.topjohnwu.magisk.ui.home.HomeViewModel.State" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
@ -63,7 +63,7 @@
|
||||
|
||||
<Button
|
||||
style="@style/WidgetFoundation.Button"
|
||||
gone="@{viewModel.stateMagisk != MagiskState.OBSOLETE}"
|
||||
gone="@{viewModel.magiskState != State.OUTDATED}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="@{() -> viewModel.onMagiskPressed()}"
|
||||
@ -74,7 +74,7 @@
|
||||
|
||||
<Button
|
||||
style="@style/WidgetFoundation.Button.Text"
|
||||
gone="@{viewModel.stateMagisk == MagiskState.OBSOLETE}"
|
||||
gone="@{viewModel.magiskState == State.OUTDATED}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
<import type="com.topjohnwu.magisk.core.Info" />
|
||||
|
||||
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
|
||||
<import type="com.topjohnwu.magisk.ui.home.HomeViewModel.State" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
@ -64,7 +64,7 @@
|
||||
|
||||
<Button
|
||||
style="@style/WidgetFoundation.Button"
|
||||
gone="@{viewModel.stateManager != MagiskState.OBSOLETE}"
|
||||
gone="@{viewModel.appState != State.OUTDATED}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="@{() -> viewModel.onManagerPressed()}"
|
||||
@ -75,7 +75,7 @@
|
||||
|
||||
<Button
|
||||
style="@style/WidgetFoundation.Button.Text"
|
||||
gone="@{viewModel.stateManager != MagiskState.UP_TO_DATE}"
|
||||
gone="@{viewModel.appState != State.UP_TO_DATE}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
|
Loading…
x
Reference in New Issue
Block a user