Load installed modules with coroutine
This commit is contained in:
parent
ae6dd50ccd
commit
86db0cd2cd
@ -1,9 +1,10 @@
|
||||
package com.topjohnwu.magisk.core.model.module
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class Module(path: String) : BaseModule() {
|
||||
override var id: String = ""
|
||||
@ -64,18 +65,13 @@ class Module(path: String) : BaseModule() {
|
||||
|
||||
private val PERSIST get() = "${Const.MAGISKTMP}/mirror/persist/magisk"
|
||||
|
||||
@WorkerThread
|
||||
fun loadModules(): List<Module> {
|
||||
val moduleList = mutableListOf<Module>()
|
||||
val path = SuFile(Const.MAGISK_PATH)
|
||||
val modules =
|
||||
path.listFiles { _, name -> name != "lost+found" && name != ".core" }.orEmpty()
|
||||
for (file in modules) {
|
||||
if (file.isFile) continue
|
||||
val module = Module(Const.MAGISK_PATH + "/" + file.name)
|
||||
moduleList.add(module)
|
||||
}
|
||||
return moduleList.sortedBy { it.name.toLowerCase() }
|
||||
suspend fun installed() = withContext(Dispatchers.IO) {
|
||||
SuFile(Const.MAGISK_PATH)
|
||||
.listFiles { _, name -> name != "lost+found" && name != ".core" }
|
||||
.orEmpty()
|
||||
.filter { !it.isFile }
|
||||
.map { Module("${Const.MAGISK_PATH}/${it.name}") }
|
||||
.sortedBy { it.name.toLowerCase() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.topjohnwu.magisk.ui.module
|
||||
|
||||
import android.Manifest
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@ -27,14 +26,13 @@ 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.KObservableField
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
|
||||
import java.lang.Runnable
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/*
|
||||
@ -143,7 +141,6 @@ class ModuleViewModel(
|
||||
|
||||
// ---
|
||||
|
||||
private var remoteJob: Disposable? = null
|
||||
private var refetch = false
|
||||
private val dao
|
||||
get() = when (Config.repoOrder) {
|
||||
@ -176,33 +173,45 @@ class ModuleViewModel(
|
||||
|
||||
// ---
|
||||
|
||||
override fun refresh(): Disposable {
|
||||
override fun refresh(): Disposable? {
|
||||
if (itemsRemote.isEmpty())
|
||||
loadRemote()
|
||||
return loadInstalled().subscribeK()
|
||||
loadInstalled()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun loadInstalled() = Single.fromCallable { Module.loadModules() }
|
||||
.map { it.map { ModuleItem(it) } }
|
||||
.map { it.loadDetail() }
|
||||
.map { it to itemsInstalled.calculateDiff(it) }
|
||||
.applyViewModel(this)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map {
|
||||
itemsInstalled.update(it.first, it.second)
|
||||
it.first
|
||||
private suspend fun loadUpdates(installed: List<ModuleItem>) = withContext(Dispatchers.IO) {
|
||||
installed
|
||||
.mapNotNull { dao.getUpdatableRepoById(it.item.id, it.item.versionCode) }
|
||||
.map { RepoItem.Update(it) }
|
||||
}
|
||||
.observeOn(Schedulers.io())
|
||||
.map { loadUpdates(it) }
|
||||
.map { it to itemsUpdatable.calculateDiff(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnSuccess { itemsUpdatable.update(it.first, it.second) }
|
||||
.doOnSuccess {
|
||||
|
||||
private suspend fun List<ModuleItem>.loadDetails() = withContext(Dispatchers.IO) {
|
||||
onEach {
|
||||
launch {
|
||||
it.repo = dao.getRepoById(it.item.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadInstalled() = viewModelScope.launch {
|
||||
state = State.LOADING
|
||||
val installed = Module.installed().map { ModuleItem(it) }
|
||||
val detailLoad = async { installed.loadDetails() }
|
||||
val updates = loadUpdates(installed)
|
||||
val diff = withContext(Dispatchers.Default) {
|
||||
val i = async { itemsInstalled.calculateDiff(installed) }
|
||||
val u = async { itemsUpdatable.calculateDiff(updates) }
|
||||
awaitAll(i, u)
|
||||
}
|
||||
detailLoad.await()
|
||||
itemsInstalled.update(installed, diff[0])
|
||||
itemsUpdatable.update(updates, diff[1])
|
||||
addInstalledEmptyMessage()
|
||||
addUpdatableEmptyMessage()
|
||||
updateActiveState()
|
||||
state = State.LOADED
|
||||
}
|
||||
.ignoreElement()!!
|
||||
|
||||
@Synchronized
|
||||
fun loadRemote() {
|
||||
@ -226,8 +235,8 @@ class ModuleViewModel(
|
||||
loadRemoteDB(itemsRemote.size)
|
||||
}
|
||||
isRemoteLoading = false
|
||||
itemsRemote.addAll(repos)
|
||||
refetch = false
|
||||
UiThreadHandler.handler.post { itemsRemote.addAll(repos) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,13 +283,6 @@ class ModuleViewModel(
|
||||
|
||||
// ---
|
||||
|
||||
@WorkerThread
|
||||
private fun List<ModuleItem>.loadDetail() = onEach { module ->
|
||||
Single.fromCallable { dao.getRepoById(module.item.id)!! }
|
||||
.subscribeK(onError = {}) { module.repo = it }
|
||||
.add()
|
||||
}
|
||||
|
||||
private fun update(repo: Repo, progress: Int) =
|
||||
Single.fromCallable { itemsRemote + itemsSearch }
|
||||
.map { it.first { it.item.id == repo.id } }
|
||||
@ -303,13 +305,6 @@ class ModuleViewModel(
|
||||
|
||||
// ---
|
||||
|
||||
@WorkerThread
|
||||
private fun loadUpdates(installed: List<ModuleItem>) = installed
|
||||
.mapNotNull { dao.getUpdatableRepoById(it.item.id, it.item.versionCode) }
|
||||
.map { RepoItem.Update(it) }
|
||||
|
||||
// ---
|
||||
|
||||
fun updateActiveState() = Single.fromCallable { itemsInstalled.any { it.isModified } }
|
||||
.subscribeK { sectionActive.hasButton = it }
|
||||
.add()
|
||||
@ -326,7 +321,6 @@ class ModuleViewModel(
|
||||
Single.fromCallable { itemsRemote }
|
||||
.subscribeK {
|
||||
itemsRemote.removeAll(it)
|
||||
remoteJob?.dispose()
|
||||
loadRemote()
|
||||
}.add()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user