diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt index 2f160e3b2..242bb8521 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt @@ -1,8 +1,6 @@ package com.topjohnwu.magisk.model.entity.recycler import android.content.res.Resources -import android.view.View -import android.view.ViewGroup import androidx.annotation.StringRes import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ComparableRvItem @@ -13,8 +11,6 @@ import com.topjohnwu.magisk.model.entity.module.Module import com.topjohnwu.magisk.model.entity.module.Repo import com.topjohnwu.magisk.redesign.module.ModuleViewModel import com.topjohnwu.magisk.utils.KObservableField -import com.topjohnwu.magisk.utils.rotationTo -import com.topjohnwu.magisk.utils.setRevealed class ModuleRvItem(val item: Module) : ComparableRvItem() { @@ -83,22 +79,29 @@ class ModuleItem(val item: Module) : ComparableRvItem() { override val layoutRes = R.layout.item_module_md2 - val isExpanded = KObservableField(false) val isEnabled = KObservableField(item.enable) + val isRemoved = KObservableField(item.remove) + val isUpdated get() = item.updated - val isModified get() = item.enable != isEnabled.value + val isModified get() = item.remove || item.updated + + init { + isEnabled.addOnPropertyChangedCallback { + item.enable = it ?: return@addOnPropertyChangedCallback + } + isRemoved.addOnPropertyChangedCallback { + item.remove = it ?: return@addOnPropertyChangedCallback + } + } fun toggle(viewModel: ModuleViewModel) { isEnabled.toggle() - viewModel.moveToState(this) + viewModel.updateState() } - fun toggle(view: View) { - isExpanded.toggle() - view.rotationTo(if (isExpanded.value) 225 else 180) - (view.parent as ViewGroup) - .findViewById(R.id.module_expand_container) - .setRevealed(isExpanded.value) + fun delete(viewModel: ModuleViewModel) { + isRemoved.toggle() + viewModel.updateState() } override fun contentSameAs(other: ModuleItem): Boolean = item.version == other.item.version diff --git a/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleViewModel.kt index 0b65aabe4..be59a5f17 100644 --- a/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleViewModel.kt @@ -1,5 +1,7 @@ package com.topjohnwu.magisk.redesign.module +import androidx.annotation.WorkerThread +import androidx.recyclerview.widget.DiffUtil import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.model.entity.module.Module @@ -7,6 +9,8 @@ import com.topjohnwu.magisk.model.entity.recycler.ModuleItem import com.topjohnwu.magisk.redesign.compat.CompatViewModel import com.topjohnwu.magisk.redesign.home.itemBindingOf import com.topjohnwu.magisk.redesign.superuser.diffListOf +import com.topjohnwu.magisk.utils.DiffObservableList +import com.topjohnwu.magisk.utils.currentLocale import io.reactivex.Single class ModuleViewModel : CompatViewModel() { @@ -19,31 +23,65 @@ class ModuleViewModel : CompatViewModel() { override fun refresh() = Single.fromCallable { Module.loadModules() } .map { it.map { ModuleItem(it) } } - .map { it to items.calculateDiff(it) } - .subscribeK { - items.update(it.first, it.second) - items.forEach { moveToState(it) } - } + .map { it.order() } + .subscribeK { it.forEach { it.update() } } - fun moveToState(item: ModuleItem) { - val isActive = items.indexOfFirst { it.itemSameAs(item) } != -1 - val isPending = itemsPending.indexOfFirst { it.itemSameAs(item) } != -1 - - when { - isActive && isPending -> if (item.isModified) { - items.remove(item) - } else { - itemsPending.remove(item) - } - isActive && item.isModified -> { - items.remove(item) - itemsPending.add(item) - } - isPending && !item.isModified -> { - itemsPending.remove(item) - items.add(item) + @WorkerThread + private fun List.order() = sortedBy { it.item.name.toLowerCase(currentLocale) } + .groupBy { + when { + it.isModified -> ModuleState.Modified + else -> ModuleState.Normal } } + .map { + val diff = when (it.key) { + ModuleState.Modified -> itemsPending + ModuleState.Normal -> items + }.calculateDiff(it.value) + ResultEnclosure(it.key, it.value, diff) + } + .ensureAllStates() + + private fun List.ensureAllStates(): List { + val me = this as? MutableList ?: this.toMutableList() + ModuleState.values().forEach { + if (me.none { rit -> it == rit.state }) { + me.add(ResultEnclosure(it, listOf(), null)) + } + } + return me + } + + fun updateState() { + // I don't feel like bothering with moving every single item to its updated state, + // so this kind of wasteful operation helps with that + Single.fromCallable { items + itemsPending } + .map { it.order() } + .subscribeK { it.forEach { it.update() } } + } + + private enum class ModuleState { + Modified, Normal + } + + private data class ResultEnclosure( + val state: ModuleState, + val list: List, + val diff: DiffUtil.DiffResult? + ) + + private fun ResultEnclosure.update() = when (state) { + ModuleState.Modified -> itemsPending + ModuleState.Normal -> items + }.update(list, diff) + + private fun DiffObservableList.update(list: List, diff: DiffUtil.DiffResult?) { + diff ?: let { + update(list) + return + } + update(list, diff) } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete_restore.xml b/app/src/main/res/drawable/ic_delete_restore.xml new file mode 100644 index 000000000..9ad463424 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_restore.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_module_md2.xml b/app/src/main/res/layout/item_module_md2.xml index 3e43f20e6..6ee1813b6 100644 --- a/app/src/main/res/layout/item_module_md2.xml +++ b/app/src/main/res/layout/item_module_md2.xml @@ -5,6 +5,8 @@ + + + + @@ -71,35 +86,18 @@ tools:lines="4" tools:text="@tools:sample/lorem/random" /> + + - - - - - - - -