Response to API usability study 2016.02.23
Documenting the 'key' setter in SyncbaseBinding.Builder, making two-way
bindings the default even for TextView, adding a few convenience
overloads, and starting to improve docs.
Change-Id: I114ef085f5a16d194c4ed1c6dae5c61ab0fb080a
diff --git a/baku-toolkit/lib/build.gradle b/baku-toolkit/lib/build.gradle
index ef83ece..24f751f 100644
--- a/baku-toolkit/lib/build.gradle
+++ b/baku-toolkit/lib/build.gradle
@@ -11,7 +11,7 @@
import org.gradle.language.base.internal.compile.Compiler
// You should change this after releasing a new version of the Baku Toolkit. See the
// list of published versions at https://repo1.maven.org/maven2/io/v/baku-toolkit.
-version = '0.7.1'
+version = '0.8.0'
group = 'io.v'
def siteUrl = 'https://github.com/vanadium/java'
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/DebouncingCoordinator.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/DebouncingCoordinator.java
index f612b9b..6e67a41 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/DebouncingCoordinator.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/DebouncingCoordinator.java
@@ -22,16 +22,16 @@
* {@value #DEFAULT_IO_DEBOUNCE_MILLIS} ms) after the latest write, then taking the latest read.
* Write/watch latency can cause reflexive watch changes from Syncbase to arrive after subsequent
* changes to the UI state have already been made, causing a stuttering revert.
- * <p>
+ *
* A simple debounce on the uplink or downlink doesn't solve the problem because it effectively just
* adds a delay to the boundary condition. To prevent this, any update from the model must be
* throttled if there was a recent update from the view.
- * <p>
+ *
* Unfortunately for rapid concurrent updates this can result in divergence which should be handled
* via conflict resolution or CRDT.
- * <p>
+ *
* This coordinator is included in the default coordinator chain for
- * {@linkplain io.v.baku.toolkit.bind.SyncbaseBinding.Builder#bindTwoWay(TextView) two-way
+ * {@linkplain io.v.baku.toolkit.bind.SyncbaseBinding.Builder#bindTo(TextView) two-way
* <code>TextView</code> bindings}.
*/
@RequiredArgsConstructor
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SuppressWriteOnReadCoordinator.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SuppressWriteOnReadCoordinator.java
index 8741ee4..d93d352 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SuppressWriteOnReadCoordinator.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SuppressWriteOnReadCoordinator.java
@@ -16,11 +16,11 @@
* Android {@link android.widget.EditText} fires text update events whether changes originate from
* the user or from code. If we don't suppress writes while responding to Syncbase changes with
* Android widgets, we easily end up in update loops.
- * <p>
+ *
* To operate correctly, this coordinator must occur single-threaded with the widget binding layer.
- * <p>
+ *
* This coordinator is required (and injected if missing) in the coordinator chain for
- * {@linkplain io.v.baku.toolkit.bind.SyncbaseBinding.Builder#bindTwoWay(TextView) two-way
+ * {@linkplain io.v.baku.toolkit.bind.SyncbaseBinding.Builder#bindTo(TextView) two-way
* <code>TextView</code> bindings}.
*/
@RequiredArgsConstructor
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SyncbaseBinding.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SyncbaseBinding.java
index 80c2a46..526ec6c 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SyncbaseBinding.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/bind/SyncbaseBinding.java
@@ -40,6 +40,9 @@
private T mDeleteValue, mDefaultValue;
private final List<CoordinatorChain<T>> mCoordinators = new ArrayList<>();
+ /**
+ * Sets the row name for the Syncbase side of the binding.
+ */
public Builder<T> key(final String key) {
mKey = key;
return this;
@@ -112,14 +115,14 @@
}
/**
- * Constructs a read-only binding from a `String` in Syncbase to the text of a
- * {@link TextView}. This is a simple unidirectional binding that does not involve any
- * coordinators.
+ * Constructs a binding from a `String` in Syncbase to the text of a {@link TextView}, only
+ * propagating changes from Syncbase to the `TextView` and not in the other direction. This
+ * is a simple unidirectional binding that does not involve any coordinators.
*
* If {@link #subscriptionParent(CompositeSubscription) subscriptionParent} is set, this
* method adds the generated binding to it.
*/
- public Builder<T> bindOneWay(final TextView textView) {
+ public Builder<T> bindReadOnly(final TextView textView) {
@SuppressWarnings("unchecked")
final Builder<String> t = (Builder<String>) this;
@@ -134,6 +137,27 @@
}
/**
+ * Binds to the provided view in a read-only direction. This method delegates to
+ * {@link #bindReadOnly(TextView)} for {@link TextView}s. Other view types are not yet
+ * supported.
+ */
+ public Builder<T> bindReadOnly(final View view) {
+ if (view instanceof TextView) {
+ return bindReadOnly((TextView) view);
+ } else {
+ throw new IllegalArgumentException("No read-only binding for view " + view);
+ }
+ }
+
+ /**
+ * Binds to the view identified by {@code viewId} in a read-only direction.
+ * @see #bindTo(View)
+ */
+ public Builder<T> bindReadOnly(final @IdRes int viewId) {
+ return bindReadOnly(mActivity.findViewById(viewId));
+ }
+
+ /**
* Constructs a two-way, bidirectional binding between a `String` in Syncbase and the text
* of a {@link TextView}.
*
@@ -152,7 +176,7 @@
* method adds the generated binding to it.
* @todo(rosswang): produce a SyncbaseBinding, and allow mutable bindings.
*/
- public Builder<T> bindTwoWay(final TextView textView) {
+ public Builder<T> bindTo(final TextView textView) {
@SuppressWarnings("unchecked")
final Builder<String> t = (Builder<String>) this;
@@ -178,22 +202,6 @@
}
/**
- * Calls {@link #bindTwoWay(TextView)} if the {@link TextView} is an {@link EditText},
- * {@link #bindOneWay(TextView)} otherwise.
- */
- public Builder<T> bindTo(final TextView textView) {
- return textView instanceof EditText ? bindTwoWay(textView) : bindOneWay(textView);
- }
-
- /**
- * An alias for {@link #bindTwoWay(TextView)}, which is the default for {@link EditText}
- * widgets.
- */
- public Builder<T> bindTo(final EditText editText) {
- return bindTwoWay(editText);
- }
-
- /**
* Binds to the provided view in a default manner. This method delegates to
* {@link #bindTo(TextView)} for {@link TextView}s. Other view types are not yet supported.
*/
diff --git a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/package-info.java b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/package-info.java
index 0205082..1d86382 100644
--- a/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/package-info.java
+++ b/baku-toolkit/lib/src/main/java/io/v/baku/toolkit/package-info.java
@@ -9,20 +9,20 @@
* {@link io.v.baku.toolkit.BakuActivityMixin} for custom inheritance trees). Then, for any UI
* widget that should have distributed state, the client application should build data bindings by
* chaining methods from a {@link io.v.baku.toolkit.BakuActivityTrait#binder() binder()} call,
- * binding shared data fields to UI widget properties. For <a href="https://goo.gl/P0Ag9a"
- * target="_blank">example</a>, the following binds a data key named `"text"` to the text of a
- * {@link android.widget.TextView} with ID `textView`:
+ * binding shared data fields in the Syncbase distributed storage system to UI widget properties.
+ * For [example](https://goo.gl/P0Ag9a), the following binds a data key named `"text"` to the text
+ * of a {@link android.widget.TextView} with ID `textView`:
*
* ```java
* {@literal @}Override
* protected void onCreate(final Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
- * setContentView(R.layout.activity_layout);
+ * setContentView(R.layout.my_activity_layout);
*
* {@link io.v.baku.toolkit.BakuActivityMixin#binder() binder}().{@link
- * io.v.baku.toolkit.bind.SyncbaseBinding.Builder#key(java.lang.String) key}("text")
+ * io.v.baku.toolkit.bind.SyncbaseBinding.Builder#key(java.lang.String) key}("myDataRow")
* .{@link io.v.baku.toolkit.bind.SyncbaseBinding.Builder#bindTo(int)
- * bindTo}(R.id.textView);
+ * bindTo}(R.id.myTextView);
* }
* }
* ```