diff --git a/autocomplete/build.gradle b/autocomplete/build.gradle index 8b3c9b4..9278b72 100644 --- a/autocomplete/build.gradle +++ b/autocomplete/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' // Required by bintray -version = '1.0.2' +version = '1.0.3' group = 'com.otaliastudios' android { diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java index 922113b..30a0468 100644 --- a/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java @@ -217,13 +217,14 @@ public void click(T item) { * There is rarely need to call this externally: it is already triggered by events on the anchor. * To control when this is called, provide a good implementation of {@link AutocompletePolicy}. * - * @param query query text. + * @param query query object. */ - public void showPopup(CharSequence query) { - if (isPopupShowing() && lastQuery.equals(query.toString())) return; - lastQuery = query.toString(); + public void showPopup(Query query) { + CharSequence queryCharSequence = query.getCharSequence(); + if (isPopupShowing() && lastQuery.equals(queryCharSequence.toString())) return; + lastQuery = queryCharSequence.toString(); - log("showPopup: called with filter "+query); + log("showPopup: called with filter " + queryCharSequence); if (!isPopupShowing()) { log("showPopup: showing"); presenter.registerDataSetObserver(new Observer()); // Calling new to avoid leaking... maybe... @@ -387,7 +388,13 @@ public void run() { * Popup is shown when text length is bigger than 0, and hidden when text is empty. * The query string is the whole text. */ - public static class SimplePolicy implements AutocompletePolicy { + public static class SimplePolicy implements AutocompletePolicy { + private final CharQuery charQuery; + + public SimplePolicy() { + this.charQuery = new CharQuery(); + } + @Override public boolean shouldShowPopup(Spannable text, int cursorPos) { return text.length() > 0; @@ -399,8 +406,9 @@ public boolean shouldDismissPopup(Spannable text, int cursorPos) { } @Override - public CharSequence getQuery(Spannable text) { - return text; + public CharQuery getQuery(Spannable text) { + charQuery.setCharSequence(text); + return charQuery; } @Override diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java index 1cc7c48..70a09b6 100644 --- a/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java @@ -8,7 +8,7 @@ * * @see Autocomplete.SimplePolicy for the simplest possible implementation */ -public interface AutocompletePolicy { +public interface AutocompletePolicy { /** * Called to understand whether the popup should be shown. Some naive examples: @@ -49,7 +49,7 @@ public interface AutocompletePolicy { * @param text current text, along with its Spans * @return the query for presenter */ - CharSequence getQuery(Spannable text); + T getQuery(Spannable text); /** * Called when popup is dismissed. This can be used, for instance, to clear custom Spans diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java index 8e17359..cbea51b 100644 --- a/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java @@ -8,7 +8,7 @@ /** * Base class for presenting items inside a popup. This is abstract and must be implemented. * - * Most important methods are {@link #getView()} and {@link #onQuery(CharSequence)}. + * Most important methods are {@link #getView()} and {@link #onQuery(Query)}. */ public abstract class AutocompletePresenter { @@ -73,7 +73,7 @@ protected PopupDimensions getPopupDimensions() { * * @param query query from the edit text, to filter our results */ - protected abstract void onQuery(@Nullable CharSequence query); + protected abstract void onQuery(@Nullable Query query); /** * Called when the popup is hidden, to release resources. diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java index c9c2afd..0a2d8d1 100644 --- a/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java @@ -1,10 +1,8 @@ package com.otaliastudios.autocomplete; -import android.support.annotation.CallSuper; import android.support.annotation.Nullable; import android.text.Spannable; import android.text.Spanned; -import android.text.TextUtils; import android.util.Log; @@ -18,7 +16,7 @@ * - text "You should see this @j" : presenter will be passed the query "j" * - text "You should see this @john @m" : presenter will be passed the query "m" */ -public class CharPolicy implements AutocompletePolicy { +public class CharPolicy implements AutocompletePolicy { private final static String TAG = CharPolicy.class.getSimpleName(); private final static boolean DEBUG = false; @@ -29,7 +27,8 @@ private static void log(String log) { private final char CH; private final int[] INT = new int[2]; - private boolean needSpaceBefore = true; + private final CharQuery charQuery; + private boolean needSpaceBefore; /** * Constructs a char policy for the given character. @@ -37,7 +36,7 @@ private static void log(String log) { * @param trigger the triggering character. */ public CharPolicy(char trigger) { - CH = trigger; + this(trigger, true); } /** @@ -49,6 +48,7 @@ public CharPolicy(char trigger) { */ public CharPolicy(char trigger, boolean needSpaceBefore) { CH = trigger; + charQuery = new CharQuery(); this.needSpaceBefore = needSpaceBefore; } @@ -133,12 +133,13 @@ public boolean shouldDismissPopup(Spannable text, int cursorPos) { } @Override - public CharSequence getQuery(Spannable text) { + public CharQuery getQuery(Spannable text) { QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class); if (span == null || span.length == 0) { // Should never happen. log("getQuery: there's no span!"); - return ""; + charQuery.setCharSequence(""); + return charQuery; } log("getQuery: found spans: "+span.length); QuerySpan sp = span[0]; @@ -146,7 +147,8 @@ public CharSequence getQuery(Spannable text) { log("getQuery: span end is "+text.getSpanEnd(sp)); CharSequence seq = text.subSequence(text.getSpanStart(sp), text.getSpanEnd(sp)); log("getQuery: returning "+seq); - return seq; + charQuery.setCharSequence(seq); + return charQuery; } diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharQuery.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharQuery.java new file mode 100644 index 0000000..a2e3c84 --- /dev/null +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharQuery.java @@ -0,0 +1,18 @@ +package com.otaliastudios.autocomplete; + +public class CharQuery implements Query { + private CharSequence charSequence; + + public CharQuery() { + } + + @Override + public CharSequence getCharSequence() { + return charSequence; + } + + + public void setCharSequence(CharSequence charSequence) { + this.charSequence = charSequence; + } +} diff --git a/autocomplete/src/main/java/com/otaliastudios/autocomplete/Query.java b/autocomplete/src/main/java/com/otaliastudios/autocomplete/Query.java new file mode 100644 index 0000000..196a58f --- /dev/null +++ b/autocomplete/src/main/java/com/otaliastudios/autocomplete/Query.java @@ -0,0 +1,5 @@ +package com.otaliastudios.autocomplete; + +public interface Query { + CharSequence getCharSequence(); +} diff --git a/sample/src/main/java/com/otaliastudios/sample/MainActivity.java b/sample/src/main/java/com/otaliastudios/sample/MainActivity.java index fcd96cf..1dfde31 100644 --- a/sample/src/main/java/com/otaliastudios/sample/MainActivity.java +++ b/sample/src/main/java/com/otaliastudios/sample/MainActivity.java @@ -4,8 +4,8 @@ import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.Spanned; import android.text.style.StyleSpan; @@ -18,12 +18,14 @@ import com.otaliastudios.autocomplete.AutocompletePolicy; import com.otaliastudios.autocomplete.AutocompletePresenter; import com.otaliastudios.autocomplete.CharPolicy; +import com.otaliastudios.autocomplete.CharQuery; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Autocomplete userAutocomplete; private Autocomplete mentionsAutocomplete; private Autocomplete maleFemaleAutocomplete; + private CharQuery charQuery; @Override protected void onCreate(Bundle savedInstanceState) { @@ -37,6 +39,8 @@ protected void onCreate(Bundle savedInstanceState) { setupUserAutocomplete(); setupMentionsAutocomplete(); setupMaleFemaleAutocomplete(); + + charQuery = new CharQuery(); } private void setupUserAutocomplete() { @@ -130,10 +134,12 @@ public void onPopupVisibilityChanged(boolean shown) {} public void onClick(View v) { switch (v.getId()) { case R.id.single_button: - userAutocomplete.showPopup(" "); + charQuery.setCharSequence(" "); + userAutocomplete.showPopup(charQuery); break; case R.id.topbar_button: - maleFemaleAutocomplete.showPopup(" "); + charQuery.setCharSequence(" "); + maleFemaleAutocomplete.showPopup(charQuery); break; case R.id.multi_button: ((EditText) findViewById(R.id.multi)).setText(""); diff --git a/sample/src/main/java/com/otaliastudios/sample/MaleFemalePresenter.java b/sample/src/main/java/com/otaliastudios/sample/MaleFemalePresenter.java index 79ac2b4..712d4cf 100644 --- a/sample/src/main/java/com/otaliastudios/sample/MaleFemalePresenter.java +++ b/sample/src/main/java/com/otaliastudios/sample/MaleFemalePresenter.java @@ -3,15 +3,12 @@ import android.content.Context; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; -import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; -import com.otaliastudios.autocomplete.RecyclerViewPresenter; +import com.otaliastudios.autocomplete.Query; import java.util.ArrayList; import java.util.List; @@ -20,7 +17,7 @@ public class MaleFemalePresenter extends UserPresenter implements TabLayout.OnTabSelectedListener { private boolean females; - private CharSequence lastQuery; + private Query lastQuery; public MaleFemalePresenter(Context context) { super(context); @@ -44,9 +41,11 @@ protected ViewGroup getView() { } @Override - protected void onQuery(@Nullable CharSequence query) { + protected void onQuery(@Nullable Query query) { lastQuery = query; + CharSequence queryCharSequence = query == null ? null : query.getCharSequence(); + // First select males/females. List all = new ArrayList<>(); for (User u : User.USERS) { @@ -54,19 +53,19 @@ protected void onQuery(@Nullable CharSequence query) { } // Then filter based on query. - if (TextUtils.isEmpty(query)) { + if (TextUtils.isEmpty(queryCharSequence)) { adapter.setData(all); } else { - query = query.toString().toLowerCase(); + queryCharSequence = queryCharSequence.toString().toLowerCase(); List list = new ArrayList<>(); for (User u : all) { - if (u.getFullname().toLowerCase().contains(query) || - u.getUsername().toLowerCase().contains(query)) { + if (u.getFullname().toLowerCase().contains(queryCharSequence) || + u.getUsername().toLowerCase().contains(queryCharSequence)) { list.add(u); } } adapter.setData(list); - Log.e("MaleFemalePresenter", "found "+list.size()+" users for query "+query); + Log.e("MaleFemalePresenter", "found " + list.size() + " users for query " + queryCharSequence); } adapter.notifyDataSetChanged(); } diff --git a/sample/src/main/java/com/otaliastudios/sample/UserPresenter.java b/sample/src/main/java/com/otaliastudios/sample/UserPresenter.java index 291cda5..30e0d22 100644 --- a/sample/src/main/java/com/otaliastudios/sample/UserPresenter.java +++ b/sample/src/main/java/com/otaliastudios/sample/UserPresenter.java @@ -2,17 +2,15 @@ import android.content.Context; import android.support.annotation.Nullable; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; import android.widget.TextView; -import com.otaliastudios.autocomplete.AutocompletePresenter; +import com.otaliastudios.autocomplete.Query; import com.otaliastudios.autocomplete.RecyclerViewPresenter; import java.util.ArrayList; @@ -42,21 +40,23 @@ protected RecyclerView.Adapter instantiateAdapter() { } @Override - protected void onQuery(@Nullable CharSequence query) { + protected void onQuery(@Nullable Query query) { + CharSequence queryCharSequence = query == null ? null : query.getCharSequence(); + List all = User.USERS; - if (TextUtils.isEmpty(query)) { + if (TextUtils.isEmpty(queryCharSequence)) { adapter.setData(all); } else { - query = query.toString().toLowerCase(); + queryCharSequence = queryCharSequence.toString().toLowerCase(); List list = new ArrayList<>(); for (User u : all) { - if (u.getFullname().toLowerCase().contains(query) || - u.getUsername().toLowerCase().contains(query)) { + if (u.getFullname().toLowerCase().contains(queryCharSequence) || + u.getUsername().toLowerCase().contains(queryCharSequence)) { list.add(u); } } adapter.setData(list); - Log.e("UserPresenter", "found "+list.size()+" users for query "+query); + Log.e("UserPresenter", "found " + list.size() + " users for query " + queryCharSequence); } adapter.notifyDataSetChanged(); }