From 71c3b71e35b2936557e94d7c13b49be9c49f3c21 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 3 Jul 2018 00:25:02 +0200 Subject: [PATCH] better MaterialChipsInput, first iteration --- .../ui/EncryptModeAsymmetricFragment.java | 22 +- .../com/pchmn/materialchips/ChipsInput.java | 126 ++++++---- .../RecyclerItemClickListener.java | 51 ++++ .../materialchips/adapter/ChipsAdapter.java | 6 +- .../adapter/FilterableAdapter.java | 236 +++--------------- .../adapter/SimpleChipDropdownAdapter.java | 60 +++++ .../com/pchmn/materialchips/model/Chip.java | 39 --- .../materialchips/model/ChipInterface.java | 5 +- .../pchmn/materialchips/model/SimpleChip.java | 48 ++++ .../views/ChipsInputEditText.java | 10 +- .../materialchips/views/DropdownListView.java | 103 ++++++++ .../views/FilterableListView.java | 156 ------------ .../src/main/res/values/attrs.xml | 2 - 13 files changed, 401 insertions(+), 463 deletions(-) create mode 100644 extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/RecyclerItemClickListener.java create mode 100644 extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java delete mode 100644 extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java create mode 100644 extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java create mode 100644 extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DropdownListView.java delete mode 100644 extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java index d8d9e7629..681ad4a03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java @@ -36,15 +36,16 @@ import android.widget.ViewAnimator; import com.pchmn.materialchips.ChipsInput; import com.pchmn.materialchips.ChipsInput.ChipsListener; -import com.pchmn.materialchips.model.Chip; +import com.pchmn.materialchips.adapter.SimpleChipDropdownAdapter; import com.pchmn.materialchips.model.ChipInterface; +import com.pchmn.materialchips.model.SimpleChip; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.daos.KeyRepository; +import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; -import org.sufficientlysecure.keychain.daos.KeyRepository; -import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; @@ -153,13 +154,14 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { } } - private void onLoadEncryptRecipients(List keyInfoChips) { - mEncryptKeyView.setFilterableList(keyInfoChips); + private void onLoadEncryptRecipients(List keyInfoChips) { + SimpleChipDropdownAdapter chipDropdownAdapter = new SimpleChipDropdownAdapter(requireContext(), keyInfoChips); + mEncryptKeyView.setChipDropdownAdapter(chipDropdownAdapter); } public static class EncryptModeViewModel extends ViewModel { private LiveData> signKeyLiveData; - private LiveData> encryptRecipientLiveData; + private LiveData> encryptRecipientLiveData; LiveData> getSignKeyLiveData(Context context) { if (signKeyLiveData == null) { @@ -171,14 +173,14 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { return signKeyLiveData; } - LiveData> getEncryptRecipientLiveData(Context context) { + LiveData> getEncryptRecipientLiveData(Context context) { if (encryptRecipientLiveData == null) { encryptRecipientLiveData = new GenericLiveData<>(context, () -> { KeyRepository keyRepository = KeyRepository.create(context); List keyInfos = keyRepository.getAllUnifiedKeyInfo(); - ArrayList result = new ArrayList<>(); + ArrayList result = new ArrayList<>(); for (UnifiedKeyInfo keyInfo : keyInfos) { - result.add(new Chip(keyInfo.master_key_id(), keyInfo.name(), keyInfo.email())); + result.add(new SimpleChip(keyInfo.master_key_id(), keyInfo.name(), keyInfo.email(), keyInfo.user_id_list())); } return result; }); @@ -206,7 +208,7 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { try { CanonicalizedPublicKeyRing ring = keyRepository.getCanonicalizedPublicKeyRing(preselectedId); - Chip infooo = new Chip(ring.getMasterKeyId(), ring.getPrimaryUserIdWithFallback(), "infooo"); + SimpleChip infooo = new SimpleChip(ring.getMasterKeyId(), ring.getPrimaryUserIdWithFallback(), "infooo", null); mEncryptKeyView.addChip(infooo); } catch (NotFoundException e) { Timber.e(e, "key not found for encryption!"); diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java index d1e7ad18d..8147b1194 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java @@ -1,14 +1,17 @@ package com.pchmn.materialchips; +import java.util.ArrayList; +import java.util.List; + import android.app.Activity; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; @@ -17,27 +20,25 @@ import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; +import android.widget.Filter.FilterListener; import android.widget.RelativeLayout; import android.widget.TextView; import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager; +import com.pchmn.materialchips.RecyclerItemClickListener.OnItemClickListener; import com.pchmn.materialchips.adapter.ChipsAdapter; -import com.pchmn.materialchips.model.Chip; +import com.pchmn.materialchips.adapter.FilterableAdapter; import com.pchmn.materialchips.model.ChipInterface; +import com.pchmn.materialchips.model.SimpleChip; import com.pchmn.materialchips.util.ActivityUtil; import com.pchmn.materialchips.util.MyWindowCallback; import com.pchmn.materialchips.util.ViewUtil; import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.DetailedChipView; -import com.pchmn.materialchips.views.FilterableListView; +import com.pchmn.materialchips.views.DropdownListView; import com.pchmn.materialchips.views.ScrollViewMaxHeight; -import java.util.ArrayList; -import java.util.List; - public class ChipsInput extends ScrollViewMaxHeight { - - private static final String TAG = ChipsInput.class.toString(); // context private Context mContext; // xml element @@ -59,18 +60,15 @@ public class ChipsInput extends ScrollViewMaxHeight { private ColorStateList mChipDetailedTextColor; private ColorStateList mChipDetailedDeleteIconColor; private ColorStateList mChipDetailedBackgroundColor; - private ColorStateList mFilterableListBackgroundColor; - private ColorStateList mFilterableListTextColor; // chips listener private List mChipsListenerList = new ArrayList<>(); - private ChipsListener mChipsListener; // chip list - private List mFilterableChipList; - private FilterableListView mFilterableListView; + private DropdownListView mDropdownListView; // chip validator private ChipValidator mChipValidator; private ViewGroup filterableListLayout; private ChipsInputEditText mEditText; + private ChipDropdownAdapter filterableAdapter; public ChipsInput(Context context) { super(context); @@ -93,7 +91,7 @@ public class ChipsInput extends ScrollViewMaxHeight { // inflate filterableListLayout View rootView = inflate(getContext(), R.layout.chips_input, this); - mRecyclerView = (RecyclerView) rootView.findViewById(R.id.chips_recycler); + mRecyclerView = rootView.findViewById(R.id.chips_recycler); initEditText(); @@ -128,9 +126,6 @@ public class ChipsInput extends ScrollViewMaxHeight { mChipDetailedTextColor = a.getColorStateList(R.styleable.ChipsInput_chip_detailed_textColor); mChipDetailedBackgroundColor = a.getColorStateList(R.styleable.ChipsInput_chip_detailed_backgroundColor); mChipDetailedDeleteIconColor = a.getColorStateList(R.styleable.ChipsInput_chip_detailed_deleteIconColor); - // filterable list - mFilterableListBackgroundColor = a.getColorStateList(R.styleable.ChipsInput_filterable_list_backgroundColor); - mFilterableListTextColor = a.getColorStateList(R.styleable.ChipsInput_filterable_list_textColor); } finally { a.recycle(); } @@ -224,13 +219,13 @@ public class ChipsInput extends ScrollViewMaxHeight { mChipsAdapter.addChip(chip); } - public void addChip(Object id, String label, String info) { - Chip chip = new Chip(id, label, info); + public void addChip(Object id, String label, String info, String filterString) { + SimpleChip chip = new SimpleChip(id, label, info, filterString); mChipsAdapter.addChip(chip); } public void addChip(String label, String info) { - Chip chip = new Chip(label, info); + SimpleChip chip = new SimpleChip(label, info); mChipsAdapter.addChip(chip); } @@ -280,7 +275,6 @@ public class ChipsInput extends ScrollViewMaxHeight { public void addChipsListener(ChipsListener chipsListener) { mChipsListenerList.add(chipsListener); - mChipsListener = chipsListener; } public void onChipAdded(ChipInterface chip, int size) { @@ -296,25 +290,35 @@ public class ChipsInput extends ScrollViewMaxHeight { } public void onTextChanged(CharSequence text) { - if (mChipsListener != null) { - for (ChipsListener chipsListener : mChipsListenerList) { - chipsListener.onTextChanged(text); - } - // show filterable list - if (mFilterableListView != null) { - if (text.length() > 0) - mFilterableListView.filterList(text); - else - mFilterableListView.fadeOut(); + for (ChipsListener chipsListener : mChipsListenerList) { + chipsListener.onTextChanged(text); + } + // show filterable list + if (mDropdownListView != null) { + if (text.length() > 0) { + filterDropdownList(text); + } else { + mDropdownListView.fadeOut(); } } } - public void onActionDone(CharSequence text) { - if (mChipsListener != null) { - for (ChipsListener chipsListener : mChipsListenerList) { - chipsListener.onActionDone(text); + public void filterDropdownList(CharSequence text) { + filterableAdapter.getFilter().filter(text, new FilterListener() { + @Override + public void onFilterComplete(int count) { + // show if there are results + if (filterableAdapter.getItemCount() > 0) + mDropdownListView.fadeIn(); + else + mDropdownListView.fadeOut(); } + }); + } + + public void onActionDone(CharSequence text) { + for (ChipsListener chipsListener : mChipsListenerList) { + chipsListener.onActionDone(text); } } @@ -388,19 +392,51 @@ public class ChipsInput extends ScrollViewMaxHeight { this.filterableListLayout = layout; } - public void setFilterableList(List list) { - mFilterableChipList = list; - if (filterableListLayout != null) { - mFilterableListView = new FilterableListView(mContext, filterableListLayout); - } else { - mFilterableListView = new FilterableListView(mContext); + public abstract static class ChipDropdownAdapter + extends FilterableAdapter { + public ChipDropdownAdapter(List itemList) { + super(itemList); } - mFilterableListView.build(mFilterableChipList, this, mFilterableListBackgroundColor, mFilterableListTextColor); - mChipsAdapter.setFilterableListView(mFilterableListView); } - public List getFilterableList() { - return mFilterableChipList; + public void setChipDropdownAdapter(final ChipDropdownAdapter filterableAdapter) { + this.filterableAdapter = filterableAdapter; + if (filterableListLayout != null) { + mDropdownListView = new DropdownListView(mContext, filterableListLayout); + } else { + mDropdownListView = new DropdownListView(mContext, this); + } + mDropdownListView.build(filterableAdapter); + mChipsAdapter.setFilterableListView(mDropdownListView); + mDropdownListView.getRecyclerView().addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + ChipInterface item = filterableAdapter.getItem(position); + addChip(item); + } + })); + + addChipsListener(new ChipsInput.ChipsListener() { + @Override + public void onChipAdded(ChipInterface chip, int newSize) { + filterableAdapter.hideItem((T) chip); + } + + @Override + public void onChipRemoved(ChipInterface chip, int newSize) { + filterableAdapter.unhideItem((T) chip); + } + + @Override + public void onTextChanged(CharSequence text) { + mDropdownListView.getRecyclerView().scrollToPosition(0); + } + + @Override + public void onActionDone(CharSequence text) { + mDropdownListView.getRecyclerView().scrollToPosition(0); + } + }); } public ChipValidator getChipValidator() { diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/RecyclerItemClickListener.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/RecyclerItemClickListener.java new file mode 100644 index 000000000..2854f9ebf --- /dev/null +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/RecyclerItemClickListener.java @@ -0,0 +1,51 @@ +package com.pchmn.materialchips; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; + +public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { + private OnItemClickListener mListener; + private boolean mIgnoreTouch = false; + + public interface OnItemClickListener { + void onItemClick(View view, int position); + } + + private GestureDetector mGestureDetector; + + public RecyclerItemClickListener(Context context, OnItemClickListener listener) { + mListener = listener; + mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + return true; + } + }); + } + + @Override + public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { + if (mIgnoreTouch) { + return false; + } + View childView = view.findChildViewUnder(e.getX(), e.getY()); + if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { + mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); + return true; + } + return false; + } + + @Override + public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { + // TODO: should we move mListener.onItemClick here + } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + mIgnoreTouch = disallowIntercept; + } +} \ No newline at end of file diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/ChipsAdapter.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/ChipsAdapter.java index 64d8216a1..f20462257 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/ChipsAdapter.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/ChipsAdapter.java @@ -15,7 +15,7 @@ import com.pchmn.materialchips.model.ChipInterface; import com.pchmn.materialchips.util.ViewUtil; import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.DetailedChipView; -import com.pchmn.materialchips.views.FilterableListView; +import com.pchmn.materialchips.views.DropdownListView; import java.util.ArrayList; import java.util.Iterator; @@ -225,9 +225,9 @@ public class ChipsAdapter extends RecyclerView.Adapter detailedChipView.fadeIn(); } - public void setFilterableListView(FilterableListView filterableListView) { + public void setFilterableListView(DropdownListView dropdownListView) { if (mEditText != null) { - mEditText.setFilterableListView(filterableListView); + mEditText.setFilterableListView(dropdownListView); } } diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java index 2895a4252..b7816050b 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java @@ -1,186 +1,47 @@ package com.pchmn.materialchips.adapter; -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.PorterDuff; +import java.util.ArrayList; +import java.util.List; + import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; import android.widget.Filter; import android.widget.Filterable; -import android.widget.TextView; -import com.pchmn.materialchips.ChipsInput; -import com.pchmn.materialchips.R; -import com.pchmn.materialchips.model.ChipInterface; -import com.pchmn.materialchips.util.ColorUtil; -import com.pchmn.materialchips.util.LetterTileProvider; +import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; -import java.text.Collator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; +public abstract class FilterableAdapter + extends RecyclerView.Adapter implements Filterable { + private List displayedList = new ArrayList<>(); + private List hiddenItemsList = new ArrayList<>(); + private ItemFilter itemFilter; -import static android.view.View.GONE; - -public class FilterableAdapter extends RecyclerView.Adapter implements Filterable { - - private static final String TAG = FilterableAdapter.class.toString(); - // context - private Context mContext; - // list - private List mOriginalList = new ArrayList<>(); - private List mChipList = new ArrayList<>(); - private List mFilteredList = new ArrayList<>(); - private ChipFilter mFilter; - private ChipsInput mChipsInput; - private LetterTileProvider mLetterTileProvider; - private ColorStateList mBackgroundColor; - private ColorStateList mTextColor; - // recycler - private RecyclerView mRecyclerView; - // sort - private Comparator mComparator; - private Collator mCollator; - - - public FilterableAdapter(Context context, - RecyclerView recyclerView, - List chipList, - ChipsInput chipsInput, - ColorStateList backgroundColor, - ColorStateList textColor) { - mContext = context; - mRecyclerView = recyclerView; - mCollator = Collator.getInstance(Locale.getDefault()); - mCollator.setStrength(Collator.PRIMARY); - mComparator = new Comparator() { - @Override - public int compare(ChipInterface o1, ChipInterface o2) { - return mCollator.compare(o1.getLabel(), o2.getLabel()); - } - }; - // remove chips that do not have label - Iterator iterator = chipList.iterator(); - while (iterator.hasNext()) { - if (iterator.next().getLabel() == null) - iterator.remove(); - } - sortList(chipList); - mOriginalList.addAll(chipList); - mChipList.addAll(chipList); - mFilteredList.addAll(chipList); - mLetterTileProvider = new LetterTileProvider(mContext); - mBackgroundColor = backgroundColor; - mTextColor = textColor; - mChipsInput = chipsInput; - - mChipsInput.addChipsListener(new ChipsInput.ChipsListener() { - @Override - public void onChipAdded(ChipInterface chip, int newSize) { - removeChip(chip); - } - - @Override - public void onChipRemoved(ChipInterface chip, int newSize) { - addChip(chip); - } - - @Override - public void onTextChanged(CharSequence text) { - mRecyclerView.scrollToPosition(0); - } - - @Override - public void onActionDone(CharSequence text) { - mRecyclerView.scrollToPosition(0); - } - }); - } - - private class ItemViewHolder extends RecyclerView.ViewHolder { - - private TextView mLabel; - private TextView mInfo; - - ItemViewHolder(View view) { - super(view); - mLabel = (TextView) view.findViewById(R.id.label); - mInfo = (TextView) view.findViewById(R.id.info); - } - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(mContext).inflate(R.layout.item_list_filterable, parent, false); - return new ItemViewHolder(view); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - ItemViewHolder itemViewHolder = (ItemViewHolder) holder; - final ChipInterface chip = getItem(position); - - // label - itemViewHolder.mLabel.setText(chip.getLabel()); - - // info - if (chip.getInfo() != null) { - itemViewHolder.mInfo.setVisibility(View.VISIBLE); - itemViewHolder.mInfo.setText(chip.getInfo()); - } else { - itemViewHolder.mInfo.setVisibility(GONE); - } - - // colors - if (mBackgroundColor != null) - itemViewHolder.itemView.getBackground().setColorFilter(mBackgroundColor.getDefaultColor(), PorterDuff.Mode.SRC_ATOP); - if (mTextColor != null) { - itemViewHolder.mLabel.setTextColor(mTextColor); - itemViewHolder.mInfo.setTextColor(ColorUtil.alpha(mTextColor.getDefaultColor(), 150)); - } - - // onclick - itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mChipsInput != null) - mChipsInput.addChip(chip); - } - }); + public FilterableAdapter(List itemList) { + itemFilter = new ItemFilter(itemList); + displayedList.addAll(itemList); } @Override public int getItemCount() { - return mFilteredList.size(); + return displayedList.size(); } - private ChipInterface getItem(int position) { - return mFilteredList.get(position); + public T getItem(int position) { + return displayedList.get(position); } @Override public Filter getFilter() { - if (mFilter == null) - mFilter = new ChipFilter(this, mChipList); - return mFilter; + return itemFilter; } - private class ChipFilter extends Filter { + private class ItemFilter extends Filter { + private List originalList; + private List filteredList; - private FilterableAdapter adapter; - private List originalList; - private List filteredList; - - public ChipFilter(FilterableAdapter adapter, List originalList) { + ItemFilter(List chipList) { super(); - this.adapter = adapter; - this.originalList = originalList; + this.originalList = new ArrayList<>(chipList); this.filteredList = new ArrayList<>(); } @@ -188,15 +49,13 @@ public class FilterableAdapter extends RecyclerView.Adapter) results.values); + FilterableAdapter.this.displayedList.clear(); + FilterableAdapter.this.displayedList.addAll((ArrayList) results.values); notifyDataSetChanged(); } } - private void removeChip(ChipInterface chip) { - int position = mFilteredList.indexOf(chip); - if (position >= 0) - mFilteredList.remove(position); - - position = mChipList.indexOf(chip); - if (position >= 0) - mChipList.remove(position); - + public void hideItem(T item) { + if (!hiddenItemsList.contains(item)) { + hiddenItemsList.add(item); + } notifyDataSetChanged(); } - private void addChip(ChipInterface chip) { - if (contains(chip)) { - mChipList.add(chip); - mFilteredList.add(chip); - // sort original list - sortList(mChipList); - // sort filtered list - sortList(mFilteredList); - - notifyDataSetChanged(); - } + public void unhideItem(T item) { + hiddenItemsList.remove(item); + notifyDataSetChanged(); } - private boolean contains(ChipInterface chip) { - for (ChipInterface item : mOriginalList) { - if (item.equals(chip)) - return true; - } - return false; - } - - private void sortList(List list) { - Collections.sort(list, mComparator); + public interface FilterableItem { + boolean isKeptForConstraint(CharSequence constraint); } } diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java new file mode 100644 index 000000000..cdf278088 --- /dev/null +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java @@ -0,0 +1,60 @@ +package com.pchmn.materialchips.adapter; + + +import java.util.List; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.pchmn.materialchips.ChipsInput.ChipDropdownAdapter; +import com.pchmn.materialchips.R; +import com.pchmn.materialchips.adapter.SimpleChipDropdownAdapter.ItemViewHolder; +import com.pchmn.materialchips.model.ChipInterface; +import com.pchmn.materialchips.model.SimpleChip; + + +public class SimpleChipDropdownAdapter extends ChipDropdownAdapter { + private final LayoutInflater layoutInflater; + + public SimpleChipDropdownAdapter(Context context, List keyInfoChips) { + super(keyInfoChips); + + layoutInflater = LayoutInflater.from(context); + } + + class ItemViewHolder extends RecyclerView.ViewHolder { + private TextView mLabel; + private TextView mInfo; + + ItemViewHolder(View view) { + super(view); + mLabel = view.findViewById(com.pchmn.materialchips.R.id.label); + mInfo = view.findViewById(com.pchmn.materialchips.R.id.info); + } + } + + @NonNull + @Override + public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = layoutInflater.inflate(R.layout.item_list_filterable, parent, false); + return new ItemViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) { + ChipInterface chip = getItem(position); + + holder.mLabel.setText(chip.getLabel()); + if (chip.getInfo() != null) { + holder.mInfo.setVisibility(View.VISIBLE); + holder.mInfo.setText(chip.getInfo()); + } else { + holder.mInfo.setVisibility(View.GONE); + } + } +} diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java deleted file mode 100644 index e79c79cd9..000000000 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.pchmn.materialchips.model; - - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -public class Chip implements ChipInterface { - - private Object id; - private String label; - private String info; - - public Chip(@NonNull Object id, @NonNull String label, @Nullable String info) { - this.id = id; - this.label = label; - this.info = info; - } - - - public Chip(@NonNull String label, @Nullable String info) { - this.label = label; - this.info = info; - } - - @Override - public Object getId() { - return id; - } - - @Override - public String getLabel() { - return label; - } - - @Override - public String getInfo() { - return info; - } -} diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java index 804ef47f1..edb12b590 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java @@ -1,11 +1,10 @@ package com.pchmn.materialchips.model; -import android.graphics.drawable.Drawable; -import android.net.Uri; +import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; -public interface ChipInterface { +public interface ChipInterface extends FilterableItem { Object getId(); String getLabel(); String getInfo(); diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java new file mode 100644 index 000000000..acd740b17 --- /dev/null +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java @@ -0,0 +1,48 @@ +package com.pchmn.materialchips.model; + + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; + + +public class SimpleChip implements ChipInterface { + + private Object id; + private String label; + private String info; + private String filterString; + + public SimpleChip(@NonNull Object id, @NonNull String label, @Nullable String info, @Nullable String filterString) { + this.id = id; + this.label = label; + this.info = info; + this.filterString = filterString != null ? filterString.toLowerCase() : label.toLowerCase(); + } + + public SimpleChip(@NonNull String label, @Nullable String info) { + this.label = label; + this.info = info; + } + + @Override + public Object getId() { + return id; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getInfo() { + return info; + } + + @Override + public boolean isKeptForConstraint(CharSequence constraint) { + return filterString.contains(constraint); + } +} diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java index d3bb04f5d..9c2b108c5 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java @@ -4,10 +4,12 @@ package com.pchmn.materialchips.views; import android.content.Context; import android.util.AttributeSet; import android.util.Log; +import android.view.View; + public class ChipsInputEditText extends android.support.v7.widget.AppCompatEditText { - private FilterableListView filterableListView; + private View filterableListView; public ChipsInputEditText(Context context) { super(context); @@ -21,11 +23,7 @@ public class ChipsInputEditText extends android.support.v7.widget.AppCompatEditT return filterableListView != null && filterableListView.getVisibility() == VISIBLE; } - public FilterableListView getFilterableListView() { - return filterableListView; - } - - public void setFilterableListView(FilterableListView filterableListView) { + public void setFilterableListView(View filterableListView) { this.filterableListView = filterableListView; } } diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DropdownListView.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DropdownListView.java new file mode 100644 index 000000000..d44019dac --- /dev/null +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DropdownListView.java @@ -0,0 +1,103 @@ +package com.pchmn.materialchips.views; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Build; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.animation.AlphaAnimation; +import android.widget.RelativeLayout; + +import com.pchmn.materialchips.R; +import com.pchmn.materialchips.adapter.FilterableAdapter; +import com.pchmn.materialchips.util.ViewUtil; + + +@SuppressLint("ViewConstructor") // this is a dropdown view, it doesn't come up in preview +public class DropdownListView extends RelativeLayout { + private RecyclerView recyclerView; + private ViewGroup rootView; + + public DropdownListView(Context context, ViewGroup layout) { + super(context); + this.rootView = layout; + init(); + } + + private void init() { + View view = inflate(getContext(), R.layout.list_filterable_view, this); + + recyclerView = view.findViewById(R.id.recycler_view); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); + + setVisibility(GONE); + } + + public void build(FilterableAdapter filterableAdapter) { + recyclerView.setAdapter(filterableAdapter); + + rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + // size + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( + ViewUtil.getWindowWidth(getContext()), + ViewGroup.LayoutParams.WRAP_CONTENT); + + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + layoutParams.bottomMargin = ViewUtil.getNavBarHeight(getContext()); + } + + // If this child view is already added to the parent rootView, then remove it first + ViewGroup parent = (ViewGroup) DropdownListView.this.getParent(); + if (parent != null) { + parent.removeView(DropdownListView.this); + } + // add view + rootView.addView(DropdownListView.this, layoutParams); + + // remove the listener: + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + } + + }); + } + + public RecyclerView getRecyclerView() { + return recyclerView; + } + + public void fadeIn() { + if (getVisibility() == VISIBLE) { + return; + } + + AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); + anim.setDuration(200); + startAnimation(anim); + setVisibility(VISIBLE); + } + + public void fadeOut() { + if (getVisibility() == GONE) { + return; + } + + AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f); + anim.setDuration(200); + startAnimation(anim); + setVisibility(GONE); + } +} diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java deleted file mode 100644 index ba4034fb7..000000000 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.pchmn.materialchips.views; - - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Configuration; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.os.Build; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.animation.AlphaAnimation; -import android.widget.Filter; -import android.widget.FrameLayout; -import android.widget.RelativeLayout; - -import com.pchmn.materialchips.ChipsInput; -import com.pchmn.materialchips.R; -import com.pchmn.materialchips.adapter.FilterableAdapter; -import com.pchmn.materialchips.model.ChipInterface; -import com.pchmn.materialchips.util.ViewUtil; - -import java.util.List; - -public class FilterableListView extends RelativeLayout { - - private static final String TAG = FilterableListView.class.toString(); - private FrameLayout frameLayout; - private Context mContext; - // list - private RecyclerView mRecyclerView; - private FilterableAdapter mAdapter; - private List mFilterableList; - // others - private ChipsInput mChipsInput; - private ViewGroup rootView; - - public FilterableListView(Context context) { - this(context, null); - } - - public FilterableListView(Context context, ViewGroup layout) { - super(context); - this.mContext = context; - this.rootView = layout; - init(); - } - - private void init() { - // inflate layout - View view = inflate(getContext(), R.layout.list_filterable_view, this); - - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - - // recycler - mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)); - - // hide on first - setVisibility(GONE); - } - - public void build(List filterableList, ChipsInput chipsInput, ColorStateList backgroundColor, ColorStateList textColor) { - mFilterableList = filterableList; - mChipsInput = chipsInput; - - // adapter - mAdapter = new FilterableAdapter(mContext, mRecyclerView, filterableList, chipsInput, backgroundColor, textColor); - mRecyclerView.setAdapter(mAdapter); - if(backgroundColor != null) - mRecyclerView.getBackground().setColorFilter(backgroundColor.getDefaultColor(), PorterDuff.Mode.SRC_ATOP); - - // listen to change in the tree - mChipsInput.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - - @Override - public void onGlobalLayout() { - - // position - if(rootView == null){ - rootView = (ViewGroup) mChipsInput.getRootView(); - } - - // size - RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( - ViewUtil.getWindowWidth(mContext), - ViewGroup.LayoutParams.WRAP_CONTENT); - - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); - - if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - layoutParams.bottomMargin = ViewUtil.getNavBarHeight(mContext); - } - - //If this child view is already added to the parent rootView, then remove it first - ViewGroup parent = (ViewGroup) FilterableListView.this.getParent(); - if (parent != null) { - parent.removeView(FilterableListView.this); - } - // add view - rootView.addView(FilterableListView.this, layoutParams); - - - // remove the listener: - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - mChipsInput.getViewTreeObserver().removeGlobalOnLayoutListener(this); - } else { - mChipsInput.getViewTreeObserver().removeOnGlobalLayoutListener(this); - } - } - - }); - } - - public void filterList(CharSequence text) { - mAdapter.getFilter().filter(text, new Filter.FilterListener() { - @Override - public void onFilterComplete(int count) { - // show if there are results - if(mAdapter.getItemCount() > 0) - fadeIn(); - else - fadeOut(); - } - }); - } - - /** - * Fade in - */ - public void fadeIn() { - if(getVisibility() == VISIBLE) - return; - - AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); - anim.setDuration(200); - startAnimation(anim); - setVisibility(VISIBLE); - } - - /** - * Fade out - */ - public void fadeOut() { - if(getVisibility() == GONE) - return; - - AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f); - anim.setDuration(200); - startAnimation(anim); - setVisibility(GONE); - } -} diff --git a/extern/MaterialChipsInput/src/main/res/values/attrs.xml b/extern/MaterialChipsInput/src/main/res/values/attrs.xml index ab9511869..7c49f83a0 100644 --- a/extern/MaterialChipsInput/src/main/res/values/attrs.xml +++ b/extern/MaterialChipsInput/src/main/res/values/attrs.xml @@ -24,8 +24,6 @@ - -