Remove usage of BindingCollectionAdapter (part 1)

This commit is contained in:
topjohnwu 2022-06-02 20:55:19 -07:00
parent 2ed092c9db
commit 6305159c5e
25 changed files with 166 additions and 167 deletions

View File

@ -81,7 +81,6 @@ dependencies {
val vBAdapt = "4.0.0" val vBAdapt = "4.0.0"
val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter" val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter"
implementation("${bindingAdapter}:${vBAdapt}") implementation("${bindingAdapter}:${vBAdapt}")
implementation("${bindingAdapter}-recyclerview:${vBAdapt}")
val vLibsu = "5.0.2" val vLibsu = "5.0.2"
implementation("com.github.topjohnwu.libsu:core:${vLibsu}") implementation("com.github.topjohnwu.libsu:core:${vLibsu}")

View File

@ -1,13 +0,0 @@
package com.topjohnwu.magisk.databinding
import androidx.databinding.ViewDataBinding
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
open class BindingBoundAdapter : BindingRecyclerViewAdapter<RvItem>() {
override fun onBindBinding(binding: ViewDataBinding, variableId: Int, layoutRes: Int, position: Int, item: RvItem) {
super.onBindBinding(binding, variableId, layoutRes, position, item)
item.onBindingBound(binding)
}
}

View File

@ -1,35 +1,7 @@
package com.topjohnwu.magisk.databinding package com.topjohnwu.magisk.databinding
import androidx.databinding.ViewDataBinding
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
import me.tatarka.bindingcollectionadapter2.ItemBinding
import me.tatarka.bindingcollectionadapter2.OnItemBind
fun <T : AnyDiffRvItem> diffListOf() = fun <T : AnyDiffRvItem> diffListOf() =
DiffObservableList(DiffRvItem.callback<T>()) DiffObservableList(DiffRvItem.callback<T>())
fun <T : AnyDiffRvItem> diffListOf(newItems: List<T>) =
DiffObservableList(DiffRvItem.callback<T>()).also { it.update(newItems) }
fun <T : AnyDiffRvItem> filterableListOf() = fun <T : AnyDiffRvItem> filterableListOf() =
FilterableDiffObservableList(DiffRvItem.callback<T>()) FilterableDiffObservableList(DiffRvItem.callback<T>())
fun <T : RvItem> adapterOf() = object : BindingRecyclerViewAdapter<T>() {
override fun onBindBinding(
binding: ViewDataBinding,
variableId: Int,
layoutRes: Int,
position: Int,
item: T
) {
super.onBindBinding(binding, variableId, layoutRes, position, item)
item.onBindingBound(binding)
}
}
inline fun <T : RvItem> itemBindingOf(
crossinline body: (ItemBinding<*>) -> Unit = {}
) = OnItemBind<T> { itemBinding, _, item ->
item.bind(itemBinding)
body(itemBinding)
}

View File

@ -1,33 +1,21 @@
package com.topjohnwu.magisk.databinding package com.topjohnwu.magisk.databinding
import androidx.annotation.CallSuper
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 com.topjohnwu.magisk.BR
import me.tatarka.bindingcollectionadapter2.ItemBinding
abstract class RvItem { abstract class RvItem {
abstract val layoutRes: Int abstract val layoutRes: Int
@CallSuper
open fun bind(binding: ItemBinding<*>) {
binding.set(BR.item, layoutRes)
}
/**
* This callback is useful if you want to manipulate your views directly.
* If you want to use this callback, you must set [me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter]
* on your RecyclerView and call it from there. You can use [BindingBoundAdapter] for your convenience.
*/
open fun onBindingBound(binding: ViewDataBinding) {}
} }
interface RvContainer<E> { interface RvContainer<E> {
val item: E val item: E
} }
interface ViewAwareRvItem {
fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView)
}
interface ComparableRv<T> : Comparable<T> { interface ComparableRv<T> : Comparable<T> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun comparableEqual(o: Any?) = fun comparableEqual(o: Any?) =
@ -77,13 +65,3 @@ abstract class ObservableDiffRvItem<T> : DiffRvItem<T>(), ObservableHost {
abstract class ObservableRvItem : RvItem(), ObservableHost { abstract class ObservableRvItem : RvItem(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null override var callbacks: PropertyChangeRegistry? = null
} }
/**
* This item addresses issues where enclosing recycler has to be invalidated or generally
* manipulated with. This shouldn't be however necessary for 99.9% of use-cases. Refrain from using
* this item as it provides virtually no additional functionality. Stick with ComparableRvItem.
* */
interface LenientRvItem {
fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView)
}

View File

@ -1,35 +0,0 @@
package com.topjohnwu.magisk.databinding
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
class RvBindingAdapter<T : RvItem> : BindingRecyclerViewAdapter<T>() {
private var recyclerView: RecyclerView? = null
override fun onBindBinding(
binding: ViewDataBinding,
variableId: Int,
layoutRes: Int,
position: Int,
item: T
) {
super.onBindBinding(binding, variableId, layoutRes, position, item)
when (item) {
is LenientRvItem -> {
val recycler = recyclerView ?: return
item.onBindingBound(binding)
item.onBindingBound(binding, recycler)
}
else -> item.onBindingBound(binding)
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
this.recyclerView = recyclerView
}
}

View File

@ -0,0 +1,118 @@
package com.topjohnwu.magisk.databinding
import android.annotation.SuppressLint
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.BindingAdapter
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableList
import androidx.databinding.ObservableList.OnListChangedCallback
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.BR
class RvItemAdapter<T: RvItem>(
private val items: List<T>,
private val extraBindings: SparseArray<*>?
) : RecyclerView.Adapter<RvItemAdapter.ViewHolder>() {
private var lifecycleOwner: LifecycleOwner? = null
private var recyclerView: RecyclerView? = null
private val observer by lazy(LazyThreadSafetyMode.NONE) { ListObserver<T>() }
override fun onAttachedToRecyclerView(rv: RecyclerView) {
lifecycleOwner = rv.findViewTreeLifecycleOwner()
recyclerView = rv
if (items is ObservableList)
items.addOnListChangedCallback(observer)
}
override fun onDetachedFromRecyclerView(rv: RecyclerView) {
lifecycleOwner = null
recyclerView = null
if (items is ObservableList)
items.removeOnListChangedCallback(observer)
}
override fun onCreateViewHolder(parent: ViewGroup, layoutRes: Int): ViewHolder {
val inflator = LayoutInflater.from(parent.context)
return ViewHolder(DataBindingUtil.inflate(inflator, layoutRes, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
holder.binding.setVariable(BR.item, item)
extraBindings?.let {
for (i in 0 until it.size()) {
holder.binding.setVariable(it.keyAt(i), it.valueAt(i))
}
}
holder.binding.lifecycleOwner = lifecycleOwner
holder.binding.executePendingBindings()
recyclerView?.let {
if (item is ViewAwareRvItem)
item.onBind(holder.binding, it)
}
}
override fun getItemCount() = items.size
override fun getItemViewType(position: Int) = items[position].layoutRes
class ViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root)
inner class ListObserver<T: RvItem> : OnListChangedCallback<ObservableList<T>>() {
@SuppressLint("NotifyDataSetChanged")
override fun onChanged(sender: ObservableList<T>) {
notifyDataSetChanged()
}
override fun onItemRangeChanged(
sender: ObservableList<T>,
positionStart: Int,
itemCount: Int
) {
notifyItemRangeChanged(positionStart, itemCount)
}
override fun onItemRangeInserted(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
notifyItemRangeInserted(positionStart, itemCount)
}
override fun onItemRangeMoved(
sender: ObservableList<T>?,
fromPosition: Int,
toPosition: Int,
itemCount: Int
) {
for (i in 0 until itemCount) {
notifyItemMoved(fromPosition + i, toPosition + i)
}
}
override fun onItemRangeRemoved(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
notifyItemRangeRemoved(positionStart, itemCount)
}
}
}
inline fun bindExtra(body: (SparseArray<Any?>) -> Unit) = SparseArray<Any?>().also(body)
@BindingAdapter("items", "extraBindings", requireAll = false)
fun <T: RvItem> RecyclerView.setAdapter(items: List<T>?, extraBindings: SparseArray<*>?) {
if (items != null) {
adapter = RvItemAdapter(items, extraBindings)
}
}

View File

@ -6,8 +6,8 @@ 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.BaseViewModel
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.filterableListOf import com.topjohnwu.magisk.databinding.filterableListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.ktx.concurrentMap import com.topjohnwu.magisk.ktx.concurrentMap
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -39,11 +39,8 @@ class DenyListViewModel : BaseViewModel() {
} }
val items = filterableListOf<DenyListRvItem>() val items = filterableListOf<DenyListRvItem>()
val itemBinding = itemBindingOf<DenyListRvItem> { val extraBindings = bindExtra {
it.bindExtra(BR.viewModel, this) it.put(BR.viewModel, this)
}
val itemInternalBinding = itemBindingOf<ProcessRvItem> {
it.bindExtra(BR.viewModel, this)
} }
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")

View File

@ -7,19 +7,18 @@ 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.DiffRvItem
import com.topjohnwu.magisk.databinding.LenientRvItem
import com.topjohnwu.magisk.databinding.RvContainer import com.topjohnwu.magisk.databinding.RvContainer
import com.topjohnwu.magisk.databinding.ViewAwareRvItem
import kotlin.math.max import kotlin.math.max
class ConsoleItem( class ConsoleItem(
override val item: String override val item: String
) : DiffRvItem<ConsoleItem>(), LenientRvItem, ) : DiffRvItem<ConsoleItem>(), ViewAwareRvItem, RvContainer<String> {
RvContainer<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
override fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView) { override fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView) {
if (parentWidth < 0) if (parentWidth < 0)
parentWidth = (recyclerView.parent as View).width parentWidth = (recyclerView.parent as View).width

View File

@ -14,9 +14,7 @@ import com.topjohnwu.magisk.core.tasks.FlashZip
import com.topjohnwu.magisk.core.tasks.MagiskInstaller import com.topjohnwu.magisk.core.tasks.MagiskInstaller
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.RvBindingAdapter
import com.topjohnwu.magisk.databinding.diffListOf import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.reboot import com.topjohnwu.magisk.ktx.reboot
@ -36,9 +34,7 @@ class FlashViewModel : BaseViewModel() {
private val _subtitle = MutableLiveData(R.string.flashing) private val _subtitle = MutableLiveData(R.string.flashing)
val subtitle get() = _subtitle as LiveData<Int> val subtitle get() = _subtitle as LiveData<Int>
val adapter = RvBindingAdapter<ConsoleItem>()
val items = diffListOf<ConsoleItem>() val items = diffListOf<ConsoleItem>()
val itemBinding = itemBindingOf<ConsoleItem>()
lateinit var args: FlashFragmentArgs lateinit var args: FlashFragmentArgs
private val logItems = mutableListOf<String>().synchronized() private val logItems = mutableListOf<String>().synchronized()

View File

@ -12,7 +12,7 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.Subject import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.download.Subject.App import com.topjohnwu.magisk.core.download.Subject.App
import com.topjohnwu.magisk.core.repository.NetworkService import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.databinding.itemBindingOf 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
import com.topjohnwu.magisk.events.dialog.EnvFixDialog import com.topjohnwu.magisk.events.dialog.EnvFixDialog
@ -75,8 +75,8 @@ class HomeViewModel(
var stateManagerProgress = 0 var stateManagerProgress = 0
set(value) = set(value, field, { field = it }, BR.stateManagerProgress) set(value) = set(value, field, { field = it }, BR.stateManagerProgress)
val itemBinding = itemBindingOf<IconLink> { val extraBindings = bindExtra {
it.bindExtra(BR.viewModel, this) it.put(BR.viewModel, this)
} }
companion object { companion object {

View File

@ -10,8 +10,8 @@ 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.bindExtra
import com.topjohnwu.magisk.databinding.diffListOf import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ktx.timeFormatStandard import com.topjohnwu.magisk.ktx.timeFormatStandard
@ -34,8 +34,8 @@ class LogViewModel(
// --- su log // --- su log
val items = diffListOf<LogRvItem>() val items = diffListOf<LogRvItem>()
val itemBinding = itemBindingOf<LogRvItem> { val extraBindings = bindExtra {
it.bindExtra(BR.viewModel, this) it.put(BR.viewModel, this)
} }
// --- magisk log // --- magisk log

View File

@ -8,8 +8,6 @@ import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.adapterOf
import rikka.recyclerview.addEdgeSpacing import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addInvalidateItemDecorationsObserver import rikka.recyclerview.addInvalidateItemDecorationsObserver
import rikka.recyclerview.addItemSpacing import rikka.recyclerview.addItemSpacing
@ -34,7 +32,6 @@ class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.moduleList.apply { binding.moduleList.apply {
adapter = adapterOf<RvItem>()
addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1) addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1) addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect() fixEdgeEffect()

View File

@ -11,8 +11,8 @@ 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.RvItem import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.diffListOf import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.events.GetContentEvent 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
@ -30,8 +30,8 @@ class ModuleViewModel : BaseViewModel() {
private val itemsInstalled = diffListOf<LocalModuleRvItem>() private val itemsInstalled = diffListOf<LocalModuleRvItem>()
val items = MergeObservableList<RvItem>() val items = MergeObservableList<RvItem>()
val itemBinding = itemBindingOf<RvItem> { val extraBindings = bindExtra {
it.bindExtra(BR.viewModel, this) it.put(BR.viewModel, this)
} }
val data get() = uri val data get() = uri

View File

@ -14,8 +14,7 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.AppContext import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.databinding.adapterOf import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.events.AddHomeIconEvent import com.topjohnwu.magisk.events.AddHomeIconEvent
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.BiometricEvent import com.topjohnwu.magisk.events.dialog.BiometricEvent
@ -26,9 +25,10 @@ import kotlinx.coroutines.launch
class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler { class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
val adapter = adapterOf<BaseSettingsItem>()
val itemBinding = itemBindingOf<BaseSettingsItem> { it.bindExtra(BR.handler, this) }
val items = createItems() val items = createItems()
val extraBindings = bindExtra {
it.put(BR.handler, this)
}
init { init {
viewModelScope.launch { viewModelScope.launch {

View File

@ -5,9 +5,7 @@ import android.view.View
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.AnyDiffRvItem
import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
import com.topjohnwu.magisk.databinding.adapterOf
import rikka.recyclerview.addEdgeSpacing import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addItemSpacing import rikka.recyclerview.addItemSpacing
import rikka.recyclerview.fixEdgeEffect import rikka.recyclerview.fixEdgeEffect
@ -26,7 +24,6 @@ class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.superuserList.apply { binding.superuserList.apply {
adapter = adapterOf<AnyDiffRvItem>()
addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1) addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1) addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect() fixEdgeEffect()

View File

@ -15,8 +15,8 @@ import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.core.utils.currentLocale import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.databinding.AnyDiffRvItem import com.topjohnwu.magisk.databinding.AnyDiffRvItem
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.diffListOf import com.topjohnwu.magisk.databinding.diffListOf
import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.BiometricEvent import com.topjohnwu.magisk.events.dialog.BiometricEvent
import com.topjohnwu.magisk.events.dialog.SuperuserRevokeDialog import com.topjohnwu.magisk.events.dialog.SuperuserRevokeDialog
@ -35,14 +35,14 @@ class SuperuserViewModel(
private val itemNoData = TextItem(R.string.superuser_policy_none) private val itemNoData = TextItem(R.string.superuser_policy_none)
private val itemsPolicies = diffListOf<PolicyRvItem>()
private val itemsHelpers = ObservableArrayList<TextItem>() private val itemsHelpers = ObservableArrayList<TextItem>()
private val itemsPolicies = diffListOf<PolicyRvItem>()
val items = MergeObservableList<AnyDiffRvItem>() val items = MergeObservableList<AnyDiffRvItem>()
.insertList(itemsHelpers) .insertList(itemsHelpers)
.insertList(itemsPolicies) .insertList(itemsPolicies)
val itemBinding = itemBindingOf<AnyDiffRvItem> { val extraBindings = bindExtra {
it.bindExtra(BR.listener, this) it.put(BR.listener, this)
} }
// --- // ---

View File

@ -23,8 +23,6 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.* import com.topjohnwu.magisk.databinding.*
import com.topjohnwu.magisk.view.MagiskDialog.DialogClickListener import com.topjohnwu.magisk.view.MagiskDialog.DialogClickListener
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapters
import me.tatarka.bindingcollectionadapter2.ItemBinding
typealias DialogButtonClickListener = (DialogInterface) -> Unit typealias DialogButtonClickListener = (DialogInterface) -> Unit
@ -181,14 +179,13 @@ class MagiskDialog(
it.layoutManager = LinearLayoutManager(context) it.layoutManager = LinearLayoutManager(context)
val items = list.mapIndexed { i, cs -> DialogItem(cs, i) } val items = list.mapIndexed { i, cs -> DialogItem(cs, i) }
val binding = itemBindingOf<DialogItem> { item -> val extraBindings = bindExtra { sa ->
item.bindExtra(BR.listener, DialogClickListener { pos -> sa.put(BR.listener, DialogClickListener { pos ->
listener.onClick(pos) listener.onClick(pos)
dismiss() dismiss()
}) })
}.let { b -> ItemBinding.of(b) } }
it.setAdapter(items, extraBindings)
BindingRecyclerViewAdapters.setAdapter(it, binding, items, null, null, null, null)
} }
) )

View File

@ -17,9 +17,6 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/app_list" android:id="@+id/app_list"
invisibleUnless="@{viewModel.loaded}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
@ -27,6 +24,9 @@
android:paddingTop="@dimen/internal_action_bar_size" android:paddingTop="@dimen/internal_action_bar_size"
app:fitsSystemWindowsInsets="top|bottom" app:fitsSystemWindowsInsets="top|bottom"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:invisibleUnless="@{viewModel.loaded}"
app:items="@{viewModel.items}"
app:extraBindings="@{viewModel.extraBindings}"
tools:listitem="@layout/item_hide_md2" tools:listitem="@layout/item_hide_md2"
tools:paddingTop="40dp" /> tools:paddingTop="40dp" />

View File

@ -24,9 +24,7 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/flash_content" android:id="@+id/flash_content"
adapter="@{viewModel.adapter}" app:items="@{viewModel.items}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"
scrollToLast="@{true}" scrollToLast="@{true}"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"

View File

@ -20,8 +20,8 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/module_list" android:id="@+id/module_list"
gone="@{viewModel.loading}" gone="@{viewModel.loading}"
itemBinding="@{viewModel.itemBinding}" app:items="@{viewModel.items}"
items="@{viewModel.items}" app:extraBindings="@{viewModel.extraBindings}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"

View File

@ -14,9 +14,8 @@
</data> </data>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
adapter="@{viewModel.adapter}" app:items="@{viewModel.items}"
itemBinding="@{viewModel.itemBinding}" app:extraBindings="@{viewModel.extraBindings}"
items="@{viewModel.items}"
android:id="@+id/settings_list" android:id="@+id/settings_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View File

@ -20,8 +20,8 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/superuser_list" android:id="@+id/superuser_list"
goneUnless="@{viewModel.loaded || !viewModel.items.empty}" goneUnless="@{viewModel.loaded || !viewModel.items.empty}"
itemBinding="@{viewModel.itemBinding}" app:items="@{viewModel.items}"
items="@{viewModel.items}" app:extraBindings="@{viewModel.extraBindings}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"

View File

@ -17,8 +17,8 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/log_superuser" android:id="@+id/log_superuser"
itemBinding="@{viewModel.itemBinding}" app:items="@{viewModel.items}"
items="@{viewModel.items}" app:extraBindings="@{viewModel.extraBindings}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"

View File

@ -32,9 +32,9 @@
tools:text="\@topjohnwu" /> tools:text="\@topjohnwu" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
itemBinding="@{viewModel.itemBinding}" app:items="@{item.items}"
items="@{item.items}" app:extraBindings="@{viewModel.extraBindings}"
nestedScrollingEnabled="@{false}" app:nestedScrollingEnabled="@{false}"
android:overScrollMode="never" android:overScrollMode="never"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -95,8 +95,8 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
goneUnless="@{item.isExpanded}" goneUnless="@{item.isExpanded}"
itemBinding="@{viewModel.itemInternalBinding}" app:items="@{item.processes}"
items="@{item.processes}" app:extraBindings="@{viewModel.extraBindings}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?colorSurfaceVariant" android:background="?colorSurfaceVariant"