aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-03-26 23:54:44 -0600
committerJason A. Donenfeld <Jason@zx2c4.com>2020-03-27 03:08:47 -0600
commit48a9fd46a679db5cc4baa0ffd03b14d006bab04a (patch)
treeb0e1647a9bba066d6c6870a397d513912782fcad /ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt
parentutil: begin conversion to kotlin (diff)
downloadwireguard-android-48a9fd46a679db5cc4baa0ffd03b14d006bab04a.tar.xz
wireguard-android-48a9fd46a679db5cc4baa0ffd03b14d006bab04a.zip
databinding: rewrite in kotlin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt')
-rw-r--r--ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt112
1 files changed, 112 insertions, 0 deletions
diff --git a/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt b/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt
new file mode 100644
index 00000000..131f3877
--- /dev/null
+++ b/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.wireguard.android.databinding
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ObservableList
+import androidx.databinding.ViewDataBinding
+import com.wireguard.android.BR
+import java.lang.ref.WeakReference
+
+/**
+ * Helper class for binding an ObservableList to the children of a ViewGroup.
+ */
+internal class ItemChangeListener<T>(private val container: ViewGroup, private val layoutId: Int) {
+ private val callback = OnListChangedCallback(this)
+ private val layoutInflater: LayoutInflater = LayoutInflater.from(container.context)
+ private var list: ObservableList<T>? = null
+
+ private fun getView(position: Int, convertView: View?): View {
+ var binding = if (convertView != null) DataBindingUtil.getBinding<ViewDataBinding>(convertView) else null
+ if (binding == null) {
+ binding = DataBindingUtil.inflate(layoutInflater, layoutId, container, false)
+ }
+ require(list != null) { "Trying to get a view while list is still null" }
+ binding!!.setVariable(BR.collection, list)
+ binding.setVariable(BR.item, list!![position])
+ binding.executePendingBindings()
+ return binding.root
+ }
+
+ fun setList(newList: ObservableList<T>?) {
+ list?.removeOnListChangedCallback(callback)
+ list = newList
+ if (list != null) {
+ list!!.addOnListChangedCallback(callback)
+ callback.onChanged(list!!)
+ } else {
+ container.removeAllViews()
+ }
+ }
+
+ private class OnListChangedCallback<T> constructor(listener: ItemChangeListener<T>) : ObservableList.OnListChangedCallback<ObservableList<T>>() {
+ private val weakListener: WeakReference<ItemChangeListener<T>> = WeakReference(listener)
+
+ override fun onChanged(sender: ObservableList<T>) {
+ val listener = weakListener.get()
+ if (listener != null) {
+ // TODO: recycle views
+ listener.container.removeAllViews()
+ for (i in sender.indices)
+ listener.container.addView(listener.getView(i, null))
+ } else {
+ sender.removeOnListChangedCallback(this)
+ }
+ }
+
+ override fun onItemRangeChanged(sender: ObservableList<T>, positionStart: Int,
+ itemCount: Int) {
+ val listener = weakListener.get()
+ if (listener != null) {
+ for (i in positionStart until positionStart + itemCount) {
+ val child = listener.container.getChildAt(i)
+ listener.container.removeViewAt(i)
+ listener.container.addView(listener.getView(i, child))
+ }
+ } else {
+ sender.removeOnListChangedCallback(this)
+ }
+ }
+
+ override fun onItemRangeInserted(sender: ObservableList<T>, positionStart: Int,
+ itemCount: Int) {
+ val listener = weakListener.get()
+ if (listener != null) {
+ for (i in positionStart until positionStart + itemCount)
+ listener.container.addView(listener.getView(i, null))
+ } else {
+ sender.removeOnListChangedCallback(this)
+ }
+ }
+
+ override fun onItemRangeMoved(sender: ObservableList<T>, fromPosition: Int,
+ toPosition: Int, itemCount: Int) {
+ val listener = weakListener.get()
+ if (listener != null) {
+ val views = arrayOfNulls<View>(itemCount)
+ for (i in 0 until itemCount) views[i] = listener.container.getChildAt(fromPosition + i)
+ listener.container.removeViews(fromPosition, itemCount)
+ for (i in 0 until itemCount) listener.container.addView(views[i], toPosition + i)
+ } else {
+ sender.removeOnListChangedCallback(this)
+ }
+ }
+
+ override fun onItemRangeRemoved(sender: ObservableList<T>, positionStart: Int,
+ itemCount: Int) {
+ val listener = weakListener.get()
+ if (listener != null) {
+ listener.container.removeViews(positionStart, itemCount)
+ } else {
+ sender.removeOnListChangedCallback(this)
+ }
+ }
+
+ }
+
+}