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 681ad4a03..d1523e9d8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java @@ -34,31 +34,29 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ViewAnimator; -import com.pchmn.materialchips.ChipsInput; -import com.pchmn.materialchips.ChipsInput.ChipsListener; -import com.pchmn.materialchips.adapter.SimpleChipDropdownAdapter; +import com.pchmn.materialchips.ChipsInput.SimpleChipsListener; import com.pchmn.materialchips.model.ChipInterface; -import com.pchmn.materialchips.model.SimpleChip; +import com.pchmn.materialchips.simple.SimpleChip; +import com.pchmn.materialchips.simple.SimpleChipsInput; 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.ui.chips.EncryptRecipientChipsInput; +import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.util.Passphrase; -import timber.log.Timber; public class EncryptModeAsymmetricFragment extends EncryptModeFragment { KeyRepository keyRepository; private KeySpinner mSignKeySpinner; - private ChipsInput mEncryptKeyView; + private SimpleChipsInput mEncryptKeyView; public static final String ARG_SINGATURE_KEY_ID = "signature_key_id"; public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; @@ -105,31 +103,21 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { mSignKeySpinner.setShowNone(R.string.cert_none); final ViewAnimator vEncryptionIcon = view.findViewById(R.id.result_encryption_icon); - mEncryptKeyView.addChipsListener(new ChipsListener() { + mEncryptKeyView.addChipsListener(new SimpleChipsListener() { @Override - public void onChipAdded(ChipInterface chipInterface, int newSize) { + public void onChipAdded(SimpleChip chipInterface, int newSize) { if (vEncryptionIcon.getDisplayedChild() != 1) { vEncryptionIcon.setDisplayedChild(1); } } @Override - public void onChipRemoved(ChipInterface chipInterface, int newSize) { + public void onChipRemoved(SimpleChip chipInterface, int newSize) { int child = newSize == 0 ? 0 : 1; if (vEncryptionIcon.getDisplayedChild() != child) { vEncryptionIcon.setDisplayedChild(child); } } - - @Override - public void onTextChanged(CharSequence charSequence) { - - } - - @Override - public void onActionDone(CharSequence charSequence) { - - } }); return view; @@ -141,7 +129,13 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class); viewModel.getSignKeyLiveData(requireContext()).observe(this, mSignKeySpinner::setData); - viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, this::onLoadEncryptRecipients); + viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, (keyUnifiedData) -> { + ArrayList simpleChips = new ArrayList<>(); + for (EncryptRecipientChip chip : keyUnifiedData) { + simpleChips.add(new SimpleChip(chip.keyInfo.master_key_id(), chip.keyInfo.name(), chip.keyInfo.email(), chip.keyInfo.user_id_list())); + } + mEncryptKeyView.setData(simpleChips); + }); // preselect keys given, from state or arguments if (savedInstanceState == null) { @@ -154,14 +148,9 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { } } - 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) { @@ -173,14 +162,15 @@ 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 SimpleChip(keyInfo.master_key_id(), keyInfo.name(), keyInfo.email(), keyInfo.user_id_list())); + EncryptRecipientChip chip = EncryptRecipientChipsInput.chipFromUnifiedKeyInfo(keyInfo); + result.add(chip); } return result; }); @@ -205,22 +195,16 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment { if (encryptionKeyIds != null) { for (long preselectedId : encryptionKeyIds) { - try { - CanonicalizedPublicKeyRing ring = - keyRepository.getCanonicalizedPublicKeyRing(preselectedId); - SimpleChip infooo = new SimpleChip(ring.getMasterKeyId(), ring.getPrimaryUserIdWithFallback(), "infooo", null); - mEncryptKeyView.addChip(infooo); - } catch (NotFoundException e) { - Timber.e(e, "key not found for encryption!"); - Notify.create(getActivity(), getString(R.string.error_preselect_encrypt_key, - KeyFormattingUtils.beautifyKeyId(preselectedId)), - Style.ERROR).show(); - } + UnifiedKeyInfo keyInfo = keyRepository.getUnifiedKeyInfo(preselectedId); + EncryptRecipientChip recipientChip = EncryptRecipientChipsInput.chipFromUnifiedKeyInfo(keyInfo); + // mEncryptKeyView.addChip(recipientChip); + // EncryptRecipientChip infooo = + // new EncryptRecipientChip(ring.getMasterKeyId(), ring.getPrimaryUserIdWithFallback(), "infooo", null); + // mEncryptKeyView.addChip(infooo); } // This is to work-around a rendering bug in TokenCompleteTextView mEncryptKeyView.requestFocus(); } - } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/chips/EncryptRecipientChipsInput.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/chips/EncryptRecipientChipsInput.java new file mode 100644 index 000000000..ea4c1bd47 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/chips/EncryptRecipientChipsInput.java @@ -0,0 +1,53 @@ +package org.sufficientlysecure.keychain.ui.chips; + + +import java.util.List; + +import android.content.Context; +import android.util.AttributeSet; + +import com.pchmn.materialchips.ChipsInput; +import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; +import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip; + + +public class EncryptRecipientChipsInput extends ChipsInput { + public EncryptRecipientChipsInput(Context context) { + super(context); + init(); + } + + public EncryptRecipientChipsInput(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { +// ChipsAdapter chipsAdapter = new SimpleChipsAdapter(getContext(), this); +// setChipsAdapter(chipsAdapter); + } + + public void setData(List keyInfoChips) { +// SimpleChipDropdownAdapter chipDropdownAdapter = new SimpleChipDropdownAdapter(getContext(), simpleChips); +// setChipDropdownAdapter(chipDropdownAdapter); + } + + public static class EncryptRecipientChip implements FilterableItem { + public final UnifiedKeyInfo keyInfo; + + EncryptRecipientChip(UnifiedKeyInfo keyInfo) { + this.keyInfo = keyInfo; + } + + @Override + public boolean isKeptForConstraint(CharSequence constraint) { + String uidList = keyInfo.user_id_list(); + return uidList == null || uidList.contains(constraint); + } + } + + public static EncryptRecipientChip chipFromUnifiedKeyInfo(UnifiedKeyInfo keyInfo) { + return new EncryptRecipientChip(keyInfo); + } +} diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml index 1ff410f43..7f4b505b7 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml @@ -38,7 +38,7 @@ - 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 cfa962a44..5320a397b 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java @@ -8,8 +8,6 @@ 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.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.Editable; @@ -28,44 +26,34 @@ import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager; import com.pchmn.materialchips.RecyclerItemClickListener.OnItemClickListener; import com.pchmn.materialchips.adapter.ChipsAdapter; import com.pchmn.materialchips.adapter.FilterableAdapter; -import com.pchmn.materialchips.model.ChipInterface; -import com.pchmn.materialchips.model.SimpleChip; +import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; import com.pchmn.materialchips.util.ActivityUtil; -import com.pchmn.materialchips.util.MyWindowCallback; +import com.pchmn.materialchips.util.ClickOutsideCallback; import com.pchmn.materialchips.util.ViewUtil; import com.pchmn.materialchips.views.ChipsInputEditText; -import com.pchmn.materialchips.views.DetailedChipView; import com.pchmn.materialchips.views.DropdownListView; import com.pchmn.materialchips.views.ScrollViewMaxHeight; -public class ChipsInput extends ScrollViewMaxHeight { - // context +public abstract class ChipsInput extends ScrollViewMaxHeight { private Context mContext; - private ChipsAdapter mChipsAdapter; + // attributes - private static final int NONE = -1; private String mHint; private ColorStateList mHintColor; private ColorStateList mTextColor; private int mMaxRows = 2; - private ColorStateList mChipLabelColor; - private boolean mChipDeletable = false; - private Drawable mChipDeleteIcon; - private ColorStateList mChipDeleteIconColor; - private ColorStateList mChipBackgroundColor; private boolean mShowChipDetailed = true; - private ColorStateList mChipDetailedTextColor; - private ColorStateList mChipDetailedDeleteIconColor; - private ColorStateList mChipDetailedBackgroundColor; - // chips listener - private List mChipsListenerList = new ArrayList<>(); - // chip list - private DropdownListView mDropdownListView; - // chip validator - private ChipValidator mChipValidator; + + private List> mChipsListenerList = new ArrayList<>(); + private ChipValidator mChipValidator; + + private ChipsAdapter chipsAdapter; + private RecyclerView chipsRecyclerView; + private ChipsInputEditText chipsInputEditText; + + private ChipDropdownAdapter filterableAdapter; private ViewGroup filterableListLayout; - private ChipsInputEditText mEditText; - private ChipDropdownAdapter filterableAdapter; + private DropdownListView mDropdownListView; public ChipsInput(Context context) { super(context); @@ -88,7 +76,7 @@ public class ChipsInput extends ScrollViewMaxHeight { // inflate filterableListLayout View rootView = inflate(getContext(), R.layout.chips_input, this); - RecyclerView recyclerView = rootView.findViewById(R.id.chips_recycler); + chipsRecyclerView = rootView.findViewById(R.id.chips_recycler); initEditText(); @@ -107,91 +95,82 @@ public class ChipsInput extends ScrollViewMaxHeight { mMaxRows = a.getInteger(R.styleable.ChipsInput_maxRows, 2); setMaxHeight(ViewUtil.dpToPx((40 * mMaxRows) + 8)); //setVerticalScrollBarEnabled(true); - // chip label color - mChipLabelColor = a.getColorStateList(R.styleable.ChipsInput_chip_labelColor); - // chip delete icon - mChipDeletable = a.getBoolean(R.styleable.ChipsInput_chip_deletable, false); - mChipDeleteIconColor = a.getColorStateList(R.styleable.ChipsInput_chip_deleteIconColor); - int deleteIconId = a.getResourceId(R.styleable.ChipsInput_chip_deleteIcon, NONE); - if (deleteIconId != NONE) - mChipDeleteIcon = ContextCompat.getDrawable(mContext, deleteIconId); - // chip background color - mChipBackgroundColor = a.getColorStateList(R.styleable.ChipsInput_chip_backgroundColor); - // show chip detailed mShowChipDetailed = a.getBoolean(R.styleable.ChipsInput_showChipDetailed, true); // chip detailed text color - 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); } finally { a.recycle(); } } - // adapter - mChipsAdapter = new ChipsAdapter(mContext, this, mEditText, recyclerView); ChipsLayoutManager chipsLayoutManager = ChipsLayoutManager.newBuilder(mContext) .setOrientation(ChipsLayoutManager.HORIZONTAL) .build(); - recyclerView.setLayoutManager(chipsLayoutManager); - recyclerView.setNestedScrollingEnabled(false); - recyclerView.setAdapter(mChipsAdapter); + chipsRecyclerView.setLayoutManager(chipsLayoutManager); + chipsRecyclerView.setNestedScrollingEnabled(false); - // set window callback - // will hide DetailedOpenView and hide keyboard on touch outside + setupClickOutsideCallback(); + } + + public void setChipsAdapter(ChipsAdapter chipsAdapter) { + this.chipsAdapter = chipsAdapter; + chipsRecyclerView.setAdapter(chipsAdapter); + } + + private void setupClickOutsideCallback() { Activity activity = ActivityUtil.scanForActivity(mContext); - if (activity == null) + if (activity == null) { throw new ClassCastException("android.view.Context cannot be cast to android.app.Activity"); + } - android.view.Window.Callback mCallBack = (activity).getWindow().getCallback(); - activity.getWindow().setCallback(new MyWindowCallback(mCallBack, activity)); + android.view.Window.Callback originalWindowCallback = (activity).getWindow().getCallback(); + activity.getWindow().setCallback(new ClickOutsideCallback(originalWindowCallback, activity)); } private void initEditText() { - mEditText = new ChipsInputEditText(mContext); + chipsInputEditText = new ChipsInputEditText(mContext); if (mHintColor != null) - mEditText.setHintTextColor(mHintColor); + chipsInputEditText.setHintTextColor(mHintColor); if (mTextColor != null) - mEditText.setTextColor(mTextColor); + chipsInputEditText.setTextColor(mTextColor); - mEditText.setLayoutParams(new RelativeLayout.LayoutParams( + chipsInputEditText.setLayoutParams(new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - mEditText.setHint(mHint); - mEditText.setBackgroundResource(android.R.color.transparent); + chipsInputEditText.setHint(mHint); + chipsInputEditText.setBackgroundResource(android.R.color.transparent); // prevent fullscreen on landscape - mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); - mEditText.setPrivateImeOptions("nm"); + chipsInputEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); + chipsInputEditText.setPrivateImeOptions("nm"); // no suggestion - mEditText.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + chipsInputEditText.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); // handle back space - mEditText.setOnKeyListener(new View.OnKeyListener() { + chipsInputEditText.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { // backspace if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL) { // remove last chip - if (mEditText.getText().toString().length() == 0) - mChipsAdapter.removeLastChip(); + if (chipsInputEditText.getText().toString().length() == 0) + chipsAdapter.removeLastChip(); } return false; } }); - mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + chipsInputEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { - ChipsInput.this.onActionDone(mEditText.getText().toString()); + ChipsInput.this.onActionDone(chipsInputEditText.getText().toString()); } return false; } }); // text changed - mEditText.addTextChangedListener(new TextWatcher() { + chipsInputEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -208,80 +187,28 @@ public class ChipsInput extends ScrollViewMaxHeight { }); } - public void addChips(List chipList) { - mChipsAdapter.addChipsProgrammatically(chipList); - } - - public void addChip(ChipInterface chip) { - mChipsAdapter.addChip(chip); - } - - 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) { - SimpleChip chip = new SimpleChip(label, info); - mChipsAdapter.addChip(chip); - } - - public void removeChip(ChipInterface chip) { - mChipsAdapter.removeChip(chip); - } - - public void removeChipById(Object id) { - mChipsAdapter.removeChipById(id); - } - - public void removeChipByLabel(String label) { - mChipsAdapter.removeChipByLabel(label); - } - - public void removeChipByInfo(String info) { - mChipsAdapter.removeChipByInfo(info); - } - - public ChipView getChipView() { - int padding = ViewUtil.dpToPx(4); - ChipView chipView = new ChipView.Builder(mContext) - .labelColor(mChipLabelColor) - .deletable(mChipDeletable) - .deleteIcon(mChipDeleteIcon) - .deleteIconColor(mChipDeleteIconColor) - .backgroundColor(mChipBackgroundColor) - .build(); - - chipView.setPadding(padding, padding, padding, padding); - - return chipView; + public void addChip(T chip) { + chipsAdapter.addChip(chip); } public ChipsInputEditText getEditText() { - return mChipsAdapter.getmEditText(); + return chipsInputEditText; } - public DetailedChipView getDetailedChipView(ChipInterface chip) { - return new DetailedChipView.Builder(mContext) - .chip(chip) - .textColor(mChipDetailedTextColor) - .backgroundColor(mChipDetailedBackgroundColor) - .deleteIconColor(mChipDetailedDeleteIconColor) - .build(); - } - - public void addChipsListener(ChipsListener chipsListener) { + public void addChipsListener(ChipsListener chipsListener) { mChipsListenerList.add(chipsListener); } - public void onChipAdded(ChipInterface chip, int size) { - for (ChipsListener chipsListener : mChipsListenerList) { + public void onChipAdded(T chip, int size) { + filterableAdapter.hideItem(chip); + for (ChipsListener chipsListener : mChipsListenerList) { chipsListener.onChipAdded(chip, size); } } - public void onChipRemoved(ChipInterface chip, int size) { - for (ChipsListener chipsListener : mChipsListenerList) { + public void onChipRemoved(T chip, int size) { + filterableAdapter.unhideItem(chip); + for (ChipsListener chipsListener : mChipsListenerList) { chipsListener.onChipRemoved(chip, size); } } @@ -290,6 +217,9 @@ public class ChipsInput extends ScrollViewMaxHeight { for (ChipsListener chipsListener : mChipsListenerList) { chipsListener.onTextChanged(text); } + + mDropdownListView.getRecyclerView().scrollToPosition(0); + // show filterable list if (mDropdownListView != null) { if (text.length() > 0) { @@ -317,10 +247,11 @@ public class ChipsInput extends ScrollViewMaxHeight { for (ChipsListener chipsListener : mChipsListenerList) { chipsListener.onActionDone(text); } + mDropdownListView.getRecyclerView().scrollToPosition(0); } - public List getSelectedChipList() { - return mChipsAdapter.getChipList(); + public List getSelectedChipList() { + return chipsAdapter.getChipList(); } public String getHint() { @@ -344,26 +275,6 @@ public class ChipsInput extends ScrollViewMaxHeight { return this; } - public void setChipLabelColor(ColorStateList mLabelColor) { - this.mChipLabelColor = mLabelColor; - } - - public void setChipDeletable(boolean mDeletable) { - this.mChipDeletable = mDeletable; - } - - public void setChipDeleteIcon(Drawable mDeleteIcon) { - this.mChipDeleteIcon = mDeleteIcon; - } - - public void setChipDeleteIconColor(ColorStateList mDeleteIconColor) { - this.mChipDeleteIconColor = mDeleteIconColor; - } - - public void setChipBackgroundColor(ColorStateList mBackgroundColor) { - this.mChipBackgroundColor = mBackgroundColor; - } - public ChipsInput setShowChipDetailed(boolean mShowChipDetailed) { this.mShowChipDetailed = mShowChipDetailed; return this; @@ -373,30 +284,22 @@ public class ChipsInput extends ScrollViewMaxHeight { return mShowChipDetailed; } - public void setChipDetailedTextColor(ColorStateList mChipDetailedTextColor) { - this.mChipDetailedTextColor = mChipDetailedTextColor; - } - - public void setChipDetailedDeleteIconColor(ColorStateList mChipDetailedDeleteIconColor) { - this.mChipDetailedDeleteIconColor = mChipDetailedDeleteIconColor; - } - - public void setChipDetailedBackgroundColor(ColorStateList mChipDetailedBackgroundColor) { - this.mChipDetailedBackgroundColor = mChipDetailedBackgroundColor; - } - public void setFilterableListLayout(ViewGroup layout) { this.filterableListLayout = layout; } - public abstract static class ChipDropdownAdapter + public RecyclerView getChipsRecyclerView() { + return chipsRecyclerView; + } + + public abstract static class ChipDropdownAdapter extends FilterableAdapter { public ChipDropdownAdapter(List itemList) { super(itemList); } } - public void setChipDropdownAdapter(final ChipDropdownAdapter filterableAdapter) { + public void setChipDropdownAdapter(final ChipDropdownAdapter filterableAdapter) { this.filterableAdapter = filterableAdapter; if (filterableListLayout != null) { mDropdownListView = new DropdownListView(mContext, filterableListLayout); @@ -404,57 +307,39 @@ public class ChipsInput extends ScrollViewMaxHeight { mDropdownListView = new DropdownListView(mContext, this); } mDropdownListView.build(filterableAdapter); - mChipsAdapter.setFilterableListView(mDropdownListView); + chipsAdapter.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); + T item = filterableAdapter.getItem(position); + chipsAdapter.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() { + public ChipValidator getChipValidator() { return mChipValidator; } - public void setChipValidator(ChipValidator mChipValidator) { + public void setChipValidator(ChipValidator mChipValidator) { this.mChipValidator = mChipValidator; } - public interface ChipsListener { - void onChipAdded(ChipInterface chip, int newSize); - - void onChipRemoved(ChipInterface chip, int newSize); - + public interface ChipsListener { + void onChipAdded(T chip, int newSize); + void onChipRemoved(T chip, int newSize); void onTextChanged(CharSequence text); - void onActionDone(CharSequence text); } - public interface ChipValidator { - boolean areEquals(ChipInterface chip1, ChipInterface chip2); + public static abstract class SimpleChipsListener implements ChipsListener { + public void onChipAdded(T chip, int newSize) { } + public void onChipRemoved(T chip, int newSize) { } + public void onTextChanged(CharSequence text) { } + public void onActionDone(CharSequence text) { } + } + + public interface ChipValidator { + boolean areEquals(T chip1, T chip2); } } 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 f20462257..1770a2b77 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 @@ -1,8 +1,14 @@ package com.pchmn.materialchips.adapter; + +import java.util.ArrayList; +import java.util.List; + import android.content.Context; import android.os.Build; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -11,105 +17,49 @@ import android.widget.RelativeLayout; import com.pchmn.materialchips.ChipView; import com.pchmn.materialchips.ChipsInput; -import com.pchmn.materialchips.model.ChipInterface; +import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; import com.pchmn.materialchips.util.ViewUtil; import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.DetailedChipView; import com.pchmn.materialchips.views.DropdownListView; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - - -public class ChipsAdapter extends RecyclerView.Adapter { +public abstract class ChipsAdapter + extends RecyclerView.Adapter { private static final int TYPE_EDIT_TEXT = 0; private static final int TYPE_ITEM = 1; - private Context mContext; - private ChipsInput mChipsInput; - private List mChipList = new ArrayList<>(); - private String mHintLabel; - private ChipsInputEditText mEditText; + protected Context context; - private RecyclerView mRecycler; + private ChipsInput chipsInput; + private List chipList = new ArrayList<>(); - public ChipsAdapter(Context context, ChipsInput chipsInput, RecyclerView recycler) { - mContext = context; - mChipsInput = chipsInput; - mRecycler = recycler; - mHintLabel = mChipsInput.getHint(); - } + private ChipsInputEditText editText; + private String hintLabel; - public ChipsAdapter(Context mContext, ChipsInput chipsInput, ChipsInputEditText mEditText, RecyclerView mRecyclerView) { - this(mContext, chipsInput, mRecyclerView); - this.mEditText = mEditText; - } + private RecyclerView chipsRecycler; - private class ItemViewHolder extends RecyclerView.ViewHolder { + public ChipsAdapter(Context context, ChipsInput chipsInput) { + this.chipsInput = chipsInput; + this.chipsRecycler = chipsInput.getChipsRecyclerView(); + this.editText = chipsInput.getEditText(); + this.context = context; - private final ChipView chipView; - - ItemViewHolder(View view) { - super(view); - chipView = (ChipView) view; - } - - } - private class EditTextViewHolder extends RecyclerView.ViewHolder { - - private final EditText editText; - - EditTextViewHolder(View view) { - super(view); - editText = (EditText) view; - } - - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == TYPE_EDIT_TEXT) { - return new EditTextViewHolder(mEditText); - } else { - return new ItemViewHolder(mChipsInput.getChipView()); - } - - } - - @Override - public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { - // edit text - if (position == mChipList.size()) { - if (mChipList.size() == 0) { - mEditText.setHint(mHintLabel); - } - - // auto fit edit text - autofitEditText(); - } - // chip - else if (getItemCount() > 1) { - ItemViewHolder itemViewHolder = (ItemViewHolder) holder; - itemViewHolder.chipView.inflate(getItem(position)); - // handle click - handleClickOnEditText(itemViewHolder.chipView, position); - } + this.hintLabel = chipsInput.getHint(); } @Override public int getItemCount() { - return mChipList.size() + 1; + return chipList.size() + 1; } - private ChipInterface getItem(int position) { - return mChipList.get(position); + protected T getItem(int position) { + return chipList.get(position); } @Override public int getItemViewType(int position) { - if (position == mChipList.size()) { + if (position == chipList.size()) { return TYPE_EDIT_TEXT; } @@ -118,44 +68,44 @@ public class ChipsAdapter extends RecyclerView.Adapter @Override public long getItemId(int position) { - return mChipList.get(position).hashCode(); + return chipList.get(position).hashCode(); } private void autofitEditText() { // min width of edit text = 50 dp - ViewGroup.LayoutParams params = mEditText.getLayoutParams(); + ViewGroup.LayoutParams params = editText.getLayoutParams(); params.width = ViewUtil.dpToPx(50); - mEditText.setLayoutParams(params); + editText.setLayoutParams(params); // listen to change in the tree - mEditText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + editText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // get right of recycler and left of edit text - int right = mRecycler.getRight(); - int left = mEditText.getLeft(); + int right = chipsRecycler.getRight(); + int left = editText.getLeft(); // edit text will fill the space - ViewGroup.LayoutParams params = mEditText.getLayoutParams(); + ViewGroup.LayoutParams params = editText.getLayoutParams(); params.width = right - left - ViewUtil.dpToPx(8); - mEditText.setLayoutParams(params); + editText.setLayoutParams(params); // request focus - mEditText.requestFocus(); + editText.requestFocus(); // remove the listener: if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - mEditText.getViewTreeObserver().removeGlobalOnLayoutListener(this); + editText.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { - mEditText.getViewTreeObserver().removeOnGlobalLayoutListener(this); + editText.getViewTreeObserver().removeOnGlobalLayoutListener(this); } } }); } - private void handleClickOnEditText(ChipView chipView, final int position) { + public void handleClickOnEditText(ChipView chipView, final int position) { // delete chip chipView.setOnDeleteClicked(new View.OnClickListener() { @Override @@ -165,7 +115,7 @@ public class ChipsAdapter extends RecyclerView.Adapter }); // show detailed chip - if (mChipsInput.isShowChipDetailed()) { + if (chipsInput.isShowChipDetailed()) { chipView.setOnChipClicked(new View.OnClickListener() { @Override public void onClick(View v) { @@ -173,7 +123,7 @@ public class ChipsAdapter extends RecyclerView.Adapter int[] coord = new int[2]; v.getLocationInWindow(coord); - final DetailedChipView detailedChipView = mChipsInput.getDetailedChipView(getItem(position)); + final DetailedChipView detailedChipView = getDetailedChipView(getItem(position)); setDetailedChipViewPosition(detailedChipView, coord); // delete button @@ -189,10 +139,12 @@ public class ChipsAdapter extends RecyclerView.Adapter } } + public abstract DetailedChipView getDetailedChipView(T chip); + private void setDetailedChipViewPosition(DetailedChipView detailedChipView, int[] coord) { // window width - ViewGroup rootView = (ViewGroup) mRecycler.getRootView(); - int windowWidth = ViewUtil.getWindowWidth(mContext); + ViewGroup rootView = (ViewGroup) chipsRecycler.getRootView(); + int windowWidth = ViewUtil.getWindowWidth(context); // chip size RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( @@ -226,150 +178,123 @@ public class ChipsAdapter extends RecyclerView.Adapter } public void setFilterableListView(DropdownListView dropdownListView) { - if (mEditText != null) { - mEditText.setFilterableListView(dropdownListView); + if (editText != null) { + editText.setFilterableListView(dropdownListView); } } - public void addChipsProgrammatically(List chipList) { + public void addChipsProgrammatically(List chipList) { if (chipList != null) { if (chipList.size() > 0) { int chipsBeforeAdding = getItemCount(); - for (ChipInterface chip : chipList) { - mChipList.add(chip); - mChipsInput.onChipAdded(chip, getItemCount()); + for (T chip : chipList) { + this.chipList.add(chip); + chipsInput.onChipAdded(chip, getItemCount()); } // hide hint - mEditText.setHint(null); + editText.setHint(null); // reset text - mEditText.setText(null); + editText.setText(null); notifyItemRangeChanged(chipsBeforeAdding, chipList.size()); } } } - public void addChip(ChipInterface chip) { - if (!listContains(mChipList, chip)) { - mChipList.add(chip); + public void addChip(T chip) { + if (!listContains(chipList, chip)) { + chipList.add(chip); // notify listener - mChipsInput.onChipAdded(chip, mChipList.size()); + chipsInput.onChipAdded(chip, chipList.size()); // hide hint - mEditText.setHint(null); + editText.setHint(null); // reset text - mEditText.setText(null); + editText.setText(null); // refresh data - notifyItemInserted(mChipList.size()); + notifyItemInserted(chipList.size()); } } - public void removeChip(ChipInterface chip) { - int position = mChipList.indexOf(chip); - mChipList.remove(position); + public void removeChip(T chip) { + int position = chipList.indexOf(chip); + chipList.remove(position); // notify listener notifyItemRangeChanged(position, getItemCount()); - mChipsInput.onChipRemoved(chip, mChipList.size()); + chipsInput.onChipRemoved(chip, chipList.size()); // if 0 chip - if (mChipList.size() == 0) { - mEditText.setHint(mHintLabel); + if (chipList.size() == 0) { + editText.setHint(hintLabel); } // refresh data notifyDataSetChanged(); } public void removeChip(int position) { - ChipInterface chip = mChipList.get(position); + T chip = chipList.get(position); // remove contact - mChipList.remove(position); + chipList.remove(position); // notify listener - mChipsInput.onChipRemoved(chip, mChipList.size()); + chipsInput.onChipRemoved(chip, chipList.size()); // if 0 chip - if (mChipList.size() == 0) { - mEditText.setHint(mHintLabel); - } - // refresh data - notifyDataSetChanged(); - } - - public void removeChipById(Object id) { - for (Iterator iter = mChipList.listIterator(); iter.hasNext(); ) { - ChipInterface chip = iter.next(); - if (chip.getId() != null && chip.getId().equals(id)) { - // remove chip - iter.remove(); - // notify listener - mChipsInput.onChipRemoved(chip, mChipList.size()); - } - } - // if 0 chip - if (mChipList.size() == 0) { - mEditText.setHint(mHintLabel); - } - // refresh data - notifyDataSetChanged(); - } - - public void removeChipByLabel(String label) { - for (Iterator iter = mChipList.listIterator(); iter.hasNext(); ) { - ChipInterface chip = iter.next(); - if (chip.getLabel().equals(label)) { - // remove chip - iter.remove(); - // notify listener - mChipsInput.onChipRemoved(chip, mChipList.size()); - } - } - // if 0 chip - if (mChipList.size() == 0) { - mEditText.setHint(mHintLabel); - } - // refresh data - notifyDataSetChanged(); - } - - public void removeChipByInfo(String info) { - for (Iterator iter = mChipList.listIterator(); iter.hasNext(); ) { - ChipInterface chip = iter.next(); - if (chip.getInfo() != null && chip.getInfo().equals(info)) { - // remove chip - iter.remove(); - // notify listener - mChipsInput.onChipRemoved(chip, mChipList.size()); - } - } - // if 0 chip - if (mChipList.size() == 0) { - mEditText.setHint(mHintLabel); + if (chipList.size() == 0) { + editText.setHint(hintLabel); } // refresh data notifyDataSetChanged(); } public void removeLastChip() { - if (mChipList.size() > 0) { - removeChip(mChipList.get(mChipList.size() - 1)); + if (chipList.size() > 0) { + removeChip(chipList.get(chipList.size() - 1)); } } - public List getChipList() { - return mChipList; + public List getChipList() { + return chipList; } - private boolean listContains(List contactList, ChipInterface chip) { - if (mChipsInput.getChipValidator() != null) { - for (ChipInterface item : contactList) { - if (mChipsInput.getChipValidator().areEquals(item, chip)) { - return true; - } - } + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + if (viewType == TYPE_EDIT_TEXT) { + return new EditTextViewHolder(editText); } else { - for (ChipInterface item : contactList) { - if (chip.getId() != null && chip.getId().equals(item.getId())) { - return true; - } - if (chip.getLabel().equals(item.getLabel())) { + return onCreateChipViewHolder(parent, viewType); + } + } + + public abstract ViewHolder onCreateChipViewHolder(ViewGroup parent, int viewType); + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (position == chipList.size()) { + if (chipList.size() == 0) { + editText.setHint(hintLabel); + } + + autofitEditText(); + } else if (getItemCount() > 1) { + onBindChipViewHolder((VH) holder, position); + } + } + + public abstract void onBindChipViewHolder(VH holder, int position); + + protected class EditTextViewHolder extends RecyclerView.ViewHolder { + private final EditText editText; + + EditTextViewHolder(View view) { + super(view); + editText = (EditText) view; + } + } + + private boolean listContains(List contactList, T chip) { + if (chipsInput.getChipValidator() != null) { + for (T item : contactList) { + if (chipsInput.getChipValidator().areEquals(item, chip)) { return true; } } @@ -377,8 +302,4 @@ public class ChipsAdapter extends RecyclerView.Adapter return false; } - - public ChipsInputEditText getmEditText() { - return mEditText; - } } diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChip.java similarity index 92% rename from extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java rename to extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChip.java index acd740b17..9e45eee83 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/SimpleChip.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChip.java @@ -1,14 +1,14 @@ -package com.pchmn.materialchips.model; +package com.pchmn.materialchips.simple; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; +import com.pchmn.materialchips.model.ChipInterface; public class SimpleChip implements ChipInterface { - private Object id; private String label; private String info; diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChipDropdownAdapter.java similarity index 83% rename from extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java rename to extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChipDropdownAdapter.java index cdf278088..7601d4fe2 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/SimpleChipDropdownAdapter.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChipDropdownAdapter.java @@ -1,4 +1,4 @@ -package com.pchmn.materialchips.adapter; +package com.pchmn.materialchips.simple; import java.util.List; @@ -13,9 +13,7 @@ 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; +import com.pchmn.materialchips.simple.SimpleChipDropdownAdapter.ItemViewHolder; public class SimpleChipDropdownAdapter extends ChipDropdownAdapter { @@ -27,7 +25,7 @@ public class SimpleChipDropdownAdapter extends ChipDropdownAdapter { + public SimpleChipsAdapter(Context context, ChipsInput chipsInput) { + super(context, chipsInput); + } + + class ItemViewHolder extends RecyclerView.ViewHolder { + private final ChipView chipView; + + ItemViewHolder(View view) { + super(view); + chipView = (ChipView) view; + } + } + + @Override + public ItemViewHolder onCreateChipViewHolder(ViewGroup parent, int viewType) { + int padding = ViewUtil.dpToPx(4); + ChipView chipView = new ChipView.Builder(context) + // .labelColor(mChipLabelColor) + // .deletable(mChipDeletable) + // .deleteIcon(mChipDeleteIcon) + // .deleteIconColor(mChipDeleteIconColor) + .build(); + chipView.setPadding(padding, padding, padding, padding); + + return new ItemViewHolder(chipView); + } + + @Override + public void onBindChipViewHolder(ItemViewHolder holder, int position) { + holder.chipView.inflate(getItem(position)); + handleClickOnEditText(holder.chipView, position); + } + + @Override + public DetailedChipView getDetailedChipView(SimpleChip chip) { + return new DetailedChipView.Builder(context) + .chip(chip) + .build(); + } + +} diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChipsInput.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChipsInput.java new file mode 100644 index 000000000..735636ee5 --- /dev/null +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/simple/SimpleChipsInput.java @@ -0,0 +1,32 @@ +package com.pchmn.materialchips.simple; + + +import java.util.List; + +import android.content.Context; +import android.util.AttributeSet; + +import com.pchmn.materialchips.ChipsInput; + + +public class SimpleChipsInput extends ChipsInput { + public SimpleChipsInput(Context context) { + super(context); + init(); + } + + public SimpleChipsInput(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + SimpleChipsAdapter chipsAdapter = new SimpleChipsAdapter(getContext(), this); + setChipsAdapter(chipsAdapter); + } + + public void setData(List simpleChips) { + SimpleChipDropdownAdapter chipDropdownAdapter = new SimpleChipDropdownAdapter(getContext(), simpleChips); + setChipDropdownAdapter(chipDropdownAdapter); + } +} diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/MyWindowCallback.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ClickOutsideCallback.java similarity index 91% rename from extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/MyWindowCallback.java rename to extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ClickOutsideCallback.java index b6e819c6e..367e57d57 100644 --- a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/MyWindowCallback.java +++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ClickOutsideCallback.java @@ -11,10 +11,10 @@ import android.view.inputmethod.InputMethodManager; import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.DetailedChipView; -public class MyWindowCallback extends DelegateWindowCallback { +public class ClickOutsideCallback extends DelegateWindowCallback { private Activity activity; - public MyWindowCallback(Window.Callback delegateCallback, Activity activity) { + public ClickOutsideCallback(Window.Callback delegateCallback, Activity activity) { super(delegateCallback); this.activity = activity; } diff --git a/extern/MaterialChipsInput/src/main/res/values/attrs.xml b/extern/MaterialChipsInput/src/main/res/values/attrs.xml index 7c49f83a0..189c0eec7 100644 --- a/extern/MaterialChipsInput/src/main/res/values/attrs.xml +++ b/extern/MaterialChipsInput/src/main/res/values/attrs.xml @@ -17,13 +17,7 @@ - - - - - -