mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 12:05:30 +00:00
Cleanup more databinding implementation
This commit is contained in:
parent
1620e15f99
commit
0b987dd0b0
@ -1,31 +1,26 @@
|
|||||||
package com.topjohnwu.magisk.databinding
|
package com.topjohnwu.magisk.databinding
|
||||||
|
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
import androidx.databinding.ListChangeRegistry
|
import androidx.databinding.ListChangeRegistry
|
||||||
import androidx.databinding.ObservableList
|
import androidx.databinding.ObservableList
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListUpdateCallback
|
import androidx.recyclerview.widget.ListUpdateCallback
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.AbstractList
|
import java.util.AbstractList
|
||||||
|
|
||||||
open class DiffObservableList<T>(
|
open class DiffObservableList<T : DiffItem<*>>
|
||||||
private val callback: Callback<T>
|
: AbstractList<T>(), ObservableList<T>, ListUpdateCallback {
|
||||||
) : AbstractList<T>(), ObservableList<T> {
|
|
||||||
|
|
||||||
protected var list: List<T> = emptyList()
|
protected var list: List<T> = emptyList()
|
||||||
|
private set
|
||||||
private val listeners = ListChangeRegistry()
|
private val listeners = ListChangeRegistry()
|
||||||
protected val listCallback = ObservableListUpdateCallback()
|
|
||||||
|
|
||||||
override val size: Int get() = list.size
|
override val size: Int get() = list.size
|
||||||
|
|
||||||
override fun get(index: Int) = list[index]
|
override fun get(index: Int) = list[index]
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the list of update operations that can convert this list into the given one.
|
|
||||||
*
|
|
||||||
* @param newItems The items that this list will be set to.
|
|
||||||
* @return A DiffResult that contains the information about the edit sequence to covert this
|
|
||||||
* list into the given one.
|
|
||||||
*/
|
|
||||||
fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult {
|
fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult {
|
||||||
return doCalculateDiff(list, newItems)
|
return doCalculateDiff(list, newItems)
|
||||||
}
|
}
|
||||||
@ -36,31 +31,34 @@ open class DiffObservableList<T>(
|
|||||||
|
|
||||||
override fun getNewListSize() = newItems.size
|
override fun getNewListSize() = newItems.size
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||||
val oldItem = oldItems[oldItemPosition]
|
val oldItem = oldItems[oldItemPosition]
|
||||||
val newItem = newItems[newItemPosition]
|
val newItem = newItems[newItemPosition]
|
||||||
return callback.areItemsTheSame(oldItem, newItem)
|
return (oldItem as DiffItem<Any>).itemSameAs(newItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||||
val oldItem = oldItems[oldItemPosition]
|
val oldItem = oldItems[oldItemPosition]
|
||||||
val newItem = newItems[newItemPosition]
|
val newItem = newItems[newItemPosition]
|
||||||
return callback.areContentsTheSame(oldItem, newItem)
|
return (oldItem as DiffItem<Any>).contentSameAs(newItem)
|
||||||
}
|
}
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the contents of this list to the given one using the DiffResults to dispatch change
|
|
||||||
* notifications.
|
|
||||||
*
|
|
||||||
* @param newItems The items to set this list to.
|
|
||||||
* @param diffResult The diff results to dispatch change notifications.
|
|
||||||
*/
|
|
||||||
@MainThread
|
@MainThread
|
||||||
fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult) {
|
fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult) {
|
||||||
list = ArrayList(newItems)
|
list = ArrayList(newItems)
|
||||||
diffResult.dispatchUpdatesTo(listCallback)
|
diffResult.dispatchUpdatesTo(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
suspend fun update(newItems: List<T>) {
|
||||||
|
val diffResult = calculateDiff(newItems)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
update(newItems, diffResult)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addOnListChangedCallback(listener: ObservableList.OnListChangedCallback<out ObservableList<T>>) {
|
override fun addOnListChangedCallback(listener: ObservableList.OnListChangedCallback<out ObservableList<T>>) {
|
||||||
@ -71,36 +69,21 @@ open class DiffObservableList<T>(
|
|||||||
listeners.remove(listener)
|
listeners.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyAdd(start: Int, count: Int) {
|
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||||
listeners.notifyInserted(this, start, count)
|
listeners.notifyChanged(this, position, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyRemove(start: Int, count: Int) {
|
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||||
listeners.notifyRemoved(this, start, count)
|
listeners.notifyMoved(this, fromPosition, toPosition, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Callback<T> {
|
override fun onInserted(position: Int, count: Int) {
|
||||||
fun areItemsTheSame(oldItem: T, newItem: T): Boolean
|
modCount += 1
|
||||||
fun areContentsTheSame(oldItem: T, newItem: T): Boolean
|
listeners.notifyInserted(this, position, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ObservableListUpdateCallback : ListUpdateCallback {
|
override fun onRemoved(position: Int, count: Int) {
|
||||||
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
modCount += 1
|
||||||
listeners.notifyChanged(this@DiffObservableList, position, count)
|
listeners.notifyRemoved(this, position, count)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
|
||||||
listeners.notifyMoved(this@DiffObservableList, fromPosition, toPosition, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onInserted(position: Int, count: Int) {
|
|
||||||
modCount += 1
|
|
||||||
listeners.notifyInserted(this@DiffObservableList, position, count)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRemoved(position: Int, count: Int) {
|
|
||||||
modCount += 1
|
|
||||||
listeners.notifyRemoved(this@DiffObservableList, position, count)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,9 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
open class FilterableDiffObservableList<T>(
|
open class FilterableDiffObservableList<T : DiffItem<*>>(
|
||||||
callback: Callback<T>,
|
|
||||||
private val scope: CoroutineScope
|
private val scope: CoroutineScope
|
||||||
) : DiffObservableList<T>(callback) {
|
) : DiffObservableList<T>() {
|
||||||
|
|
||||||
private var sublist: List<T> = emptyList()
|
private var sublist: List<T> = emptyList()
|
||||||
private var job: Job? = null
|
private var job: Job? = null
|
||||||
@ -24,7 +23,7 @@ open class FilterableDiffObservableList<T>(
|
|||||||
val diff = doCalculateDiff(oldList, newList)
|
val diff = doCalculateDiff(oldList, newList)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
sublist = newList
|
sublist = newList
|
||||||
diff.dispatchUpdatesTo(listCallback)
|
diff.dispatchUpdatesTo(this@FilterableDiffObservableList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,69 +3,33 @@ package com.topjohnwu.magisk.databinding
|
|||||||
import androidx.databinding.PropertyChangeRegistry
|
import androidx.databinding.PropertyChangeRegistry
|
||||||
import androidx.databinding.ViewDataBinding
|
import androidx.databinding.ViewDataBinding
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
|
|
||||||
abstract class RvItem {
|
abstract class RvItem {
|
||||||
abstract val layoutRes: Int
|
abstract val layoutRes: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RvContainer<E> {
|
|
||||||
val item: E
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ViewAwareRvItem {
|
|
||||||
fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ComparableRv<T> : Comparable<T> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun comparableEqual(o: Any?) =
|
|
||||||
o != null && o::class == this::class && compareTo(o as T) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class DiffRvItem<T> : RvItem() {
|
|
||||||
|
|
||||||
// Defer to contentSameAs by default
|
|
||||||
open fun itemSameAs(other: T) = true
|
|
||||||
|
|
||||||
open fun contentSameAs(other: T) =
|
|
||||||
when (this) {
|
|
||||||
is RvContainer<*> -> item == (other as RvContainer<*>).item
|
|
||||||
is ComparableRv<*> -> comparableEqual(other)
|
|
||||||
else -> this == other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typealias AnyDiffRvItem = DiffRvItem<*>
|
|
||||||
|
|
||||||
abstract class ObservableDiffRvItem<T> : DiffRvItem<T>(), ObservableHost {
|
|
||||||
override var callbacks: PropertyChangeRegistry? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class ObservableRvItem : RvItem(), ObservableHost {
|
abstract class ObservableRvItem : RvItem(), ObservableHost {
|
||||||
override var callbacks: PropertyChangeRegistry? = null
|
override var callbacks: PropertyChangeRegistry? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DiffRvItemCallback : DiffObservableList.Callback<DiffRvItem<Any>> {
|
interface ItemWrapper<E> {
|
||||||
override fun areItemsTheSame(
|
val item: E
|
||||||
oldItem: DiffRvItem<Any>,
|
|
||||||
newItem: DiffRvItem<Any>
|
|
||||||
): Boolean {
|
|
||||||
return oldItem::class == newItem::class && oldItem.itemSameAs(newItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun areContentsTheSame(
|
|
||||||
oldItem: DiffRvItem<Any>,
|
|
||||||
newItem: DiffRvItem<Any>
|
|
||||||
): Boolean {
|
|
||||||
return oldItem.contentSameAs(newItem)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
interface ViewAwareItem {
|
||||||
class DiffRvItemList<T: AnyDiffRvItem> : DiffObservableList<T>(DiffRvItemCallback as Callback<T>)
|
fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
interface DiffItem<T : Any> {
|
||||||
class DiffRvItemFilterList<T: AnyDiffRvItem>(
|
|
||||||
scope: CoroutineScope
|
fun itemSameAs(other: T): Boolean {
|
||||||
) : FilterableDiffObservableList<T>(DiffRvItemCallback as Callback<T>, scope)
|
if (this === other) return true
|
||||||
|
return when (this) {
|
||||||
|
is ItemWrapper<*> -> item == (other as ItemWrapper<*>).item
|
||||||
|
is Comparable<*> -> compareValues(this, other as Comparable<*>) == 0
|
||||||
|
else -> this == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun contentSameAs(other: T) = true
|
||||||
|
}
|
||||||
|
@ -53,7 +53,7 @@ class RvItemAdapter<T: RvItem>(
|
|||||||
holder.binding.lifecycleOwner = lifecycleOwner
|
holder.binding.lifecycleOwner = lifecycleOwner
|
||||||
holder.binding.executePendingBindings()
|
holder.binding.executePendingBindings()
|
||||||
recyclerView?.let {
|
recyclerView?.let {
|
||||||
if (item is ViewAwareRvItem)
|
if (item is ViewAwareItem)
|
||||||
item.onBind(holder.binding, it)
|
item.onBind(holder.binding, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import android.view.ViewGroup
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.ComparableRv
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
import com.topjohnwu.magisk.databinding.addOnPropertyChangedCallback
|
import com.topjohnwu.magisk.databinding.addOnPropertyChangedCallback
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.ktx.startAnimations
|
import com.topjohnwu.magisk.ktx.startAnimations
|
||||||
@ -15,7 +15,7 @@ import kotlin.math.roundToInt
|
|||||||
|
|
||||||
class DenyListRvItem(
|
class DenyListRvItem(
|
||||||
val info: AppProcessInfo
|
val info: AppProcessInfo
|
||||||
) : ObservableDiffRvItem<DenyListRvItem>(), ComparableRv<DenyListRvItem> {
|
) : ObservableRvItem(), DiffItem<DenyListRvItem>, Comparable<DenyListRvItem> {
|
||||||
|
|
||||||
override val layoutRes get() = R.layout.item_hide_md2
|
override val layoutRes get() = R.layout.item_hide_md2
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class DenyListRvItem(
|
|||||||
|
|
||||||
class ProcessRvItem(
|
class ProcessRvItem(
|
||||||
val process: ProcessInfo
|
val process: ProcessInfo
|
||||||
) : ObservableDiffRvItem<ProcessRvItem>() {
|
) : ObservableRvItem(), DiffItem<ProcessRvItem> {
|
||||||
|
|
||||||
override val layoutRes get() = R.layout.item_hide_process_md2
|
override val layoutRes get() = R.layout.item_hide_process_md2
|
||||||
|
|
||||||
@ -122,10 +122,9 @@ class ProcessRvItem(
|
|||||||
val defaultSelection get() =
|
val defaultSelection get() =
|
||||||
process.isIsolated || process.isAppZygote || process.name == process.packageName
|
process.isIsolated || process.isAppZygote || process.name == process.packageName
|
||||||
|
|
||||||
override fun contentSameAs(other: ProcessRvItem) =
|
|
||||||
process.isEnabled == other.process.isEnabled
|
|
||||||
|
|
||||||
override fun itemSameAs(other: ProcessRvItem) =
|
override fun itemSameAs(other: ProcessRvItem) =
|
||||||
process.name == other.process.name && process.packageName == other.process.packageName
|
process.name == other.process.name && process.packageName == other.process.packageName
|
||||||
|
|
||||||
|
override fun contentSameAs(other: ProcessRvItem) =
|
||||||
|
process.isEnabled == other.process.isEnabled
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
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.DiffRvItemFilterList
|
import com.topjohnwu.magisk.databinding.FilterableDiffObservableList
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.ktx.concurrentMap
|
import com.topjohnwu.magisk.ktx.concurrentMap
|
||||||
@ -38,7 +38,7 @@ class DenyListViewModel : AsyncLoadViewModel() {
|
|||||||
query()
|
query()
|
||||||
}
|
}
|
||||||
|
|
||||||
val items = DiffRvItemFilterList<DenyListRvItem>(viewModelScope)
|
val items = FilterableDiffObservableList<DenyListRvItem>(viewModelScope)
|
||||||
val extraBindings = bindExtra {
|
val extraBindings = bindExtra {
|
||||||
it.put(BR.viewModel, this)
|
it.put(BR.viewModel, this)
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ class DenyListViewModel : AsyncLoadViewModel() {
|
|||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
override suspend fun doLoadWork() {
|
override suspend fun doLoadWork() {
|
||||||
loading = true
|
loading = true
|
||||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
val pm = AppContext.packageManager
|
val pm = AppContext.packageManager
|
||||||
val denyList = Shell.cmd("magisk --denylist ls").exec().out
|
val denyList = Shell.cmd("magisk --denylist ls").exec().out
|
||||||
.map { CmdlineListItem(it) }
|
.map { CmdlineListItem(it) }
|
||||||
@ -63,9 +63,8 @@ class DenyListViewModel : AsyncLoadViewModel() {
|
|||||||
.toCollection(ArrayList(size))
|
.toCollection(ArrayList(size))
|
||||||
}
|
}
|
||||||
apps.sort()
|
apps.sort()
|
||||||
apps to items.calculateDiff(apps)
|
items.update(apps)
|
||||||
}
|
}
|
||||||
items.update(apps, diff)
|
|
||||||
query()
|
query()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,14 +6,15 @@ import androidx.core.view.updateLayoutParams
|
|||||||
import androidx.databinding.ViewDataBinding
|
import androidx.databinding.ViewDataBinding
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.DiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.RvContainer
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
import com.topjohnwu.magisk.databinding.ViewAwareRvItem
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
import com.topjohnwu.magisk.databinding.ViewAwareItem
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
class ConsoleItem(
|
class ConsoleItem(
|
||||||
override val item: String
|
override val item: String
|
||||||
) : DiffRvItem<ConsoleItem>(), ViewAwareRvItem, RvContainer<String> {
|
) : RvItem(), ViewAwareItem, DiffItem<ConsoleItem>, ItemWrapper<String> {
|
||||||
override val layoutRes = R.layout.item_console_md2
|
override val layoutRes = R.layout.item_console_md2
|
||||||
|
|
||||||
private var parentWidth = -1
|
private var parentWidth = -1
|
||||||
|
@ -4,18 +4,17 @@ import androidx.databinding.ViewDataBinding
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.RvContainer
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
import com.topjohnwu.magisk.databinding.ViewAwareRvItem
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
|
import com.topjohnwu.magisk.databinding.ViewAwareItem
|
||||||
|
|
||||||
class LogRvItem(
|
class LogRvItem(
|
||||||
override val item: String
|
override val item: String
|
||||||
) : ObservableDiffRvItem<LogRvItem>(), RvContainer<String>, ViewAwareRvItem {
|
) : ObservableRvItem(), DiffItem<LogRvItem>, ItemWrapper<String>, ViewAwareItem {
|
||||||
|
|
||||||
override val layoutRes = R.layout.item_log_textview
|
override val layoutRes = R.layout.item_log_textview
|
||||||
|
|
||||||
override fun itemSameAs(other: LogRvItem) = item == other.item
|
|
||||||
|
|
||||||
override fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView) {
|
override fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView) {
|
||||||
val view = binding.root as MaterialTextView
|
val view = binding.root as MaterialTextView
|
||||||
view.measure(0, 0)
|
view.measure(0, 0)
|
||||||
|
@ -11,7 +11,7 @@ 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
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
import com.topjohnwu.magisk.databinding.DiffRvItemList
|
import com.topjohnwu.magisk.databinding.DiffObservableList
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
@ -37,28 +37,26 @@ class LogViewModel(
|
|||||||
|
|
||||||
// --- su log
|
// --- su log
|
||||||
|
|
||||||
val items = DiffRvItemList<SuLogRvItem>()
|
val items = DiffObservableList<SuLogRvItem>()
|
||||||
val extraBindings = bindExtra {
|
val extraBindings = bindExtra {
|
||||||
it.put(BR.viewModel, this)
|
it.put(BR.viewModel, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- magisk log
|
// --- magisk log
|
||||||
val logs = DiffRvItemList<LogRvItem>()
|
val logs = DiffObservableList<LogRvItem>()
|
||||||
var magiskLogRaw = " "
|
var magiskLogRaw = " "
|
||||||
|
|
||||||
override suspend fun doLoadWork() {
|
override suspend fun doLoadWork() {
|
||||||
loading = true
|
loading = true
|
||||||
val (logs, logDiff) = withContext(Dispatchers.Default) {
|
|
||||||
magiskLogRaw = repo.fetchMagiskLogs()
|
|
||||||
val logs = magiskLogRaw.split('\n').map { LogRvItem(it) }
|
|
||||||
logs to this@LogViewModel.logs.calculateDiff(logs)
|
|
||||||
}
|
|
||||||
this.logs.update(logs, logDiff)
|
|
||||||
|
|
||||||
val (suLogs, suDiff) = withContext(Dispatchers.Default) {
|
val (suLogs, suDiff) = withContext(Dispatchers.Default) {
|
||||||
|
magiskLogRaw = repo.fetchMagiskLogs()
|
||||||
|
val newLogs = magiskLogRaw.split('\n').map { LogRvItem(it) }
|
||||||
|
logs.update(newLogs)
|
||||||
val suLogs = repo.fetchSuLogs().map { SuLogRvItem(it) }
|
val suLogs = repo.fetchSuLogs().map { SuLogRvItem(it) }
|
||||||
suLogs to items.calculateDiff(suLogs)
|
suLogs to items.calculateDiff(suLogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
items.firstOrNull()?.isTop = false
|
items.firstOrNull()?.isTop = false
|
||||||
items.lastOrNull()?.isBottom = false
|
items.lastOrNull()?.isBottom = false
|
||||||
items.update(suLogs, suDiff)
|
items.update(suLogs, suDiff)
|
||||||
|
@ -4,19 +4,17 @@ import androidx.databinding.Bindable
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.model.su.SuLog
|
import com.topjohnwu.magisk.core.model.su.SuLog
|
||||||
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.RvContainer
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.ktx.timeDateFormat
|
import com.topjohnwu.magisk.ktx.timeDateFormat
|
||||||
import com.topjohnwu.magisk.ktx.toTime
|
import com.topjohnwu.magisk.ktx.toTime
|
||||||
|
|
||||||
class SuLogRvItem(
|
class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
|
||||||
override val item: SuLog
|
|
||||||
) : ObservableDiffRvItem<SuLogRvItem>(), RvContainer<SuLog> {
|
|
||||||
|
|
||||||
override val layoutRes = R.layout.item_log_access_md2
|
override val layoutRes = R.layout.item_log_access_md2
|
||||||
|
|
||||||
val date = item.time.toTime(timeDateFormat)
|
val date = log.time.toTime(timeDateFormat)
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var isTop = false
|
var isTop = false
|
||||||
@ -26,5 +24,5 @@ class SuLogRvItem(
|
|||||||
var isBottom = false
|
var isBottom = false
|
||||||
set(value) = set(value, field, { field = it }, BR.bottom)
|
set(value) = set(value, field, { field = it }, BR.bottom)
|
||||||
|
|
||||||
override fun itemSameAs(other: SuLogRvItem) = item.appName == other.item.appName
|
override fun itemSameAs(other: SuLogRvItem) = log.appName == other.log.appName
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,21 @@ import com.topjohnwu.magisk.BR
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||||
import com.topjohnwu.magisk.databinding.DiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
import com.topjohnwu.magisk.databinding.RvContainer
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.utils.TextHolder
|
import com.topjohnwu.magisk.utils.TextHolder
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
|
|
||||||
object InstallModule : DiffRvItem<InstallModule>() {
|
object InstallModule : RvItem(), DiffItem<InstallModule> {
|
||||||
override val layoutRes = R.layout.item_module_download
|
override val layoutRes = R.layout.item_module_download
|
||||||
}
|
}
|
||||||
|
|
||||||
class LocalModuleRvItem(
|
class LocalModuleRvItem(
|
||||||
override val item: LocalModule
|
override val item: LocalModule
|
||||||
) : ObservableDiffRvItem<LocalModuleRvItem>(), RvContainer<LocalModule> {
|
) : ObservableRvItem(), DiffItem<LocalModuleRvItem>, ItemWrapper<LocalModule> {
|
||||||
|
|
||||||
override val layoutRes = R.layout.item_module_md2
|
override val layoutRes = R.layout.item_module_md2
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ 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
|
||||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||||
import com.topjohnwu.magisk.databinding.DiffRvItemList
|
import com.topjohnwu.magisk.databinding.DiffObservableList
|
||||||
import com.topjohnwu.magisk.databinding.MergeObservableList
|
import com.topjohnwu.magisk.databinding.MergeObservableList
|
||||||
import com.topjohnwu.magisk.databinding.RvItem
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
@ -26,7 +26,7 @@ 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)
|
||||||
|
|
||||||
private val itemsInstalled = DiffRvItemList<LocalModuleRvItem>()
|
private val itemsInstalled = DiffObservableList<LocalModuleRvItem>()
|
||||||
|
|
||||||
val items = MergeObservableList<RvItem>()
|
val items = MergeObservableList<RvItem>()
|
||||||
val extraBindings = bindExtra {
|
val extraBindings = bindExtra {
|
||||||
@ -57,11 +57,10 @@ class ModuleViewModel : AsyncLoadViewModel() {
|
|||||||
override fun onNetworkChanged(network: Boolean) = startLoading()
|
override fun onNetworkChanged(network: Boolean) = startLoading()
|
||||||
|
|
||||||
private suspend fun loadInstalled() {
|
private suspend fun loadInstalled() {
|
||||||
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
withContext(Dispatchers.Default) {
|
||||||
val diff = withContext(Dispatchers.Default) {
|
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
||||||
itemsInstalled.calculateDiff(installed)
|
itemsInstalled.update(installed)
|
||||||
}
|
}
|
||||||
itemsInstalled.update(installed, diff)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadUpdateInfo() {
|
private suspend fun loadUpdateInfo() {
|
||||||
|
@ -5,8 +5,9 @@ import androidx.databinding.Bindable
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.RvContainer
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
|
|
||||||
class PolicyRvItem(
|
class PolicyRvItem(
|
||||||
@ -16,7 +17,7 @@ class PolicyRvItem(
|
|||||||
private val isSharedUid: Boolean,
|
private val isSharedUid: Boolean,
|
||||||
val icon: Drawable,
|
val icon: Drawable,
|
||||||
val appName: String
|
val appName: String
|
||||||
) : ObservableDiffRvItem<PolicyRvItem>(), RvContainer<SuPolicy> {
|
) : ObservableRvItem(), DiffItem<PolicyRvItem>, ItemWrapper<SuPolicy> {
|
||||||
|
|
||||||
override val layoutRes = R.layout.item_policy_md2
|
override val layoutRes = R.layout.item_policy_md2
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ class SuperuserViewModel(
|
|||||||
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
||||||
|
|
||||||
private val itemsHelpers = ObservableArrayList<TextItem>()
|
private val itemsHelpers = ObservableArrayList<TextItem>()
|
||||||
private val itemsPolicies = DiffRvItemList<PolicyRvItem>()
|
private val itemsPolicies = DiffObservableList<PolicyRvItem>()
|
||||||
|
|
||||||
val items = MergeObservableList<AnyDiffRvItem>()
|
val items = MergeObservableList<RvItem>()
|
||||||
.insertList(itemsHelpers)
|
.insertList(itemsHelpers)
|
||||||
.insertList(itemsPolicies)
|
.insertList(itemsPolicies)
|
||||||
val extraBindings = bindExtra {
|
val extraBindings = bindExtra {
|
||||||
@ -54,7 +54,7 @@ class SuperuserViewModel(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
loading = true
|
loading = true
|
||||||
val (policies, diff) = withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.deleteOutdated()
|
db.deleteOutdated()
|
||||||
db.delete(AppContext.applicationInfo.uid)
|
db.delete(AppContext.applicationInfo.uid)
|
||||||
val policies = ArrayList<PolicyRvItem>()
|
val policies = ArrayList<PolicyRvItem>()
|
||||||
@ -91,9 +91,8 @@ class SuperuserViewModel(
|
|||||||
{ it.appName.lowercase(currentLocale) },
|
{ it.appName.lowercase(currentLocale) },
|
||||||
{ it.packageName }
|
{ it.packageName }
|
||||||
))
|
))
|
||||||
policies to itemsPolicies.calculateDiff(policies)
|
itemsPolicies.update(policies)
|
||||||
}
|
}
|
||||||
itemsPolicies.update(policies, diff)
|
|
||||||
if (itemsPolicies.isNotEmpty())
|
if (itemsPolicies.isNotEmpty())
|
||||||
itemsHelpers.clear()
|
itemsHelpers.clear()
|
||||||
else if (itemsHelpers.isEmpty())
|
else if (itemsHelpers.isEmpty())
|
||||||
|
@ -22,7 +22,14 @@ import com.google.android.material.shape.MaterialShapeDrawable
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||||
import com.topjohnwu.magisk.databinding.*
|
import com.topjohnwu.magisk.databinding.DialogMagiskBaseBinding
|
||||||
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
|
import com.topjohnwu.magisk.databinding.ObservableHost
|
||||||
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
|
import com.topjohnwu.magisk.databinding.set
|
||||||
|
import com.topjohnwu.magisk.databinding.setAdapter
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog.DialogClickListener
|
import com.topjohnwu.magisk.view.MagiskDialog.DialogClickListener
|
||||||
|
|
||||||
typealias DialogButtonClickListener = (DialogInterface) -> Unit
|
typealias DialogButtonClickListener = (DialogInterface) -> Unit
|
||||||
@ -166,7 +173,7 @@ class MagiskDialog(
|
|||||||
class DialogItem(
|
class DialogItem(
|
||||||
override val item: CharSequence,
|
override val item: CharSequence,
|
||||||
val position: Int
|
val position: Int
|
||||||
) : DiffRvItem<DialogItem>(), RvContainer<CharSequence> {
|
) : RvItem(), DiffItem<DialogItem>, ItemWrapper<CharSequence> {
|
||||||
override val layoutRes = R.layout.item_list_single_line
|
override val layoutRes = R.layout.item_list_single_line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package com.topjohnwu.magisk.view
|
package com.topjohnwu.magisk.view
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.DiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
|
||||||
sealed class TappableHeadlineItem : DiffRvItem<TappableHeadlineItem>() {
|
sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
|
||||||
|
|
||||||
abstract val title: Int
|
abstract val title: Int
|
||||||
abstract val icon: Int
|
abstract val icon: Int
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.topjohnwu.magisk.view
|
package com.topjohnwu.magisk.view
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.DiffRvItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
|
||||||
class TextItem(val text: Int) : DiffRvItem<TextItem>() {
|
class TextItem(override val item: Int) : RvItem(), DiffItem<TextItem>, ItemWrapper<Int> {
|
||||||
override val layoutRes = R.layout.item_text
|
override val layoutRes = R.layout.item_text
|
||||||
|
|
||||||
override fun contentSameAs(other: TextItem) = text == other.text
|
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/log_track_container"
|
android:id="@+id/log_track_container"
|
||||||
bullet="@{item.item.action ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
|
bullet="@{item.log.action ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
|
||||||
isBottom="@{item.isBottom}"
|
isBottom="@{item.isBottom}"
|
||||||
isSelected="@{!item.item.action}"
|
isSelected="@{!item.log.action}"
|
||||||
isTop="@{item.isTop}"
|
isTop="@{item.isTop}"
|
||||||
layout="@layout/item_log_track_md2"
|
layout="@layout/item_log_track_md2"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -51,7 +51,7 @@
|
|||||||
android:id="@+id/log_app_name"
|
android:id="@+id/log_app_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{item.item.appName}"
|
android:text="@{item.log.appName}"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body"
|
android:textAppearance="@style/AppearanceFoundation.Body"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/log_date"
|
app:layout_constraintBottom_toTopOf="@+id/log_date"
|
||||||
@ -76,7 +76,7 @@
|
|||||||
android:id="@+id/log_app_details"
|
android:id="@+id/log_app_details"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{String.format(`%s %s`, @string/pid(item.item.fromPid), @string/target_uid(item.item.toUid))}"
|
android:text="@{String.format(`%s %s`, @string/pid(item.log.fromPid), @string/target_uid(item.log.toUid))}"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
|
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
|
||||||
app:layout_constraintBottom_toTopOf="@id/log_command"
|
app:layout_constraintBottom_toTopOf="@id/log_command"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@ -89,7 +89,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="monospace"
|
android:fontFamily="monospace"
|
||||||
android:text="@{item.item.command}"
|
android:text="@{item.log.command}"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
|
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="@dimen/l1"
|
android:padding="@dimen/l1"
|
||||||
android:text="@{item.text}"
|
android:text="@{item.item}"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Tiny.Variant"
|
android:textAppearance="@style/AppearanceFoundation.Tiny.Variant"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user