From 5471147422ff8a2c0e9fc63d867c1b8617b3abce Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 2 Jun 2022 23:40:10 -0700 Subject: [PATCH] Remove usage of BindingCollectionAdapter (part 2) --- app/build.gradle.kts | 4 - .../magisk/databinding/DataBindingAdapters.kt | 10 +- .../magisk/databinding/MergeObservableList.kt | 162 ++++++++++++++++++ .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 2 +- .../magisk/ui/module/ModuleViewModel.kt | 2 +- .../magisk/ui/superuser/SuperuserViewModel.kt | 2 +- .../magisk/ui/surequest/SuRequestViewModel.kt | 3 - app/src/main/res/layout/activity_request.xml | 6 +- app/src/main/res/layout/item_spinner.xml | 37 ++-- 9 files changed, 186 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/databinding/MergeObservableList.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4375057e1..e187855d1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -78,10 +78,6 @@ dependencies { implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.1") implementation("io.noties.markwon:core:4.6.2") - val vBAdapt = "4.0.0" - val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter" - implementation("${bindingAdapter}:${vBAdapt}") - val vLibsu = "5.0.2" implementation("com.github.topjohnwu.libsu:core:${vLibsu}") implementation("com.github.topjohnwu.libsu:service:${vLibsu}") diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt index 13ef8c020..a162a2b76 100644 --- a/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt @@ -8,10 +8,7 @@ import android.text.Spanned import android.util.TypedValue import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.TextView +import android.widget.* import androidx.annotation.DrawableRes import androidx.appcompat.widget.Toolbar import androidx.cardview.widget.CardView @@ -295,3 +292,8 @@ fun TextView.setTextColorAttr(attr: Int) { fun TextView.setText(text: TextHolder) { this.text = text.getText(context.resources) } + +@BindingAdapter("items", "layout") +fun Spinner.setAdapter(items: Array, layoutRes: Int) { + adapter = ArrayAdapter(context, layoutRes, items) +} diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/MergeObservableList.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/MergeObservableList.kt new file mode 100644 index 000000000..582a06235 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/MergeObservableList.kt @@ -0,0 +1,162 @@ +package com.topjohnwu.magisk.databinding + +import androidx.databinding.ListChangeRegistry +import androidx.databinding.ObservableList +import androidx.databinding.ObservableList.OnListChangedCallback +import java.util.* + +@Suppress("UNCHECKED_CAST") +class MergeObservableList : AbstractList(), ObservableList { + + private val lists: MutableList> = mutableListOf() + private val listeners = ListChangeRegistry() + private val callback = Callback() + + override fun addOnListChangedCallback(callback: OnListChangedCallback>) { + listeners.add(callback) + } + + override fun removeOnListChangedCallback(callback: OnListChangedCallback>) { + listeners.remove(callback) + } + + override fun get(index: Int): T { + if (index < 0) + throw IndexOutOfBoundsException() + var idx = index + for (list in lists) { + val size = list.size + if (idx < size) { + return list[idx] + } + idx -= size + } + throw IndexOutOfBoundsException() + } + + override val size: Int + get() = lists.fold(0) { i, it -> i + it.size } + + + fun insertItem(obj: T): MergeObservableList { + val idx = size + lists.add(listOf(obj)) + ++modCount + listeners.notifyInserted(this, idx, 1) + return this + } + + fun insertList(list: ObservableList): MergeObservableList { + val idx = size + lists.add(list) + ++modCount + (list as ObservableList).addOnListChangedCallback(callback) + if (list.isNotEmpty()) + listeners.notifyInserted(this, idx, list.size) + return this + } + + fun removeItem(obj: T): Boolean { + var idx = 0 + for ((i, list) in lists.withIndex()) { + if (list !is ObservableList<*>) { + if (obj == list[0]) { + lists.removeAt(i) + ++modCount + listeners.notifyRemoved(this, idx, 1) + return true + } + } + idx += list.size + } + return false + } + + fun removeList(listToRemove: ObservableList): Boolean { + var idx = 0 + for ((i, list) in lists.withIndex()) { + if (listToRemove === list) { + (list as ObservableList).removeOnListChangedCallback(callback) + lists.removeAt(i) + ++modCount + listeners.notifyRemoved(this, idx, list.size) + return true + } + idx += list.size + } + return false + } + + override fun clear() { + val sz = size + for (list in lists) { + if (list is ObservableList<*>) { + (list as ObservableList).removeOnListChangedCallback(callback) + } + } + ++modCount + lists.clear() + if (sz > 0) + listeners.notifyRemoved(this, 0, sz) + } + + private fun subIndexToIndex(subList: List<*>, index: Int): Int { + if (index < 0) + throw IndexOutOfBoundsException() + var idx = 0 + for (list in lists) { + if (subList === list) { + return idx + index + } + idx += list.size + } + throw IllegalArgumentException() + } + + inner class Callback : OnListChangedCallback>() { + override fun onChanged(sender: ObservableList) { + ++modCount + listeners.notifyChanged(this@MergeObservableList) + } + + override fun onItemRangeChanged( + sender: ObservableList, + positionStart: Int, + itemCount: Int + ) { + listeners.notifyChanged(this@MergeObservableList, + subIndexToIndex(sender, positionStart), itemCount) + } + + override fun onItemRangeInserted( + sender: ObservableList, + positionStart: Int, + itemCount: Int + ) { + ++modCount + listeners.notifyInserted(this@MergeObservableList, + subIndexToIndex(sender, positionStart), itemCount) + } + + override fun onItemRangeMoved( + sender: ObservableList, + fromPosition: Int, + toPosition: Int, + itemCount: Int + ) { + val idx = subIndexToIndex(sender, 0) + listeners.notifyMoved(this@MergeObservableList, + idx + fromPosition, idx + toPosition, itemCount) + } + + override fun onItemRangeRemoved( + sender: ObservableList, + positionStart: Int, + itemCount: Int + ) { + ++modCount + listeners.notifyRemoved(this@MergeObservableList, + subIndexToIndex(sender, positionStart), itemCount) + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index 110e290af..5d882a539 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.core.net.toUri import androidx.databinding.Bindable import androidx.lifecycle.viewModelScope +import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.R import com.topjohnwu.magisk.arch.* @@ -23,7 +24,6 @@ import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.asText import com.topjohnwu.superuser.Shell import kotlinx.coroutines.launch -import me.tatarka.bindingcollectionadapter2.BR import kotlin.math.roundToInt enum class MagiskState { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt index 836dff11a..99cf6b22e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt @@ -10,6 +10,7 @@ import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.base.ContentResultCallback import com.topjohnwu.magisk.core.model.module.LocalModule import com.topjohnwu.magisk.core.model.module.OnlineModule +import com.topjohnwu.magisk.databinding.MergeObservableList import com.topjohnwu.magisk.databinding.RvItem import com.topjohnwu.magisk.databinding.bindExtra import com.topjohnwu.magisk.databinding.diffListOf @@ -21,7 +22,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize -import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList class ModuleViewModel : BaseViewModel() { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt index 30687b68c..87c3bbd4e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt @@ -15,6 +15,7 @@ import com.topjohnwu.magisk.core.model.su.SuPolicy import com.topjohnwu.magisk.core.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.currentLocale import com.topjohnwu.magisk.databinding.AnyDiffRvItem +import com.topjohnwu.magisk.databinding.MergeObservableList import com.topjohnwu.magisk.databinding.bindExtra import com.topjohnwu.magisk.databinding.diffListOf import com.topjohnwu.magisk.events.SnackbarEvent @@ -27,7 +28,6 @@ import com.topjohnwu.magisk.view.TextItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList class SuperuserViewModel( private val db: PolicyDao diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt index 307ab2b0b..117c7ea54 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt @@ -34,7 +34,6 @@ import com.topjohnwu.magisk.ktx.getLabel import com.topjohnwu.magisk.utils.TextHolder import com.topjohnwu.magisk.utils.Utils import kotlinx.coroutines.launch -import me.tatarka.bindingcollectionadapter2.ItemBinding import java.util.concurrent.TimeUnit.SECONDS class SuRequestViewModel( @@ -70,8 +69,6 @@ class SuRequestViewModel( false } - val itemBinding = ItemBinding.of(BR.item, R.layout.item_spinner) - private val handler = SuRequestHandler(AppContext.packageManager, policyDB) private lateinit var timer: CountDownTimer private var initialized = false diff --git a/app/src/main/res/layout/activity_request.xml b/app/src/main/res/layout/activity_request.xml index 709516897..18adebdbb 100644 --- a/app/src/main/res/layout/activity_request.xml +++ b/app/src/main/res/layout/activity_request.xml @@ -5,8 +5,6 @@ - - @@ -101,8 +99,8 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:enabled="@{viewModel.grantEnabled}" - app:items="@{Arrays.asList(@stringArray/allow_timeout)}" - app:itemBinding="@{viewModel.itemBinding}" + app:items="@{@stringArray/allow_timeout}" + app:layout="@{@layout/item_spinner}" android:selection="@={viewModel.selectedItemPosition}" /> - - - - - - - - - - - +