diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/FilterableDiffObservableList.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/FilterableDiffObservableList.kt index 8f3e85e10..00a4b13ea 100644 --- a/app/src/main/java/com/topjohnwu/magisk/databinding/FilterableDiffObservableList.kt +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/FilterableDiffObservableList.kt @@ -1,55 +1,38 @@ package com.topjohnwu.magisk.databinding -import android.os.Handler -import android.os.HandlerThread -import android.os.Looper -import java.util.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.util.Collections class FilterableDiffObservableList( - callback: Callback + callback: Callback, + private val scope: CoroutineScope ) : DiffObservableList(callback) { - var filter: ((T) -> Boolean)? = null - set(value) { - field = value - queueUpdate() - } - @Volatile - private var sublist: MutableList = super.list + private var sublist: MutableList = list + private var job: Job? = null // --- - private val ui by lazy { Handler(Looper.getMainLooper()) } - private val handler = Handler(HandlerThread("List${hashCode()}").apply { start() }.looper) - private val updater = Runnable { - val filter = filter ?: { true } - val newList = super.list.filter(filter) - val diff = synchronized(this) { doCalculateDiff(sublist, newList) } - ui.post { - sublist = Collections.synchronizedList(newList) - diff.dispatchUpdatesTo(listCallback) + fun filter(filter: (T) -> Boolean) { + job?.cancel() + job = scope.launch(Dispatchers.Default) { + val newList = list.filter(filter) + val diff = synchronized(this) { doCalculateDiff(sublist, newList) } + withContext(Dispatchers.Main) { + sublist = Collections.synchronizedList(newList) + diff.dispatchUpdatesTo(listCallback) + } } } - private fun queueUpdate() { - handler.removeCallbacks(updater) - handler.post(updater) - } - - fun hasFilter() = filter != null - - fun filter(switch: (T) -> Boolean) { - filter = switch - } - - fun reset() { - filter = null - } - // --- override fun get(index: Int): T { - return sublist.get(index) + return sublist[index] } override fun add(element: T): Boolean { diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/Helpers.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/Helpers.kt index ca591196e..113675a4c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/databinding/Helpers.kt +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/Helpers.kt @@ -1,7 +1,9 @@ package com.topjohnwu.magisk.databinding +import kotlinx.coroutines.CoroutineScope + fun diffListOf() = DiffObservableList(DiffRvItem.callback()) -fun filterableListOf() = - FilterableDiffObservableList(DiffRvItem.callback()) +fun filterableListOf(scope: CoroutineScope) = + FilterableDiffObservableList(DiffRvItem.callback(), scope) diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/RvItemAdapter.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/RvItemAdapter.kt index 981b15299..8ca0b2d12 100644 --- a/app/src/main/java/com/topjohnwu/magisk/databinding/RvItemAdapter.kt +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/RvItemAdapter.kt @@ -15,8 +15,8 @@ import androidx.recyclerview.widget.RecyclerView import com.topjohnwu.magisk.BR class RvItemAdapter( - internal val items: List, - private val extraBindings: SparseArray<*>? + val items: List, + val extraBindings: SparseArray<*>? ) : RecyclerView.Adapter() { private var lifecycleOwner: LifecycleOwner? = null @@ -113,7 +113,8 @@ inline fun bindExtra(body: (SparseArray) -> Unit) = SparseArray().al @BindingAdapter("items", "extraBindings", requireAll = false) fun RecyclerView.setAdapter(items: List?, extraBindings: SparseArray<*>?) { if (items != null) { - if ((adapter as? RvItemAdapter)?.items !== items) { + val rva = (adapter as? RvItemAdapter<*>) + if (rva == null || rva.items !== items || rva.extraBindings !== extraBindings) { adapter = RvItemAdapter(items, extraBindings) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt index 2c43273e2..13a3ed82f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt @@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.deny import android.annotation.SuppressLint import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES import androidx.databinding.Bindable +import androidx.lifecycle.viewModelScope import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.arch.AsyncLoadViewModel import com.topjohnwu.magisk.core.di.AppContext @@ -37,7 +38,7 @@ class DenyListViewModel : AsyncLoadViewModel() { query() } - val items = filterableListOf() + val items = filterableListOf(viewModelScope) val extraBindings = bindExtra { it.put(BR.viewModel, this) } @@ -68,7 +69,7 @@ class DenyListViewModel : AsyncLoadViewModel() { query() } - fun query() { + private fun query() { items.filter { fun filterSystem() = isShowSystem || !it.info.isSystemApp()