mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-22 21:01:33 +00:00
Move coroutine job into its own class
This commit is contained in:
parent
46d4708386
commit
515f81944c
@ -0,0 +1,22 @@
|
|||||||
|
package com.topjohnwu.magisk.arch
|
||||||
|
|
||||||
|
import androidx.annotation.MainThread
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
abstract class AsyncLoadViewModel : BaseViewModel() {
|
||||||
|
|
||||||
|
private var loadingJob: Job? = null
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
fun startLoading() {
|
||||||
|
if (loadingJob?.isActive == true) {
|
||||||
|
// Prevent multiple jobs from running at the same time
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadingJob = viewModelScope.launch { doLoadWork() }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract suspend fun doLoadWork()
|
||||||
|
}
|
@ -76,7 +76,10 @@ abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHo
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
viewModel.requestRefresh()
|
viewModel.let {
|
||||||
|
if (it is AsyncLoadViewModel)
|
||||||
|
it.startLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onPreBind(binding: Binding) {
|
protected open fun onPreBind(binding: Binding) {
|
||||||
|
@ -16,31 +16,16 @@ import com.topjohnwu.magisk.events.BackPressEvent
|
|||||||
import com.topjohnwu.magisk.events.NavigationEvent
|
import com.topjohnwu.magisk.events.NavigationEvent
|
||||||
import com.topjohnwu.magisk.events.PermissionEvent
|
import com.topjohnwu.magisk.events.PermissionEvent
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
|
|
||||||
abstract class BaseViewModel : ViewModel(), ObservableHost {
|
abstract class BaseViewModel : ViewModel(), ObservableHost {
|
||||||
|
|
||||||
override var callbacks: PropertyChangeRegistry? = null
|
override var callbacks: PropertyChangeRegistry? = null
|
||||||
|
|
||||||
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
|
|
||||||
|
|
||||||
private val _viewEvents = MutableLiveData<ViewEvent>()
|
private val _viewEvents = MutableLiveData<ViewEvent>()
|
||||||
private var runningJob: Job? = null
|
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
|
||||||
|
|
||||||
open fun onSaveState(state: Bundle) {}
|
open fun onSaveState(state: Bundle) {}
|
||||||
open fun onRestoreState(state: Bundle) {}
|
open fun onRestoreState(state: Bundle) {}
|
||||||
|
|
||||||
/** This should probably never be called manually, it's called manually via delegate. */
|
|
||||||
@Synchronized
|
|
||||||
fun requestRefresh() {
|
|
||||||
if (runningJob?.isActive == true) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
runningJob = refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun refresh(): Job? = null
|
|
||||||
|
|
||||||
open fun onNetworkChanged(network: Boolean) {}
|
open fun onNetworkChanged(network: Boolean) {}
|
||||||
|
|
||||||
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
|
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
|
||||||
|
@ -89,7 +89,10 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
viewModel.requestRefresh()
|
viewModel.let {
|
||||||
|
if (it is AsyncLoadViewModel)
|
||||||
|
it.startLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEventDispatched(event: ViewEvent) = when (event) {
|
override fun onEventDispatched(event: ViewEvent) = when (event) {
|
||||||
|
@ -3,9 +3,8 @@ package com.topjohnwu.magisk.ui.deny
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
import com.topjohnwu.magisk.databinding.filterableListOf
|
import com.topjohnwu.magisk.databinding.filterableListOf
|
||||||
@ -16,10 +15,9 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.toCollection
|
import kotlinx.coroutines.flow.toCollection
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class DenyListViewModel : BaseViewModel() {
|
class DenyListViewModel : AsyncLoadViewModel() {
|
||||||
|
|
||||||
var isShowSystem = false
|
var isShowSystem = false
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -49,7 +47,7 @@ class DenyListViewModel : BaseViewModel() {
|
|||||||
private set(value) = set(value, field, { field = it }, BR.loading)
|
private set(value) = set(value, field, { field = it }, BR.loading)
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
loading = true
|
loading = true
|
||||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
val (apps, diff) = withContext(Dispatchers.Default) {
|
||||||
val pm = AppContext.packageManager
|
val pm = AppContext.packageManager
|
||||||
|
@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.home
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
import com.topjohnwu.magisk.BuildConfig
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
@ -23,12 +22,11 @@ import com.topjohnwu.magisk.ktx.await
|
|||||||
import com.topjohnwu.magisk.utils.Utils
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class HomeViewModel(
|
class HomeViewModel(
|
||||||
private val svc: NetworkService
|
private val svc: NetworkService
|
||||||
) : BaseViewModel() {
|
) : AsyncLoadViewModel() {
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
LOADING, INVALID, OUTDATED, UP_TO_DATE
|
LOADING, INVALID, OUTDATED, UP_TO_DATE
|
||||||
@ -83,7 +81,7 @@ class HomeViewModel(
|
|||||||
private var checkedEnv = false
|
private var checkedEnv = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
appState = State.LOADING
|
appState = State.LOADING
|
||||||
Info.getRemote(svc)?.apply {
|
Info.getRemote(svc)?.apply {
|
||||||
appState = when {
|
appState = when {
|
||||||
@ -101,9 +99,7 @@ class HomeViewModel(
|
|||||||
ensureEnv()
|
ensureEnv()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNetworkChanged(network: Boolean) {
|
override fun onNetworkChanged(network: Boolean) = startLoading()
|
||||||
requestRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onProgressUpdate(progress: Float, subject: Subject) {
|
fun onProgressUpdate(progress: Float, subject: Subject) {
|
||||||
if (subject is App)
|
if (subject is App)
|
||||||
|
@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
import com.topjohnwu.magisk.BuildConfig
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.repository.LogRepository
|
import com.topjohnwu.magisk.core.repository.LogRepository
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||||
@ -24,7 +24,7 @@ import java.io.FileInputStream
|
|||||||
|
|
||||||
class LogViewModel(
|
class LogViewModel(
|
||||||
private val repo: LogRepository
|
private val repo: LogRepository
|
||||||
) : BaseViewModel() {
|
) : AsyncLoadViewModel() {
|
||||||
|
|
||||||
// --- empty view
|
// --- empty view
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class LogViewModel(
|
|||||||
var consoleText = " "
|
var consoleText = " "
|
||||||
set(value) = set(value, field, { field = it }, BR.consoleText)
|
set(value) = set(value, field, { field = it }, BR.consoleText)
|
||||||
|
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
consoleText = repo.fetchMagiskLogs()
|
consoleText = repo.fetchMagiskLogs()
|
||||||
val (suLogs, diff) = withContext(Dispatchers.Default) {
|
val (suLogs, diff) = withContext(Dispatchers.Default) {
|
||||||
val suLogs = repo.fetchSuLogs().map { LogRvItem(it) }
|
val suLogs = repo.fetchSuLogs().map { LogRvItem(it) }
|
||||||
@ -89,12 +89,12 @@ class LogViewModel(
|
|||||||
|
|
||||||
fun clearMagiskLog() = repo.clearMagiskLogs {
|
fun clearMagiskLog() = repo.clearMagiskLogs {
|
||||||
SnackbarEvent(R.string.logs_cleared).publish()
|
SnackbarEvent(R.string.logs_cleared).publish()
|
||||||
requestRefresh()
|
startLoading()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearLog() = viewModelScope.launch {
|
fun clearLog() = viewModelScope.launch {
|
||||||
repo.clearLogs()
|
repo.clearLogs()
|
||||||
SnackbarEvent(R.string.logs_cleared).publish()
|
SnackbarEvent(R.string.logs_cleared).publish()
|
||||||
requestRefresh()
|
startLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,9 @@ package com.topjohnwu.magisk.ui.module
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||||
@ -16,12 +15,10 @@ import com.topjohnwu.magisk.events.GetContentEvent
|
|||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
|
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
class ModuleViewModel : BaseViewModel() {
|
class ModuleViewModel : AsyncLoadViewModel() {
|
||||||
|
|
||||||
val bottomBarBarrierIds = intArrayOf(R.id.module_update, R.id.module_remove)
|
val bottomBarBarrierIds = intArrayOf(R.id.module_update, R.id.module_remove)
|
||||||
|
|
||||||
@ -45,18 +42,14 @@ class ModuleViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refresh(): Job {
|
override suspend fun doLoadWork() {
|
||||||
return viewModelScope.launch {
|
|
||||||
loading = true
|
loading = true
|
||||||
loadInstalled()
|
loadInstalled()
|
||||||
loading = false
|
loading = false
|
||||||
loadUpdateInfo()
|
loadUpdateInfo()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNetworkChanged(network: Boolean) {
|
override fun onNetworkChanged(network: Boolean) = startLoading()
|
||||||
requestRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun loadInstalled() {
|
private suspend fun loadInstalled() {
|
||||||
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
||||||
|
@ -9,7 +9,7 @@ import androidx.databinding.ObservableArrayList
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
@ -29,7 +29,7 @@ import kotlinx.coroutines.withContext
|
|||||||
|
|
||||||
class SuperuserViewModel(
|
class SuperuserViewModel(
|
||||||
private val db: PolicyDao
|
private val db: PolicyDao
|
||||||
) : BaseViewModel() {
|
) : AsyncLoadViewModel() {
|
||||||
|
|
||||||
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
||||||
|
|
||||||
@ -48,10 +48,10 @@ class SuperuserViewModel(
|
|||||||
private set(value) = set(value, field, { field = it }, BR.loading)
|
private set(value) = set(value, field, { field = it }, BR.loading)
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
if (!Utils.showSuperUser()) {
|
if (!Utils.showSuperUser()) {
|
||||||
loading = false
|
loading = false
|
||||||
return@launch
|
return
|
||||||
}
|
}
|
||||||
loading = true
|
loading = true
|
||||||
val (policies, diff) = withContext(Dispatchers.IO) {
|
val (policies, diff) = withContext(Dispatchers.IO) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user