Commit ed837ba2 authored by Viktor De Pasquale's avatar Viktor De Pasquale

Updated the logic that refreshes the modules

Also added empty states for installed and made updatable modules visible all the time to avoid unnecessary transitions
parent 13262fdb
package com.topjohnwu.magisk.model.entity.recycler
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
class TextItem(val text: Int) : ComparableRvItem<TextItem>() {
override val layoutRes = R.layout.item_text
override fun onBindingBound(binding: ViewDataBinding) {
super.onBindingBound(binding)
val params = binding.root.layoutParams as? StaggeredGridLayoutManager.LayoutParams
params?.isFullSpan = true
}
override fun contentSameAs(other: TextItem) = text == other.text
override fun itemSameAs(other: TextItem) = contentSameAs(other)
}
\ No newline at end of file
......@@ -22,9 +22,12 @@ import com.topjohnwu.magisk.redesign.compat.*
import com.topjohnwu.magisk.tasks.RepoUpdater
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.magisk.utils.currentLocale
import io.reactivex.Completable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
import timber.log.Timber
import kotlin.math.roundToInt
......@@ -54,8 +57,24 @@ class ModuleViewModel(
it.bindExtra(BR.viewModel, this)
}
private val itemNoneInstalled = TextItem(R.string.module_install_none)
private val itemNoneUpdatable = TextItem(R.string.module_update_none)
private val itemsInstalled = diffListOf<ModuleItem>()
private val itemsUpdatable = diffListOf<RepoItem.Update>()
private val itemsRemote = diffListOf<RepoItem.Remote>()
val adapter = adapterOf<ComparableRvItem<*>>()
val items = diffListOf<ComparableRvItem<*>>()
val items = MergeObservableList<ComparableRvItem<*>>()
.insertItem(sectionActive)
.insertItem(itemNoneInstalled)
.insertList(itemsInstalled)
.insertItem(InstallModule)
.insertItem(sectionUpdate)
.insertItem(itemNoneUpdatable)
.insertList(itemsUpdatable)
.insertItem(sectionRemote)
.insertList(itemsRemote)!!
val itemBinding = itemBindingOf<ComparableRvItem<*>> {
it.bindExtra(BR.viewModel, this)
}
......@@ -94,15 +113,6 @@ class ModuleViewModel(
// ---
private val itemsInstalled
@WorkerThread get() = items.filterIsInstance<ModuleItem>()
private val itemsUpdatable
@WorkerThread get() = items.filterIsInstance<RepoItem.Update>()
private val itemsRemote
@WorkerThread get() = items.filterIsInstance<RepoItem.Remote>()
private var remoteJob: Disposable? = null
private val dao
get() = when (Config.repoOrder) {
......@@ -126,22 +136,34 @@ class ModuleViewModel(
// ---
override fun refresh() = Single.fromCallable { Module.loadModules() }
override fun refresh(): Disposable {
val installedTask = loadInstalled()
val remoteTask = if (itemsRemote.isEmpty()) {
Completable.fromAction { loadRemote() }
} else {
Completable.complete()
}
return Completable.merge(listOf(installedTask, remoteTask)).subscribeK()
}
private fun loadInstalled() = Single.fromCallable { Module.loadModules() }
.map { it.map { ModuleItem(it) } }
.map { it.order() }
.map { it.loadDetail() }
.map { build(active = it, updatable = loadUpdates(it)) }
.map { it to items.calculateDiff(it) }
.map { it to itemsInstalled.calculateDiff(it) }
.applyViewModel(this)
.subscribeK {
items.update(it.first, it.second)
if (!items.contains(sectionRemote)) {
loadRemote()
}
updateActiveState()
}
fun loadRemoteImplicit() = let { items.clear(); itemsSearch.clear() }
.observeOn(AndroidSchedulers.mainThread())
.doOnSuccess { itemsInstalled.update(it.first, it.second) }
.doOnSuccess { if (itemsInstalled.isNotEmpty()) items.remove(itemNoneInstalled) }
.observeOn(Schedulers.io())
.map { loadUpdates(it.first) }
.observeOn(AndroidSchedulers.mainThread())
.map { it to itemsUpdatable.calculateDiff(it) }
.doOnSuccess { itemsUpdatable.update(it.first, it.second) }
.doOnSuccess { if (itemsUpdatable.isNotEmpty()) items.remove(itemNoneUpdatable) }
.ignoreElement()!!
fun loadRemoteImplicit() = let { itemsRemote.clear(); itemsSearch.clear() }
.run { downloadRepos() }
.applyViewModel(this, false)
.subscribeK { refresh(); submitQuery() }
......@@ -156,10 +178,7 @@ class ModuleViewModel(
remoteJob = Single.fromCallable { itemsRemote.size }
.flatMap { loadRemoteInternal(offset = it) }
.subscribeK(onError = Timber::e) {
if (!items.contains(sectionRemote)) {
items.add(sectionRemote)
}
items.addAll(it)
itemsRemote.addAll(it)
}
}
......@@ -201,7 +220,7 @@ class ModuleViewModel(
private fun loadRemoteInternal(
offset: Int = 0,
downloadRepos: Boolean = offset == 0
): Single<List<RepoItem>> = Single.fromCallable { dao.getRepos(offset) }
): Single<List<RepoItem.Remote>> = Single.fromCallable { dao.getRepos(offset) }
.map { it.map { RepoItem.Remote(it) } }
.flatMap {
when {
......@@ -260,7 +279,7 @@ class ModuleViewModel(
updateOrderIcon()
Single.fromCallable { itemsRemote }
.subscribeK {
items.removeAll(it)
itemsRemote.removeAll(it)
remoteJob?.dispose()
loadRemote()
}.add()
......@@ -275,24 +294,4 @@ class ModuleViewModel(
OpenChangelogEvent(item.repo ?: return).publish()
}
// ---
/** Callable only from worker thread because of expensive list filtering */
@WorkerThread
private fun build(
active: List<ModuleItem> = itemsInstalled,
updatable: List<RepoItem.Update> = itemsUpdatable,
remote: List<RepoItem.Remote> = itemsRemote
) = (active + InstallModule)
.prependIfNotEmpty { sectionActive }
.prependIf(Config.coreOnly) { SafeModeNotice } +
updatable.prependIfNotEmpty { sectionUpdate } +
remote.prependIfNotEmpty { sectionRemote }
private fun <T> List<T>.prependIf(condition: Boolean, item: () -> T) =
if (condition) listOf(item()) + this else this
private fun <T> List<T>.prependIfNotEmpty(item: () -> T) =
prependIf(isNotEmpty(), item)
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.TextItem" />
</data>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="@dimen/l1"
android:text="@{item.text}"
android:textAppearance="@style/AppearanceFoundation.Tiny.Variant"
tools:text="@tools:sample/lorem/random" />
</layout>
\ No newline at end of file
......@@ -85,6 +85,8 @@
<string name="module_state_remove">Remove</string>
<string name="module_state_restore">Restore</string>
<string name="module_action_install_external">Install from storage</string>
<string name="module_update_none">Your modules are up to date!</string>
<string name="module_install_none">No modules detected, try installing one from the list below.</string>
<string name="superuser_toggle_log">Logs</string>
<string name="superuser_toggle_notification">Notifications</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment