Baku - Usability improvements
RecyclerView is now a compile dependency rather than provided. Since the
unit of classloading is a class, RecyclerView is required whenever a
collection binding builder is used, even if used to bind to a
ListView. It's thus still not always required, but this requirement
would be surprising to a developer, and it's better to let ProGuard
strip it out later if possible.
Fixed a case where the type requirement on a prefix binding builder
would throw NPE instead of IllegalStateException.
Prefix binding builder and associated adapters now take Comparator
rather than Ordering (which implements Comparator).
Change-Id: I53c6991e265951b1f1634d228fcb8b4e5330992e
diff --git a/baku-toolkit/build.gradle b/baku-toolkit/build.gradle
index 6f8507c..62608d7 100644
--- a/baku-toolkit/build.gradle
+++ b/baku-toolkit/build.gradle
@@ -6,11 +6,13 @@
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.5.0'
- classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
- classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+'
- classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
- classpath 'me.tatarka:gradle-retrolambda:3.2.4'
+ classpath (
+ 'com.android.tools.build:gradle:1.5.0',
+ 'com.github.dcendents:android-maven-gradle-plugin:1.3',
+ 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0',
+ 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6',
+ 'me.tatarka:gradle-retrolambda:3.2.4'
+ )
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/baku-toolkit/clean-cloudsync b/baku-toolkit/clean-cloudsync
index 87dd8d3..deadc90 100755
--- a/baku-toolkit/clean-cloudsync
+++ b/baku-toolkit/clean-cloudsync
@@ -5,7 +5,7 @@
if [ ${host-} ]; then
- ssh="/usr/bin/ssh -i /home/$USER/.ssh/google_compute_engine $host"
+ ssh="/usr/bin/ssh -i $HOME/.ssh/google_compute_engine $host"
fullinstallation=`$ssh ls /tmp/dmrun/dm/dmroot/app'*'`
installation=${fullinstallation:13}
diff --git a/baku-toolkit/lib/build.gradle b/baku-toolkit/lib/build.gradle
index 7829abf..fafc703 100644
--- a/baku-toolkit/lib/build.gradle
+++ b/baku-toolkit/lib/build.gradle
@@ -39,7 +39,6 @@
dependencies {
provided(
- 'com.android.support:recyclerview-v7:23.0.1',
/*
https://projectlombok.org/setup/android.html
Follow Android Studio instructions at the bottom of the page to install the Lombok
@@ -64,6 +63,12 @@
}
compile(
+ /*
+ Ideally this would be optional, but this unexpectedly becomes required if you touch
+ the Baku CollectionBinding Builder, even if you don't actually try to bind to a
+ RecyclerView.
+ */
+ 'com.android.support:recyclerview-v7:23.0.1',
'com.jakewharton.rxbinding:rxbinding:0.3.0',
'commons-io:commons-io:2.4',
'io.reactivex:rxandroid:1.1.0',
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/CollectionAdapterBuilder.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/CollectionAdapterBuilder.java
index d11f93a..0c4d7b2 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/CollectionAdapterBuilder.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/CollectionAdapterBuilder.java
@@ -4,6 +4,7 @@
package io.v.baku.toolkit.bind;
+import android.support.annotation.IdRes;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ListView;
@@ -88,4 +89,12 @@
throw new IllegalArgumentException("No default binding for view " + view);
}
}
+
+ /**
+ * Binds to the view identified by {@code viewId}.
+ * @see #bindTo(View)
+ */
+ public RangeAdapter bindTo(final @IdRes int viewId) {
+ return bindTo(mBase.mActivity.findViewById(viewId));
+ }
}
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixBindingBuilder.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixBindingBuilder.java
index b1085f3..600c3f5 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixBindingBuilder.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixBindingBuilder.java
@@ -6,6 +6,8 @@
import com.google.common.collect.Ordering;
+import java.util.Comparator;
+
import io.v.rx.syncbase.RangeWatchBatch;
import io.v.rx.syncbase.RxTable;
import io.v.v23.syncbase.nosql.PrefixRange;
@@ -21,7 +23,7 @@
extends CollectionAdapterBuilder<PrefixBindingBuilder<T, A>, RxTable.Row<T>, A> {
private Class<T> mType;
private PrefixRange mPrefix;
- private Ordering<? super RxTable.Row<T>> mOrdering;
+ private Comparator<? super RxTable.Row<T>> mOrdering;
private Func1<String, Boolean> mKeyFilter;
public PrefixBindingBuilder(final CollectionBinding.Builder base) {
@@ -38,9 +40,11 @@
}
/**
+ * The element type for the collection, i.e. the value type for rows matching the prefix and key
+ * filter.
+ * <p>
* This setter is minimally typesafe; after setting the {@code type}, clients should
- * probably also update {@code ordering} and {@code viewAdapter}. If intending to use a
- * collection binding that requires a
+ * probably also update {@code ordering} and {@code viewAdapter}.
*/
public <U> PrefixBindingBuilder<U, A> type(final Class<U> type) {
@SuppressWarnings("unchecked")
@@ -68,12 +72,19 @@
return new TextViewAdapter(mBase.getDefaultViewAdapterContext()).map(RxTable.Row::getValue);
}
+ private Class<T> getType() {
+ if (mType == null) {
+ throw new IllegalStateException("Missing required type property");
+ }
+ return mType;
+ }
+
/**
* For comparable {@code T}, default to natural ordering on values. Otherwise, default to
* natural ordering on row names.
*/
private Ordering<? super RxTable.Row<? extends T>> getDefaultOrdering() {
- if (mOrdering == null && Comparable.class.isAssignableFrom(mType)) {
+ if (mOrdering == null && Comparable.class.isAssignableFrom(getType())) {
return Ordering.natural().onResultOf(r -> (Comparable) r.getValue());
} else {
return Ordering.natural().onResultOf(RxTable.Row::getRowName);
@@ -86,14 +97,11 @@
}
public Observable<RangeWatchBatch<T>> buildPrefixWatch() {
- if (mType == null) {
- throw new IllegalStateException("Missing required type property");
- }
return mBase.mRxTable.watch(mPrefix == null? RowRange.prefix("") : mPrefix,
- mKeyFilter, mType);
+ mKeyFilter, getType());
}
- private Ordering<? super RxTable.Row<T>> getOrdering() {
+ private Comparator<? super RxTable.Row<T>> getOrdering() {
return mOrdering == null ? getDefaultOrdering() : mOrdering;
}
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListAccumulator.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListAccumulator.java
index 9bd3c57..117fc87 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListAccumulator.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListAccumulator.java
@@ -10,6 +10,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
@@ -35,13 +36,17 @@
private final Map<String, T> mRows = new HashMap<>();
private final List<RxTable.Row<T>> mSorted = new ArrayList<>();
- private final Ordering<? super RxTable.Row<T>> mOrdering;
+ private final Comparator<? super RxTable.Row<T>> mOrdering;
- public PrefixListAccumulator(final Ordering<? super RxTable.Row<T>> ordering) {
+ public PrefixListAccumulator(final Comparator<? super RxTable.Row<T>> ordering) {
// ensure deterministic ordering by always applying secondary order on row name
- mOrdering = ordering.compound(Ordering.natural().onResultOf(RxTable.Row::getRowName));
+ mOrdering = Ordering.from(ordering).compound(
+ Ordering.natural().onResultOf(RxTable.Row::getRowName));
}
+ /**
+ * The generic wildcard is for the benefit of subclass overrides.
+ */
public Observable<? extends PrefixListAccumulator<T>> scanFrom(
final Observable<RangeWatchBatch<T>> watch) {
return watch
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListDeltaAccumulator.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListDeltaAccumulator.java
index d804799..7d5a232 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListDeltaAccumulator.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/PrefixListDeltaAccumulator.java
@@ -6,7 +6,7 @@
import android.support.v7.widget.RecyclerView;
-import com.google.common.collect.Ordering;
+import java.util.Comparator;
import io.v.rx.syncbase.RangeWatchBatch;
import io.v.rx.syncbase.RxTable;
@@ -24,7 +24,7 @@
private Consumer<RecyclerView.Adapter> mDeltas;
private final NumericIdMapper mIds = new NumericIdMapper();
- public PrefixListDeltaAccumulator(final Ordering<? super RxTable.Row<T>> ordering) {
+ public PrefixListDeltaAccumulator(final Comparator<? super RxTable.Row<T>> ordering) {
super(ordering);
}
diff --git a/baku-toolkit/lib/src/test/java/io/v/baku/toolkit/bind/PrefixBindingBuilderTest.java b/baku-toolkit/lib/src/test/java/io/v/baku/toolkit/bind/PrefixBindingBuilderTest.java
new file mode 100644
index 0000000..15757d2
--- /dev/null
+++ b/baku-toolkit/lib/src/test/java/io/v/baku/toolkit/bind/PrefixBindingBuilderTest.java
@@ -0,0 +1,18 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io.v.baku.toolkit.bind;
+
+import android.widget.ListView;
+
+import org.junit.Test;
+
+public class PrefixBindingBuilderTest {
+ @Test(expected = IllegalStateException.class)
+ public void testMissingType() {
+ CollectionBinding.builder()
+ .onPrefix("foo")
+ .bindTo((ListView)null);
+ }
+}