generify ChipsInput, extract SimpleChipsInput

This commit is contained in:
Vincent Breitmoser
2018-07-03 20:12:09 +02:00
parent 355a4eaa0f
commit 93e8c74ec6
11 changed files with 376 additions and 451 deletions

View File

@@ -34,31 +34,29 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ViewAnimator; import android.widget.ViewAnimator;
import com.pchmn.materialchips.ChipsInput; import com.pchmn.materialchips.ChipsInput.SimpleChipsListener;
import com.pchmn.materialchips.ChipsInput.ChipsListener;
import com.pchmn.materialchips.adapter.SimpleChipDropdownAdapter;
import com.pchmn.materialchips.model.ChipInterface; 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.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; 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.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
import timber.log.Timber;
public class EncryptModeAsymmetricFragment extends EncryptModeFragment { public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
KeyRepository keyRepository; KeyRepository keyRepository;
private KeySpinner mSignKeySpinner; 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_SINGATURE_KEY_ID = "signature_key_id";
public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; 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); mSignKeySpinner.setShowNone(R.string.cert_none);
final ViewAnimator vEncryptionIcon = view.findViewById(R.id.result_encryption_icon); final ViewAnimator vEncryptionIcon = view.findViewById(R.id.result_encryption_icon);
mEncryptKeyView.addChipsListener(new ChipsListener() { mEncryptKeyView.addChipsListener(new SimpleChipsListener<SimpleChip>() {
@Override @Override
public void onChipAdded(ChipInterface chipInterface, int newSize) { public void onChipAdded(SimpleChip chipInterface, int newSize) {
if (vEncryptionIcon.getDisplayedChild() != 1) { if (vEncryptionIcon.getDisplayedChild() != 1) {
vEncryptionIcon.setDisplayedChild(1); vEncryptionIcon.setDisplayedChild(1);
} }
} }
@Override @Override
public void onChipRemoved(ChipInterface chipInterface, int newSize) { public void onChipRemoved(SimpleChip chipInterface, int newSize) {
int child = newSize == 0 ? 0 : 1; int child = newSize == 0 ? 0 : 1;
if (vEncryptionIcon.getDisplayedChild() != child) { if (vEncryptionIcon.getDisplayedChild() != child) {
vEncryptionIcon.setDisplayedChild(child); vEncryptionIcon.setDisplayedChild(child);
} }
} }
@Override
public void onTextChanged(CharSequence charSequence) {
}
@Override
public void onActionDone(CharSequence charSequence) {
}
}); });
return view; return view;
@@ -141,7 +129,13 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class); EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class);
viewModel.getSignKeyLiveData(requireContext()).observe(this, mSignKeySpinner::setData); viewModel.getSignKeyLiveData(requireContext()).observe(this, mSignKeySpinner::setData);
viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, this::onLoadEncryptRecipients); viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, (keyUnifiedData) -> {
ArrayList<SimpleChip> 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 // preselect keys given, from state or arguments
if (savedInstanceState == null) { if (savedInstanceState == null) {
@@ -154,14 +148,9 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
} }
} }
private void onLoadEncryptRecipients(List<SimpleChip> keyInfoChips) {
SimpleChipDropdownAdapter chipDropdownAdapter = new SimpleChipDropdownAdapter(requireContext(), keyInfoChips);
mEncryptKeyView.setChipDropdownAdapter(chipDropdownAdapter);
}
public static class EncryptModeViewModel extends ViewModel { public static class EncryptModeViewModel extends ViewModel {
private LiveData<List<UnifiedKeyInfo>> signKeyLiveData; private LiveData<List<UnifiedKeyInfo>> signKeyLiveData;
private LiveData<List<SimpleChip>> encryptRecipientLiveData; private LiveData<List<EncryptRecipientChip>> encryptRecipientLiveData;
LiveData<List<UnifiedKeyInfo>> getSignKeyLiveData(Context context) { LiveData<List<UnifiedKeyInfo>> getSignKeyLiveData(Context context) {
if (signKeyLiveData == null) { if (signKeyLiveData == null) {
@@ -173,14 +162,15 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
return signKeyLiveData; return signKeyLiveData;
} }
LiveData<List<SimpleChip>> getEncryptRecipientLiveData(Context context) { LiveData<List<EncryptRecipientChip>> getEncryptRecipientLiveData(Context context) {
if (encryptRecipientLiveData == null) { if (encryptRecipientLiveData == null) {
encryptRecipientLiveData = new GenericLiveData<>(context, () -> { encryptRecipientLiveData = new GenericLiveData<>(context, () -> {
KeyRepository keyRepository = KeyRepository.create(context); KeyRepository keyRepository = KeyRepository.create(context);
List<UnifiedKeyInfo> keyInfos = keyRepository.getAllUnifiedKeyInfo(); List<UnifiedKeyInfo> keyInfos = keyRepository.getAllUnifiedKeyInfo();
ArrayList<SimpleChip> result = new ArrayList<>(); ArrayList<EncryptRecipientChip> result = new ArrayList<>();
for (UnifiedKeyInfo keyInfo : keyInfos) { 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; return result;
}); });
@@ -205,22 +195,16 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
if (encryptionKeyIds != null) { if (encryptionKeyIds != null) {
for (long preselectedId : encryptionKeyIds) { for (long preselectedId : encryptionKeyIds) {
try { UnifiedKeyInfo keyInfo = keyRepository.getUnifiedKeyInfo(preselectedId);
CanonicalizedPublicKeyRing ring = EncryptRecipientChip recipientChip = EncryptRecipientChipsInput.chipFromUnifiedKeyInfo(keyInfo);
keyRepository.getCanonicalizedPublicKeyRing(preselectedId); // mEncryptKeyView.addChip(recipientChip);
SimpleChip infooo = new SimpleChip(ring.getMasterKeyId(), ring.getPrimaryUserIdWithFallback(), "infooo", null); // EncryptRecipientChip infooo =
mEncryptKeyView.addChip(infooo); // new EncryptRecipientChip(ring.getMasterKeyId(), ring.getPrimaryUserIdWithFallback(), "infooo", null);
} catch (NotFoundException e) { // mEncryptKeyView.addChip(infooo);
Timber.e(e, "key not found for encryption!");
Notify.create(getActivity(), getString(R.string.error_preselect_encrypt_key,
KeyFormattingUtils.beautifyKeyId(preselectedId)),
Style.ERROR).show();
}
} }
// This is to work-around a rendering bug in TokenCompleteTextView // This is to work-around a rendering bug in TokenCompleteTextView
mEncryptKeyView.requestFocus(); mEncryptKeyView.requestFocus();
} }
} }
@Override @Override

View File

@@ -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<EncryptRecipientChip> {
public EncryptRecipientChipsInput(Context context) {
super(context);
init();
}
public EncryptRecipientChipsInput(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// ChipsAdapter<EncryptRecipientChip> chipsAdapter = new SimpleChipsAdapter(getContext(), this);
// setChipsAdapter(chipsAdapter);
}
public void setData(List<EncryptRecipientChip> 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);
}
}

View File

@@ -38,7 +38,7 @@
</ViewAnimator> </ViewAnimator>
<com.pchmn.materialchips.ChipsInput <com.pchmn.materialchips.simple.SimpleChipsInput
android:id="@+id/recipient_list" android:id="@+id/recipient_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -47,7 +47,6 @@
android:paddingRight="8dp" android:paddingRight="8dp"
app:hint="@string/label_to" app:hint="@string/label_to"
app:maxRows="2" app:maxRows="2"
app:chip_detailed_backgroundColor="@color/colorChipViewBackground"
/> />
</LinearLayout> </LinearLayout>

View File

@@ -8,8 +8,6 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.TypedArray; 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;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.Editable; import android.text.Editable;
@@ -28,44 +26,34 @@ import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager;
import com.pchmn.materialchips.RecyclerItemClickListener.OnItemClickListener; import com.pchmn.materialchips.RecyclerItemClickListener.OnItemClickListener;
import com.pchmn.materialchips.adapter.ChipsAdapter; import com.pchmn.materialchips.adapter.ChipsAdapter;
import com.pchmn.materialchips.adapter.FilterableAdapter; import com.pchmn.materialchips.adapter.FilterableAdapter;
import com.pchmn.materialchips.model.ChipInterface; import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem;
import com.pchmn.materialchips.model.SimpleChip;
import com.pchmn.materialchips.util.ActivityUtil; 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.util.ViewUtil;
import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.ChipsInputEditText;
import com.pchmn.materialchips.views.DetailedChipView;
import com.pchmn.materialchips.views.DropdownListView; import com.pchmn.materialchips.views.DropdownListView;
import com.pchmn.materialchips.views.ScrollViewMaxHeight; import com.pchmn.materialchips.views.ScrollViewMaxHeight;
public class ChipsInput extends ScrollViewMaxHeight { public abstract class ChipsInput<T extends FilterableItem> extends ScrollViewMaxHeight {
// context
private Context mContext; private Context mContext;
private ChipsAdapter mChipsAdapter;
// attributes // attributes
private static final int NONE = -1;
private String mHint; private String mHint;
private ColorStateList mHintColor; private ColorStateList mHintColor;
private ColorStateList mTextColor; private ColorStateList mTextColor;
private int mMaxRows = 2; 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 boolean mShowChipDetailed = true;
private ColorStateList mChipDetailedTextColor;
private ColorStateList mChipDetailedDeleteIconColor; private List<ChipsListener<T>> mChipsListenerList = new ArrayList<>();
private ColorStateList mChipDetailedBackgroundColor; private ChipValidator<T> mChipValidator;
// chips listener
private List<ChipsListener> mChipsListenerList = new ArrayList<>(); private ChipsAdapter<T, ?> chipsAdapter;
// chip list private RecyclerView chipsRecyclerView;
private DropdownListView mDropdownListView; private ChipsInputEditText chipsInputEditText;
// chip validator
private ChipValidator mChipValidator; private ChipDropdownAdapter<T, ?> filterableAdapter;
private ViewGroup filterableListLayout; private ViewGroup filterableListLayout;
private ChipsInputEditText mEditText; private DropdownListView mDropdownListView;
private ChipDropdownAdapter<? extends ChipInterface, ?> filterableAdapter;
public ChipsInput(Context context) { public ChipsInput(Context context) {
super(context); super(context);
@@ -88,7 +76,7 @@ public class ChipsInput extends ScrollViewMaxHeight {
// inflate filterableListLayout // inflate filterableListLayout
View rootView = inflate(getContext(), R.layout.chips_input, this); 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(); initEditText();
@@ -107,91 +95,82 @@ public class ChipsInput extends ScrollViewMaxHeight {
mMaxRows = a.getInteger(R.styleable.ChipsInput_maxRows, 2); mMaxRows = a.getInteger(R.styleable.ChipsInput_maxRows, 2);
setMaxHeight(ViewUtil.dpToPx((40 * mMaxRows) + 8)); setMaxHeight(ViewUtil.dpToPx((40 * mMaxRows) + 8));
//setVerticalScrollBarEnabled(true); //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); mShowChipDetailed = a.getBoolean(R.styleable.ChipsInput_showChipDetailed, true);
// chip detailed text color // 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 { } finally {
a.recycle(); a.recycle();
} }
} }
// adapter
mChipsAdapter = new ChipsAdapter(mContext, this, mEditText, recyclerView);
ChipsLayoutManager chipsLayoutManager = ChipsLayoutManager.newBuilder(mContext) ChipsLayoutManager chipsLayoutManager = ChipsLayoutManager.newBuilder(mContext)
.setOrientation(ChipsLayoutManager.HORIZONTAL) .setOrientation(ChipsLayoutManager.HORIZONTAL)
.build(); .build();
recyclerView.setLayoutManager(chipsLayoutManager); chipsRecyclerView.setLayoutManager(chipsLayoutManager);
recyclerView.setNestedScrollingEnabled(false); chipsRecyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(mChipsAdapter);
// set window callback setupClickOutsideCallback();
// will hide DetailedOpenView and hide keyboard on touch outside }
public void setChipsAdapter(ChipsAdapter<T, ?> chipsAdapter) {
this.chipsAdapter = chipsAdapter;
chipsRecyclerView.setAdapter(chipsAdapter);
}
private void setupClickOutsideCallback() {
Activity activity = ActivityUtil.scanForActivity(mContext); Activity activity = ActivityUtil.scanForActivity(mContext);
if (activity == null) if (activity == null) {
throw new ClassCastException("android.view.Context cannot be cast to android.app.Activity"); throw new ClassCastException("android.view.Context cannot be cast to android.app.Activity");
}
android.view.Window.Callback mCallBack = (activity).getWindow().getCallback(); android.view.Window.Callback originalWindowCallback = (activity).getWindow().getCallback();
activity.getWindow().setCallback(new MyWindowCallback(mCallBack, activity)); activity.getWindow().setCallback(new ClickOutsideCallback(originalWindowCallback, activity));
} }
private void initEditText() { private void initEditText() {
mEditText = new ChipsInputEditText(mContext); chipsInputEditText = new ChipsInputEditText(mContext);
if (mHintColor != null) if (mHintColor != null)
mEditText.setHintTextColor(mHintColor); chipsInputEditText.setHintTextColor(mHintColor);
if (mTextColor != null) 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,
ViewGroup.LayoutParams.WRAP_CONTENT)); ViewGroup.LayoutParams.WRAP_CONTENT));
mEditText.setHint(mHint); chipsInputEditText.setHint(mHint);
mEditText.setBackgroundResource(android.R.color.transparent); chipsInputEditText.setBackgroundResource(android.R.color.transparent);
// prevent fullscreen on landscape // prevent fullscreen on landscape
mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); chipsInputEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
mEditText.setPrivateImeOptions("nm"); chipsInputEditText.setPrivateImeOptions("nm");
// no suggestion // 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 // handle back space
mEditText.setOnKeyListener(new View.OnKeyListener() { chipsInputEditText.setOnKeyListener(new View.OnKeyListener() {
@Override @Override
public boolean onKey(View v, int keyCode, KeyEvent event) { public boolean onKey(View v, int keyCode, KeyEvent event) {
// backspace // backspace
if (event.getAction() == KeyEvent.ACTION_DOWN if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getKeyCode() == KeyEvent.KEYCODE_DEL) { && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
// remove last chip // remove last chip
if (mEditText.getText().toString().length() == 0) if (chipsInputEditText.getText().toString().length() == 0)
mChipsAdapter.removeLastChip(); chipsAdapter.removeLastChip();
} }
return false; return false;
} }
}); });
mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { chipsInputEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override @Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((actionId == EditorInfo.IME_ACTION_DONE) || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { 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; return false;
} }
}); });
// text changed // text changed
mEditText.addTextChangedListener(new TextWatcher() { chipsInputEditText.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -208,80 +187,28 @@ public class ChipsInput extends ScrollViewMaxHeight {
}); });
} }
public void addChips(List<ChipInterface> chipList) { public void addChip(T chip) {
mChipsAdapter.addChipsProgrammatically(chipList); chipsAdapter.addChip(chip);
}
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 ChipsInputEditText getEditText() { public ChipsInputEditText getEditText() {
return mChipsAdapter.getmEditText(); return chipsInputEditText;
} }
public DetailedChipView getDetailedChipView(ChipInterface chip) { public void addChipsListener(ChipsListener<T> chipsListener) {
return new DetailedChipView.Builder(mContext)
.chip(chip)
.textColor(mChipDetailedTextColor)
.backgroundColor(mChipDetailedBackgroundColor)
.deleteIconColor(mChipDetailedDeleteIconColor)
.build();
}
public void addChipsListener(ChipsListener chipsListener) {
mChipsListenerList.add(chipsListener); mChipsListenerList.add(chipsListener);
} }
public void onChipAdded(ChipInterface chip, int size) { public void onChipAdded(T chip, int size) {
for (ChipsListener chipsListener : mChipsListenerList) { filterableAdapter.hideItem(chip);
for (ChipsListener<T> chipsListener : mChipsListenerList) {
chipsListener.onChipAdded(chip, size); chipsListener.onChipAdded(chip, size);
} }
} }
public void onChipRemoved(ChipInterface chip, int size) { public void onChipRemoved(T chip, int size) {
for (ChipsListener chipsListener : mChipsListenerList) { filterableAdapter.unhideItem(chip);
for (ChipsListener<T> chipsListener : mChipsListenerList) {
chipsListener.onChipRemoved(chip, size); chipsListener.onChipRemoved(chip, size);
} }
} }
@@ -290,6 +217,9 @@ public class ChipsInput extends ScrollViewMaxHeight {
for (ChipsListener chipsListener : mChipsListenerList) { for (ChipsListener chipsListener : mChipsListenerList) {
chipsListener.onTextChanged(text); chipsListener.onTextChanged(text);
} }
mDropdownListView.getRecyclerView().scrollToPosition(0);
// show filterable list // show filterable list
if (mDropdownListView != null) { if (mDropdownListView != null) {
if (text.length() > 0) { if (text.length() > 0) {
@@ -317,10 +247,11 @@ public class ChipsInput extends ScrollViewMaxHeight {
for (ChipsListener chipsListener : mChipsListenerList) { for (ChipsListener chipsListener : mChipsListenerList) {
chipsListener.onActionDone(text); chipsListener.onActionDone(text);
} }
mDropdownListView.getRecyclerView().scrollToPosition(0);
} }
public List<? extends ChipInterface> getSelectedChipList() { public List<T> getSelectedChipList() {
return mChipsAdapter.getChipList(); return chipsAdapter.getChipList();
} }
public String getHint() { public String getHint() {
@@ -344,26 +275,6 @@ public class ChipsInput extends ScrollViewMaxHeight {
return this; 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) { public ChipsInput setShowChipDetailed(boolean mShowChipDetailed) {
this.mShowChipDetailed = mShowChipDetailed; this.mShowChipDetailed = mShowChipDetailed;
return this; return this;
@@ -373,30 +284,22 @@ public class ChipsInput extends ScrollViewMaxHeight {
return mShowChipDetailed; 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) { public void setFilterableListLayout(ViewGroup layout) {
this.filterableListLayout = layout; this.filterableListLayout = layout;
} }
public abstract static class ChipDropdownAdapter<T extends ChipInterface, VH extends ViewHolder> public RecyclerView getChipsRecyclerView() {
return chipsRecyclerView;
}
public abstract static class ChipDropdownAdapter<T extends FilterableItem, VH extends ViewHolder>
extends FilterableAdapter<T, VH> { extends FilterableAdapter<T, VH> {
public ChipDropdownAdapter(List<? extends T> itemList) { public ChipDropdownAdapter(List<? extends T> itemList) {
super(itemList); super(itemList);
} }
} }
public <T extends ChipInterface> void setChipDropdownAdapter(final ChipDropdownAdapter<T, ?> filterableAdapter) { public void setChipDropdownAdapter(final ChipDropdownAdapter<T, ?> filterableAdapter) {
this.filterableAdapter = filterableAdapter; this.filterableAdapter = filterableAdapter;
if (filterableListLayout != null) { if (filterableListLayout != null) {
mDropdownListView = new DropdownListView(mContext, filterableListLayout); mDropdownListView = new DropdownListView(mContext, filterableListLayout);
@@ -404,57 +307,39 @@ public class ChipsInput extends ScrollViewMaxHeight {
mDropdownListView = new DropdownListView(mContext, this); mDropdownListView = new DropdownListView(mContext, this);
} }
mDropdownListView.build(filterableAdapter); mDropdownListView.build(filterableAdapter);
mChipsAdapter.setFilterableListView(mDropdownListView); chipsAdapter.setFilterableListView(mDropdownListView);
mDropdownListView.getRecyclerView().addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new OnItemClickListener() { mDropdownListView.getRecyclerView().addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new OnItemClickListener() {
@Override @Override
public void onItemClick(View view, int position) { public void onItemClick(View view, int position) {
ChipInterface item = filterableAdapter.getItem(position); T item = filterableAdapter.getItem(position);
addChip(item); 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<T> getChipValidator() {
return mChipValidator; return mChipValidator;
} }
public void setChipValidator(ChipValidator mChipValidator) { public void setChipValidator(ChipValidator<T> mChipValidator) {
this.mChipValidator = mChipValidator; this.mChipValidator = mChipValidator;
} }
public interface ChipsListener { public interface ChipsListener<T extends FilterableItem> {
void onChipAdded(ChipInterface chip, int newSize); void onChipAdded(T chip, int newSize);
void onChipRemoved(T chip, int newSize);
void onChipRemoved(ChipInterface chip, int newSize);
void onTextChanged(CharSequence text); void onTextChanged(CharSequence text);
void onActionDone(CharSequence text); void onActionDone(CharSequence text);
} }
public interface ChipValidator { public static abstract class SimpleChipsListener<T extends FilterableItem> implements ChipsListener<T> {
boolean areEquals(ChipInterface chip1, ChipInterface chip2); 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<T extends FilterableItem> {
boolean areEquals(T chip1, T chip2);
} }
} }

View File

@@ -1,8 +1,14 @@
package com.pchmn.materialchips.adapter; package com.pchmn.materialchips.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
@@ -11,105 +17,49 @@ import android.widget.RelativeLayout;
import com.pchmn.materialchips.ChipView; import com.pchmn.materialchips.ChipView;
import com.pchmn.materialchips.ChipsInput; 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.util.ViewUtil;
import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.ChipsInputEditText;
import com.pchmn.materialchips.views.DetailedChipView; import com.pchmn.materialchips.views.DetailedChipView;
import com.pchmn.materialchips.views.DropdownListView; import com.pchmn.materialchips.views.DropdownListView;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public abstract class ChipsAdapter<T extends FilterableItem, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_EDIT_TEXT = 0; private static final int TYPE_EDIT_TEXT = 0;
private static final int TYPE_ITEM = 1; private static final int TYPE_ITEM = 1;
private Context mContext;
private ChipsInput mChipsInput;
private List<ChipInterface> mChipList = new ArrayList<>();
private String mHintLabel;
private ChipsInputEditText mEditText; protected Context context;
private RecyclerView mRecycler; private ChipsInput<T> chipsInput;
private List<T> chipList = new ArrayList<>();
public ChipsAdapter(Context context, ChipsInput chipsInput, RecyclerView recycler) { private ChipsInputEditText editText;
mContext = context; private String hintLabel;
mChipsInput = chipsInput;
mRecycler = recycler;
mHintLabel = mChipsInput.getHint();
}
public ChipsAdapter(Context mContext, ChipsInput chipsInput, ChipsInputEditText mEditText, RecyclerView mRecyclerView) { private RecyclerView chipsRecycler;
this(mContext, chipsInput, mRecyclerView);
this.mEditText = mEditText;
}
private class ItemViewHolder extends RecyclerView.ViewHolder { public ChipsAdapter(Context context, ChipsInput<T> chipsInput) {
this.chipsInput = chipsInput;
this.chipsRecycler = chipsInput.getChipsRecyclerView();
this.editText = chipsInput.getEditText();
this.context = context;
private final ChipView chipView; this.hintLabel = chipsInput.getHint();
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);
}
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return mChipList.size() + 1; return chipList.size() + 1;
} }
private ChipInterface getItem(int position) { protected T getItem(int position) {
return mChipList.get(position); return chipList.get(position);
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (position == mChipList.size()) { if (position == chipList.size()) {
return TYPE_EDIT_TEXT; return TYPE_EDIT_TEXT;
} }
@@ -118,44 +68,44 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
return mChipList.get(position).hashCode(); return chipList.get(position).hashCode();
} }
private void autofitEditText() { private void autofitEditText() {
// min width of edit text = 50 dp // min width of edit text = 50 dp
ViewGroup.LayoutParams params = mEditText.getLayoutParams(); ViewGroup.LayoutParams params = editText.getLayoutParams();
params.width = ViewUtil.dpToPx(50); params.width = ViewUtil.dpToPx(50);
mEditText.setLayoutParams(params); editText.setLayoutParams(params);
// listen to change in the tree // listen to change in the tree
mEditText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { editText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override @Override
public void onGlobalLayout() { public void onGlobalLayout() {
// get right of recycler and left of edit text // get right of recycler and left of edit text
int right = mRecycler.getRight(); int right = chipsRecycler.getRight();
int left = mEditText.getLeft(); int left = editText.getLeft();
// edit text will fill the space // edit text will fill the space
ViewGroup.LayoutParams params = mEditText.getLayoutParams(); ViewGroup.LayoutParams params = editText.getLayoutParams();
params.width = right - left - ViewUtil.dpToPx(8); params.width = right - left - ViewUtil.dpToPx(8);
mEditText.setLayoutParams(params); editText.setLayoutParams(params);
// request focus // request focus
mEditText.requestFocus(); editText.requestFocus();
// remove the listener: // remove the listener:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mEditText.getViewTreeObserver().removeGlobalOnLayoutListener(this); editText.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else { } 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 // delete chip
chipView.setOnDeleteClicked(new View.OnClickListener() { chipView.setOnDeleteClicked(new View.OnClickListener() {
@Override @Override
@@ -165,7 +115,7 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}); });
// show detailed chip // show detailed chip
if (mChipsInput.isShowChipDetailed()) { if (chipsInput.isShowChipDetailed()) {
chipView.setOnChipClicked(new View.OnClickListener() { chipView.setOnChipClicked(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -173,7 +123,7 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
int[] coord = new int[2]; int[] coord = new int[2];
v.getLocationInWindow(coord); v.getLocationInWindow(coord);
final DetailedChipView detailedChipView = mChipsInput.getDetailedChipView(getItem(position)); final DetailedChipView detailedChipView = getDetailedChipView(getItem(position));
setDetailedChipViewPosition(detailedChipView, coord); setDetailedChipViewPosition(detailedChipView, coord);
// delete button // delete button
@@ -189,10 +139,12 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
} }
} }
public abstract DetailedChipView getDetailedChipView(T chip);
private void setDetailedChipViewPosition(DetailedChipView detailedChipView, int[] coord) { private void setDetailedChipViewPosition(DetailedChipView detailedChipView, int[] coord) {
// window width // window width
ViewGroup rootView = (ViewGroup) mRecycler.getRootView(); ViewGroup rootView = (ViewGroup) chipsRecycler.getRootView();
int windowWidth = ViewUtil.getWindowWidth(mContext); int windowWidth = ViewUtil.getWindowWidth(context);
// chip size // chip size
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
@@ -226,150 +178,123 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
} }
public void setFilterableListView(DropdownListView dropdownListView) { public void setFilterableListView(DropdownListView dropdownListView) {
if (mEditText != null) { if (editText != null) {
mEditText.setFilterableListView(dropdownListView); editText.setFilterableListView(dropdownListView);
} }
} }
public void addChipsProgrammatically(List<ChipInterface> chipList) { public void addChipsProgrammatically(List<T> chipList) {
if (chipList != null) { if (chipList != null) {
if (chipList.size() > 0) { if (chipList.size() > 0) {
int chipsBeforeAdding = getItemCount(); int chipsBeforeAdding = getItemCount();
for (ChipInterface chip : chipList) { for (T chip : chipList) {
mChipList.add(chip); this.chipList.add(chip);
mChipsInput.onChipAdded(chip, getItemCount()); chipsInput.onChipAdded(chip, getItemCount());
} }
// hide hint // hide hint
mEditText.setHint(null); editText.setHint(null);
// reset text // reset text
mEditText.setText(null); editText.setText(null);
notifyItemRangeChanged(chipsBeforeAdding, chipList.size()); notifyItemRangeChanged(chipsBeforeAdding, chipList.size());
} }
} }
} }
public void addChip(ChipInterface chip) { public void addChip(T chip) {
if (!listContains(mChipList, chip)) { if (!listContains(chipList, chip)) {
mChipList.add(chip); chipList.add(chip);
// notify listener // notify listener
mChipsInput.onChipAdded(chip, mChipList.size()); chipsInput.onChipAdded(chip, chipList.size());
// hide hint // hide hint
mEditText.setHint(null); editText.setHint(null);
// reset text // reset text
mEditText.setText(null); editText.setText(null);
// refresh data // refresh data
notifyItemInserted(mChipList.size()); notifyItemInserted(chipList.size());
} }
} }
public void removeChip(ChipInterface chip) { public void removeChip(T chip) {
int position = mChipList.indexOf(chip); int position = chipList.indexOf(chip);
mChipList.remove(position); chipList.remove(position);
// notify listener // notify listener
notifyItemRangeChanged(position, getItemCount()); notifyItemRangeChanged(position, getItemCount());
mChipsInput.onChipRemoved(chip, mChipList.size()); chipsInput.onChipRemoved(chip, chipList.size());
// if 0 chip // if 0 chip
if (mChipList.size() == 0) { if (chipList.size() == 0) {
mEditText.setHint(mHintLabel); editText.setHint(hintLabel);
} }
// refresh data // refresh data
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void removeChip(int position) { public void removeChip(int position) {
ChipInterface chip = mChipList.get(position); T chip = chipList.get(position);
// remove contact // remove contact
mChipList.remove(position); chipList.remove(position);
// notify listener // notify listener
mChipsInput.onChipRemoved(chip, mChipList.size()); chipsInput.onChipRemoved(chip, chipList.size());
// if 0 chip // if 0 chip
if (mChipList.size() == 0) { if (chipList.size() == 0) {
mEditText.setHint(mHintLabel); editText.setHint(hintLabel);
}
// refresh data
notifyDataSetChanged();
}
public void removeChipById(Object id) {
for (Iterator<ChipInterface> 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<ChipInterface> 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<ChipInterface> 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);
} }
// refresh data // refresh data
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void removeLastChip() { public void removeLastChip() {
if (mChipList.size() > 0) { if (chipList.size() > 0) {
removeChip(mChipList.get(mChipList.size() - 1)); removeChip(chipList.get(chipList.size() - 1));
} }
} }
public List<ChipInterface> getChipList() { public List<T> getChipList() {
return mChipList; return chipList;
} }
private boolean listContains(List<ChipInterface> contactList, ChipInterface chip) {
if (mChipsInput.getChipValidator() != null) { @NonNull
for (ChipInterface item : contactList) { @Override
if (mChipsInput.getChipValidator().areEquals(item, chip)) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return true; if (viewType == TYPE_EDIT_TEXT) {
} return new EditTextViewHolder(editText);
}
} else { } else {
for (ChipInterface item : contactList) { return onCreateChipViewHolder(parent, viewType);
if (chip.getId() != null && chip.getId().equals(item.getId())) { }
return true; }
}
if (chip.getLabel().equals(item.getLabel())) { 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<T> contactList, T chip) {
if (chipsInput.getChipValidator() != null) {
for (T item : contactList) {
if (chipsInput.getChipValidator().areEquals(item, chip)) {
return true; return true;
} }
} }
@@ -377,8 +302,4 @@ public class ChipsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
return false; return false;
} }
public ChipsInputEditText getmEditText() {
return mEditText;
}
} }

View File

@@ -1,14 +1,14 @@
package com.pchmn.materialchips.model; package com.pchmn.materialchips.simple;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem; import com.pchmn.materialchips.adapter.FilterableAdapter.FilterableItem;
import com.pchmn.materialchips.model.ChipInterface;
public class SimpleChip implements ChipInterface { public class SimpleChip implements ChipInterface {
private Object id; private Object id;
private String label; private String label;
private String info; private String info;

View File

@@ -1,4 +1,4 @@
package com.pchmn.materialchips.adapter; package com.pchmn.materialchips.simple;
import java.util.List; import java.util.List;
@@ -13,9 +13,7 @@ import android.widget.TextView;
import com.pchmn.materialchips.ChipsInput.ChipDropdownAdapter; import com.pchmn.materialchips.ChipsInput.ChipDropdownAdapter;
import com.pchmn.materialchips.R; import com.pchmn.materialchips.R;
import com.pchmn.materialchips.adapter.SimpleChipDropdownAdapter.ItemViewHolder; import com.pchmn.materialchips.simple.SimpleChipDropdownAdapter.ItemViewHolder;
import com.pchmn.materialchips.model.ChipInterface;
import com.pchmn.materialchips.model.SimpleChip;
public class SimpleChipDropdownAdapter extends ChipDropdownAdapter<SimpleChip, ItemViewHolder> { public class SimpleChipDropdownAdapter extends ChipDropdownAdapter<SimpleChip, ItemViewHolder> {
@@ -27,7 +25,7 @@ public class SimpleChipDropdownAdapter extends ChipDropdownAdapter<SimpleChip, I
layoutInflater = LayoutInflater.from(context); layoutInflater = LayoutInflater.from(context);
} }
class ItemViewHolder extends RecyclerView.ViewHolder { static class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView mLabel; private TextView mLabel;
private TextView mInfo; private TextView mInfo;
@@ -47,7 +45,7 @@ public class SimpleChipDropdownAdapter extends ChipDropdownAdapter<SimpleChip, I
@Override @Override
public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) { public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
ChipInterface chip = getItem(position); SimpleChip chip = getItem(position);
holder.mLabel.setText(chip.getLabel()); holder.mLabel.setText(chip.getLabel());
if (chip.getInfo() != null) { if (chip.getInfo() != null) {
@@ -57,4 +55,5 @@ public class SimpleChipDropdownAdapter extends ChipDropdownAdapter<SimpleChip, I
holder.mInfo.setVisibility(View.GONE); holder.mInfo.setVisibility(View.GONE);
} }
} }
} }

View File

@@ -0,0 +1,58 @@
package com.pchmn.materialchips.simple;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import com.pchmn.materialchips.ChipView;
import com.pchmn.materialchips.ChipsInput;
import com.pchmn.materialchips.adapter.ChipsAdapter;
import com.pchmn.materialchips.simple.SimpleChipsAdapter.ItemViewHolder;
import com.pchmn.materialchips.util.ViewUtil;
import com.pchmn.materialchips.views.DetailedChipView;
public class SimpleChipsAdapter extends ChipsAdapter<SimpleChip, ItemViewHolder> {
public SimpleChipsAdapter(Context context, ChipsInput<SimpleChip> 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();
}
}

View File

@@ -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<SimpleChip> {
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<SimpleChip> simpleChips) {
SimpleChipDropdownAdapter chipDropdownAdapter = new SimpleChipDropdownAdapter(getContext(), simpleChips);
setChipDropdownAdapter(chipDropdownAdapter);
}
}

View File

@@ -11,10 +11,10 @@ import android.view.inputmethod.InputMethodManager;
import com.pchmn.materialchips.views.ChipsInputEditText; import com.pchmn.materialchips.views.ChipsInputEditText;
import com.pchmn.materialchips.views.DetailedChipView; import com.pchmn.materialchips.views.DetailedChipView;
public class MyWindowCallback extends DelegateWindowCallback { public class ClickOutsideCallback extends DelegateWindowCallback {
private Activity activity; private Activity activity;
public MyWindowCallback(Window.Callback delegateCallback, Activity activity) { public ClickOutsideCallback(Window.Callback delegateCallback, Activity activity) {
super(delegateCallback); super(delegateCallback);
this.activity = activity; this.activity = activity;
} }

View File

@@ -17,13 +17,7 @@
<attr name="maxRows" format="integer" /> <attr name="maxRows" format="integer" />
<attr name="chip_labelColor" format="color" /> <attr name="chip_labelColor" format="color" />
<attr name="chip_deletable" format="boolean" /> <attr name="chip_deletable" format="boolean" />
<attr name="chip_deleteIcon" format="reference" />
<attr name="chip_deleteIconColor" format="color" />
<attr name="chip_backgroundColor" format="color" />
<attr name="showChipDetailed" format="boolean" /> <attr name="showChipDetailed" format="boolean" />
<attr name="chip_detailed_textColor" format="color" />
<attr name="chip_detailed_backgroundColor" format="color" />
<attr name="chip_detailed_deleteIconColor" format="color" />
</declare-styleable> </declare-styleable>
<declare-styleable name="ScrollViewMaxHeight"> <declare-styleable name="ScrollViewMaxHeight">