summaryrefslogtreecommitdiffhomepage
path: root/app
diff options
context:
space:
mode:
authorSamuel Holland <samuel@sholland.org>2017-08-07 19:46:19 -0500
committerSamuel Holland <samuel@sholland.org>2017-08-07 19:46:19 -0500
commit7d3e79684204e8df60eaf8d3985c22317f6594ef (patch)
tree642a162ba30bd2b4a0a0be556addfc68f2e767b9 /app
parent2df899eae52591ff46819c960e129a2c698b201e (diff)
ObservableArrayMapAdapter: Copy ObservableListAdapter
Since the conversion to a sequential list (to implement ListAdapter) depends on the implementation detail that ObservableArrayMap is backed by an array, we can't use the ObservableMap interface here. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/com/wireguard/android/BindingAdapters.java27
-rw-r--r--app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java84
2 files changed, 111 insertions, 0 deletions
diff --git a/app/src/main/java/com/wireguard/android/BindingAdapters.java b/app/src/main/java/com/wireguard/android/BindingAdapters.java
index aa5b8c1e..77c6f657 100644
--- a/app/src/main/java/com/wireguard/android/BindingAdapters.java
+++ b/app/src/main/java/com/wireguard/android/BindingAdapters.java
@@ -1,6 +1,7 @@
package com.wireguard.android;
import android.databinding.BindingAdapter;
+import android.databinding.ObservableArrayMap;
import android.databinding.ObservableList;
import android.widget.ListView;
@@ -10,6 +11,32 @@ import android.widget.ListView;
public final class BindingAdapters {
@BindingAdapter({"items", "layout"})
+ public static <K, V> void arrayMapBinding(ListView view, ObservableArrayMap<K, V> oldMap,
+ int oldLayoutId, ObservableArrayMap<K, V> newMap,
+ int newLayoutId) {
+ // Remove any existing binding when there is no new map.
+ if (newMap == null) {
+ view.setAdapter(null);
+ return;
+ }
+ // The ListAdapter interface is not generic, so this cannot be checked.
+ @SuppressWarnings("unchecked")
+ ObservableArrayMapAdapter<K, V> adapter =
+ (ObservableArrayMapAdapter<K, V>) view.getAdapter();
+ // If the layout changes, any existing adapter must be replaced.
+ if (newLayoutId != oldLayoutId)
+ adapter = null;
+ // Add a new binding if there was none, or if it must be replaced due to a layout change.
+ if (adapter == null) {
+ adapter = new ObservableArrayMapAdapter<>(view.getContext(), newLayoutId, newMap);
+ view.setAdapter(adapter);
+ } else if (newMap != oldMap) {
+ // Changing the list only requires modifying the existing adapter.
+ adapter.setMap(newMap);
+ }
+ }
+
+ @BindingAdapter({"items", "layout"})
public static <T> void listBinding(ListView view, ObservableList<T> oldList, int oldLayoutId,
ObservableList<T> newList, int newLayoutId) {
// Remove any existing binding when there is no new list.
diff --git a/app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java b/app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java
new file mode 100644
index 00000000..d2a5a4cc
--- /dev/null
+++ b/app/src/main/java/com/wireguard/android/ObservableArrayMapAdapter.java
@@ -0,0 +1,84 @@
+package com.wireguard.android;
+
+import android.content.Context;
+import android.databinding.DataBindingUtil;
+import android.databinding.ObservableArrayMap;
+import android.databinding.ObservableMap;
+import android.databinding.ViewDataBinding;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListAdapter;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A generic ListAdapter backed by an ObservableMap.
+ */
+
+class ObservableArrayMapAdapter<K, V> extends BaseAdapter implements ListAdapter {
+ private final int layoutId;
+ private final LayoutInflater layoutInflater;
+ private ObservableArrayMap<K, V> map;
+ private final OnMapChangedCallback<K, V> callback = new OnMapChangedCallback<>(this);
+
+ ObservableArrayMapAdapter(Context context, int layoutId, ObservableArrayMap<K, V> map) {
+ this.layoutInflater = LayoutInflater.from(context);
+ this.layoutId = layoutId;
+ setMap(map);
+ }
+
+ @Override
+ public int getCount() {
+ return map != null ? map.size() : 0;
+ }
+
+ @Override
+ public V getItem(int position) {
+ return map != null ? map.get(map.keyAt(position)) : null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewDataBinding binding = DataBindingUtil.getBinding(convertView);
+ if (binding == null)
+ binding = DataBindingUtil.inflate(layoutInflater, layoutId, parent, false);
+ binding.setVariable(BR.item, getItem(position));
+ binding.executePendingBindings();
+ return binding.getRoot();
+ }
+
+ public void setMap(ObservableArrayMap<K, V> newMap) {
+ if (map != null)
+ map.removeOnMapChangedCallback(callback);
+ map = newMap;
+ if (map != null) {
+ map.addOnMapChangedCallback(callback);
+ }
+ }
+
+ private static class OnMapChangedCallback<K, V>
+ extends ObservableMap.OnMapChangedCallback<ObservableMap<K, V>, K, V> {
+
+ private final WeakReference<ObservableArrayMapAdapter<K, V>> weakAdapter;
+
+ private OnMapChangedCallback(ObservableArrayMapAdapter<K, V> adapter) {
+ weakAdapter = new WeakReference<>(adapter);
+ }
+
+ @Override
+ public void onMapChanged(ObservableMap<K, V> sender, K key) {
+ final ObservableArrayMapAdapter<K, V> adapter = weakAdapter.get();
+ if (adapter != null)
+ adapter.notifyDataSetChanged();
+ else
+ sender.removeOnMapChangedCallback(this);
+ }
+ }
+}