diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle
index 94d9cffbf..36d4afdb9 100644
--- a/OpenKeychain/build.gradle
+++ b/OpenKeychain/build.gradle
@@ -28,7 +28,6 @@ dependencies {
// UI
compile 'org.sufficientlysecure:html-textview:3.1'
- compile 'com.github.sikeeoh:MaterialChipsInput:1.1.1'
compile 'com.jpardogo.materialtabstrip:library:1.1.1'
compile 'com.getbase:floatingactionbutton:1.10.1'
compile 'com.nispok:snackbar:2.11.0'
@@ -61,6 +60,7 @@ dependencies {
implementation project(':extern:minidns')
implementation project(':KeybaseLib')
implementation project(':safeslinger-exchange')
+ implementation project(':extern:MaterialChipsInput')
implementation "android.arch.work:work-runtime:1.0.0-alpha02"
diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
index b191c1b80..1ff410f43 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml
@@ -46,7 +46,6 @@
android:paddingLeft="8dp"
android:paddingRight="8dp"
app:hint="@string/label_to"
- app:chip_hasAvatarIcon="false"
app:maxRows="2"
app:chip_detailed_backgroundColor="@color/colorChipViewBackground"
/>
diff --git a/extern/MaterialChipsInput/.gitignore b/extern/MaterialChipsInput/.gitignore
new file mode 100644
index 000000000..09b993d06
--- /dev/null
+++ b/extern/MaterialChipsInput/.gitignore
@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/local.properties
+/.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/extern/MaterialChipsInput/build.gradle b/extern/MaterialChipsInput/build.gradle
new file mode 100644
index 000000000..d6a67320a
--- /dev/null
+++ b/extern/MaterialChipsInput/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 27
+ buildToolsVersion "27.0.3"
+
+ defaultConfig {
+ minSdkVersion 15
+ targetSdkVersion 27
+ versionCode 114
+ versionName "1.1.4"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ compile 'com.android.support:appcompat-v7:27.1.0'
+ testCompile 'junit:junit:4.12'
+
+ // recycler
+ compile 'com.android.support:recyclerview-v7:27.1.0'
+ compile 'com.beloo.widget:ChipsLayoutManager:0.3.7@aar'
+}
+
diff --git a/extern/MaterialChipsInput/proguard-rules.pro b/extern/MaterialChipsInput/proguard-rules.pro
new file mode 100644
index 000000000..0ae68584d
--- /dev/null
+++ b/extern/MaterialChipsInput/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/couleurwhatever/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/extern/MaterialChipsInput/src/androidTest/java/com/pchmn/materialchips/ExampleInstrumentedTest.java b/extern/MaterialChipsInput/src/androidTest/java/com/pchmn/materialchips/ExampleInstrumentedTest.java
new file mode 100644
index 000000000..a28c3f326
--- /dev/null
+++ b/extern/MaterialChipsInput/src/androidTest/java/com/pchmn/materialchips/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.pchmn.materialchips;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.pchmn.library.test", appContext.getPackageName());
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/AndroidManifest.xml b/extern/MaterialChipsInput/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..ce7e64f72
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipView.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipView.java
new file mode 100644
index 000000000..7b57353e2
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipView.java
@@ -0,0 +1,399 @@
+package com.pchmn.materialchips;
+
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.pchmn.materialchips.model.ChipInterface;
+import com.pchmn.materialchips.util.LetterTileProvider;
+import com.pchmn.materialchips.util.ViewUtil;
+
+public class ChipView extends RelativeLayout {
+
+ private static final String TAG = ChipView.class.toString();
+ // context
+ private Context mContext;
+ // xml elements
+ private LinearLayout mContentLayout;
+ private TextView mLabelTextView;
+ private ImageButton mDeleteButton;
+ // attributes
+ private static final int NONE = -1;
+ private String mLabel;
+ private ColorStateList mLabelColor;
+ private boolean mDeletable = false;
+ private Drawable mDeleteIcon;
+ private ColorStateList mDeleteIconColor;
+ private ColorStateList mBackgroundColor;
+ // letter tile provider
+ private LetterTileProvider mLetterTileProvider;
+ // chip
+ private ChipInterface mChip;
+
+ public ChipView(Context context) {
+ super(context);
+ mContext = context;
+ init(null);
+ }
+
+ public ChipView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ init(attrs);
+ }
+
+ /**
+ * Inflate the view according to attributes
+ *
+ * @param attrs the attributes
+ */
+ private void init(AttributeSet attrs) {
+ // inflate layout
+ View rootView = inflate(getContext(), R.layout.chip_view, this);
+
+ mContentLayout = (LinearLayout) rootView.findViewById(R.id.content);
+ mLabelTextView = (TextView) rootView.findViewById(R.id.label);
+ mDeleteButton = (ImageButton) rootView.findViewById(R.id.delete_button);
+
+ // letter tile provider
+ mLetterTileProvider = new LetterTileProvider(mContext);
+
+ // attributes
+ if (attrs != null) {
+ TypedArray a = mContext.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.ChipView,
+ 0, 0);
+
+ try {
+ // label
+ mLabel = a.getString(R.styleable.ChipView_label);
+ mLabelColor = a.getColorStateList(R.styleable.ChipView_labelColor);
+ mDeletable = a.getBoolean(R.styleable.ChipView_deletable, false);
+ mDeleteIconColor = a.getColorStateList(R.styleable.ChipView_deleteIconColor);
+ int deleteIconId = a.getResourceId(R.styleable.ChipView_deleteIcon, NONE);
+ if (deleteIconId != NONE)
+ mDeleteIcon = ContextCompat.getDrawable(mContext, deleteIconId);
+ // background color
+ mBackgroundColor = a.getColorStateList(R.styleable.ChipView_backgroundColor);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ // inflate
+ inflateWithAttributes();
+ }
+
+ /**
+ * Inflate the view
+ */
+ private void inflateWithAttributes() {
+ // label
+ setLabel(mLabel);
+ if (mLabelColor != null)
+ setLabelColor(mLabelColor);
+
+ // delete button
+ setDeletable(mDeletable);
+
+ // background color
+ if (mBackgroundColor != null)
+ setChipBackgroundColor(mBackgroundColor);
+ }
+
+ public void inflate(ChipInterface chip) {
+ mChip = chip;
+ // label
+ mLabel = mChip.getLabel();
+ // inflate
+ inflateWithAttributes();
+ }
+
+ /**
+ * Get label
+ *
+ * @return the label
+ */
+ public String getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Set label
+ *
+ * @param label the label to set
+ */
+ public void setLabel(String label) {
+ mLabel = label;
+ mLabelTextView.setText(label);
+ }
+
+ /**
+ * Set label color
+ *
+ * @param color the color to set
+ */
+ public void setLabelColor(ColorStateList color) {
+ mLabelColor = color;
+ mLabelTextView.setTextColor(color);
+ }
+
+ /**
+ * Set label color
+ *
+ * @param color the color to set
+ */
+ public void setLabelColor(@ColorInt int color) {
+ mLabelColor = ColorStateList.valueOf(color);
+ mLabelTextView.setTextColor(color);
+ }
+
+// /**
+// * Show or hide avatar icon
+// *
+// * @param hasAvatarIcon true to show, false to hide
+// */
+// public void setHasAvatarIcon(boolean hasAvatarIcon) {
+// mHasAvatarIcon = hasAvatarIcon;
+//
+// if(!mHasAvatarIcon) {
+// // hide icon
+// mAvatarIconImageView.setVisibility(GONE);
+// // adjust padding
+// if(mDeleteButton.getVisibility() == VISIBLE)
+// mLabelTextView.setPadding(ViewUtil.dpToPx(12), 0, 0, 0);
+// else
+// mLabelTextView.setPadding(ViewUtil.dpToPx(12), 0, ViewUtil.dpToPx(12), 0);
+//
+// }
+// else {
+// // show icon
+// mAvatarIconImageView.setVisibility(VISIBLE);
+// // adjust padding
+// if(mDeleteButton.getVisibility() == VISIBLE)
+// mLabelTextView.setPadding(ViewUtil.dpToPx(8), 0, 0, 0);
+// else
+// mLabelTextView.setPadding(ViewUtil.dpToPx(8), 0, ViewUtil.dpToPx(12), 0);
+//
+// // set icon
+// if(mAvatarIconUri != null)
+// mAvatarIconImageView.setImageURI(mAvatarIconUri);
+// else if(mAvatarIconDrawable != null)
+// mAvatarIconImageView.setImageDrawable(mAvatarIconDrawable);
+// else
+// mAvatarIconImageView.setImageBitmap(mLetterTileProvider.getLetterTile(getLabel()));
+// }
+// }
+
+// /**
+// * Set avatar icon
+// *
+// * @param avatarIcon the icon to set
+// */
+// public void setAvatarIcon(Drawable avatarIcon) {
+// mAvatarIconDrawable = avatarIcon;
+// mHasAvatarIcon = true;
+// inflateWithAttributes();
+// }
+
+// /**
+// * Set avatar icon
+// *
+// * @param avatarUri the uri of the icon to set
+// */
+// public void setAvatarIcon(Uri avatarUri) {
+// mAvatarIconUri = avatarUri;
+// mHasAvatarIcon = true;
+// inflateWithAttributes();
+// }
+
+ /**
+ * Show or hide delte button
+ *
+ * @param deletable true to show, false to hide
+ */
+ public void setDeletable(boolean deletable) {
+ mDeletable = deletable;
+ if (!mDeletable) {
+ // hide delete icon
+ mDeleteButton.setVisibility(GONE);
+ // adjust padding
+ mLabelTextView.setPadding(ViewUtil.dpToPx(12), 0, ViewUtil.dpToPx(12), 0);
+ } else {
+ // show icon
+ mDeleteButton.setVisibility(VISIBLE);
+ // adjust padding
+ mLabelTextView.setPadding(ViewUtil.dpToPx(12), 0, 0, 0);
+
+ // set icon
+ if (mDeleteIcon != null)
+ mDeleteButton.setImageDrawable(mDeleteIcon);
+ if (mDeleteIconColor != null)
+ mDeleteButton.getDrawable().mutate().setColorFilter(mDeleteIconColor.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
+ }
+ }
+
+ /**
+ * Set delete icon color
+ *
+ * @param color the color to set
+ */
+ public void setDeleteIconColor(ColorStateList color) {
+ mDeleteIconColor = color;
+ mDeletable = true;
+ inflateWithAttributes();
+ }
+
+ /**
+ * Set delete icon color
+ *
+ * @param color the color to set
+ */
+ public void setDeleteIconColor(@ColorInt int color) {
+ mDeleteIconColor = ColorStateList.valueOf(color);
+ mDeletable = true;
+ inflateWithAttributes();
+ }
+
+ /**
+ * Set delete icon
+ *
+ * @param deleteIcon the icon to set
+ */
+ public void setDeleteIcon(Drawable deleteIcon) {
+ mDeleteIcon = deleteIcon;
+ mDeletable = true;
+ inflateWithAttributes();
+ }
+
+ /**
+ * Set background color
+ *
+ * @param color the color to set
+ */
+ public void setChipBackgroundColor(ColorStateList color) {
+ mBackgroundColor = color;
+ setChipBackgroundColor(color.getDefaultColor());
+ }
+
+ /**
+ * Set background color
+ *
+ * @param color the color to set
+ */
+ public void setChipBackgroundColor(@ColorInt int color) {
+ mBackgroundColor = ColorStateList.valueOf(color);
+ mContentLayout.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ }
+
+ /**
+ * Set the chip object
+ *
+ * @param chip the chip
+ */
+ public void setChip(ChipInterface chip) {
+ mChip = chip;
+ }
+
+ /**
+ * Set OnClickListener on the delete button
+ *
+ * @param onClickListener the OnClickListener
+ */
+ public void setOnDeleteClicked(OnClickListener onClickListener) {
+ mDeleteButton.setOnClickListener(onClickListener);
+ }
+
+ /**
+ * Set OnclickListener on the entire chip
+ *
+ * @param onClickListener the OnClickListener
+ */
+ public void setOnChipClicked(OnClickListener onClickListener) {
+ mContentLayout.setOnClickListener(onClickListener);
+ }
+
+ /**
+ * Builder class
+ */
+ public static class Builder {
+ private Context context;
+ private String label;
+ private ColorStateList labelColor;
+ private boolean deletable = false;
+ private Drawable deleteIcon;
+ private ColorStateList deleteIconColor;
+ private ColorStateList backgroundColor;
+ private ChipInterface chip;
+
+ public Builder(Context context) {
+ this.context = context;
+ }
+
+ public Builder label(String label) {
+ this.label = label;
+ return this;
+ }
+
+ public Builder labelColor(ColorStateList labelColor) {
+ this.labelColor = labelColor;
+ return this;
+ }
+
+ public Builder deletable(boolean deletable) {
+ this.deletable = deletable;
+ return this;
+ }
+
+ public Builder deleteIcon(Drawable deleteIcon) {
+ this.deleteIcon = deleteIcon;
+ return this;
+ }
+
+ public Builder deleteIconColor(ColorStateList deleteIconColor) {
+ this.deleteIconColor = deleteIconColor;
+ return this;
+ }
+
+ public Builder backgroundColor(ColorStateList backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ return this;
+ }
+
+ public Builder chip(ChipInterface chip) {
+ this.chip = chip;
+ this.label = chip.getLabel();
+ return this;
+ }
+
+ public ChipView build() {
+ return newInstance(this);
+ }
+ }
+
+ private static ChipView newInstance(Builder builder) {
+ ChipView chipView = new ChipView(builder.context);
+ chipView.mLabel = builder.label;
+ chipView.mLabelColor = builder.labelColor;
+ chipView.mDeletable = builder.deletable;
+ chipView.mDeleteIcon = builder.deleteIcon;
+ chipView.mDeleteIconColor = builder.deleteIconColor;
+ chipView.mBackgroundColor = builder.backgroundColor;
+ chipView.mChip = builder.chip;
+ chipView.inflateWithAttributes();
+
+ return chipView;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java
new file mode 100644
index 000000000..d1e7ad18d
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/ChipsInput.java
@@ -0,0 +1,427 @@
+package com.pchmn.materialchips;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.RecyclerView;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager;
+import com.pchmn.materialchips.adapter.ChipsAdapter;
+import com.pchmn.materialchips.model.Chip;
+import com.pchmn.materialchips.model.ChipInterface;
+import com.pchmn.materialchips.util.ActivityUtil;
+import com.pchmn.materialchips.util.MyWindowCallback;
+import com.pchmn.materialchips.util.ViewUtil;
+import com.pchmn.materialchips.views.ChipsInputEditText;
+import com.pchmn.materialchips.views.DetailedChipView;
+import com.pchmn.materialchips.views.FilterableListView;
+import com.pchmn.materialchips.views.ScrollViewMaxHeight;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ChipsInput extends ScrollViewMaxHeight {
+
+ private static final String TAG = ChipsInput.class.toString();
+ // context
+ private Context mContext;
+ // xml element
+ private RecyclerView mRecyclerView;
+ // adapter
+ 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;
+ private ColorStateList mFilterableListBackgroundColor;
+ private ColorStateList mFilterableListTextColor;
+ // chips listener
+ private List mChipsListenerList = new ArrayList<>();
+ private ChipsListener mChipsListener;
+ // chip list
+ private List extends ChipInterface> mFilterableChipList;
+ private FilterableListView mFilterableListView;
+ // chip validator
+ private ChipValidator mChipValidator;
+ private ViewGroup filterableListLayout;
+ private ChipsInputEditText mEditText;
+
+ public ChipsInput(Context context) {
+ super(context);
+ mContext = context;
+ init(null);
+ }
+
+ public ChipsInput(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ init(attrs);
+ }
+
+ /**
+ * Inflate the view according to attributes
+ *
+ * @param attrs the attributes
+ */
+ private void init(AttributeSet attrs) {
+ // inflate filterableListLayout
+ View rootView = inflate(getContext(), R.layout.chips_input, this);
+
+ mRecyclerView = (RecyclerView) rootView.findViewById(R.id.chips_recycler);
+
+ initEditText();
+
+ // attributes
+ if (attrs != null) {
+ TypedArray a = mContext.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.ChipsInput,
+ 0, 0);
+
+ try {
+ // hint
+ mHint = a.getString(R.styleable.ChipsInput_hint);
+ mHintColor = a.getColorStateList(R.styleable.ChipsInput_hintColor);
+ mTextColor = a.getColorStateList(R.styleable.ChipsInput_textColor);
+ 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);
+ // filterable list
+ mFilterableListBackgroundColor = a.getColorStateList(R.styleable.ChipsInput_filterable_list_backgroundColor);
+ mFilterableListTextColor = a.getColorStateList(R.styleable.ChipsInput_filterable_list_textColor);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ // adapter
+ mChipsAdapter = new ChipsAdapter(mContext, this, mEditText, mRecyclerView);
+ ChipsLayoutManager chipsLayoutManager = ChipsLayoutManager.newBuilder(mContext)
+ .setOrientation(ChipsLayoutManager.HORIZONTAL)
+ .build();
+ mRecyclerView.setLayoutManager(chipsLayoutManager);
+ mRecyclerView.setNestedScrollingEnabled(false);
+ mRecyclerView.setAdapter(mChipsAdapter);
+
+ // set window callback
+ // will hide DetailedOpenView and hide keyboard on touch outside
+ Activity activity = ActivityUtil.scanForActivity(mContext);
+ 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));
+ }
+
+ private void initEditText() {
+ mEditText = new ChipsInputEditText(mContext);
+ if (mHintColor != null)
+ mEditText.setHintTextColor(mHintColor);
+ if (mTextColor != null)
+ mEditText.setTextColor(mTextColor);
+
+ mEditText.setLayoutParams(new RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ mEditText.setHint(mHint);
+ mEditText.setBackgroundResource(android.R.color.transparent);
+ // prevent fullscreen on landscape
+ mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
+ mEditText.setPrivateImeOptions("nm");
+ // no suggestion
+ mEditText.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
+
+ // handle back space
+ mEditText.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();
+ }
+ return false;
+ }
+ });
+
+ mEditText.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());
+ }
+ return false;
+ }
+ });
+
+ // text changed
+ mEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ ChipsInput.this.onTextChanged(s);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+ }
+
+ 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) {
+ Chip chip = new Chip(id, label, info);
+ mChipsAdapter.addChip(chip);
+ }
+
+ public void addChip(String label, String info) {
+ Chip chip = new Chip(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() {
+ return mChipsAdapter.getmEditText();
+ }
+
+ public DetailedChipView getDetailedChipView(ChipInterface chip) {
+ return new DetailedChipView.Builder(mContext)
+ .chip(chip)
+ .textColor(mChipDetailedTextColor)
+ .backgroundColor(mChipDetailedBackgroundColor)
+ .deleteIconColor(mChipDetailedDeleteIconColor)
+ .build();
+ }
+
+ public void addChipsListener(ChipsListener chipsListener) {
+ mChipsListenerList.add(chipsListener);
+ mChipsListener = chipsListener;
+ }
+
+ public void onChipAdded(ChipInterface chip, int size) {
+ for (ChipsListener chipsListener : mChipsListenerList) {
+ chipsListener.onChipAdded(chip, size);
+ }
+ }
+
+ public void onChipRemoved(ChipInterface chip, int size) {
+ for (ChipsListener chipsListener : mChipsListenerList) {
+ chipsListener.onChipRemoved(chip, size);
+ }
+ }
+
+ public void onTextChanged(CharSequence text) {
+ if (mChipsListener != null) {
+ for (ChipsListener chipsListener : mChipsListenerList) {
+ chipsListener.onTextChanged(text);
+ }
+ // show filterable list
+ if (mFilterableListView != null) {
+ if (text.length() > 0)
+ mFilterableListView.filterList(text);
+ else
+ mFilterableListView.fadeOut();
+ }
+ }
+ }
+
+ public void onActionDone(CharSequence text) {
+ if (mChipsListener != null) {
+ for (ChipsListener chipsListener : mChipsListenerList) {
+ chipsListener.onActionDone(text);
+ }
+ }
+ }
+
+ public List extends ChipInterface> getSelectedChipList() {
+ return mChipsAdapter.getChipList();
+ }
+
+ public String getHint() {
+ return mHint;
+ }
+
+ public void setHint(String mHint) {
+ this.mHint = mHint;
+ }
+
+ public void setHintColor(ColorStateList mHintColor) {
+ this.mHintColor = mHintColor;
+ }
+
+ public void setTextColor(ColorStateList mTextColor) {
+ this.mTextColor = mTextColor;
+ }
+
+ public ChipsInput setMaxRows(int mMaxRows) {
+ this.mMaxRows = mMaxRows;
+ 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;
+ }
+
+ public boolean isShowChipDetailed() {
+ 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 void setFilterableList(List extends ChipInterface> list) {
+ mFilterableChipList = list;
+ if (filterableListLayout != null) {
+ mFilterableListView = new FilterableListView(mContext, filterableListLayout);
+ } else {
+ mFilterableListView = new FilterableListView(mContext);
+ }
+ mFilterableListView.build(mFilterableChipList, this, mFilterableListBackgroundColor, mFilterableListTextColor);
+ mChipsAdapter.setFilterableListView(mFilterableListView);
+ }
+
+ public List extends ChipInterface> getFilterableList() {
+ return mFilterableChipList;
+ }
+
+ public ChipValidator getChipValidator() {
+ return mChipValidator;
+ }
+
+ public void setChipValidator(ChipValidator mChipValidator) {
+ this.mChipValidator = mChipValidator;
+ }
+
+ public interface ChipsListener {
+ void onChipAdded(ChipInterface chip, int newSize);
+
+ void onChipRemoved(ChipInterface chip, int newSize);
+
+ void onTextChanged(CharSequence text);
+
+ void onActionDone(CharSequence text);
+ }
+
+ public interface ChipValidator {
+ boolean areEquals(ChipInterface chip1, ChipInterface 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
new file mode 100644
index 000000000..64d8216a1
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/ChipsAdapter.java
@@ -0,0 +1,384 @@
+package com.pchmn.materialchips.adapter;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.EditText;
+import android.widget.RelativeLayout;
+
+import com.pchmn.materialchips.ChipView;
+import com.pchmn.materialchips.ChipsInput;
+import com.pchmn.materialchips.model.ChipInterface;
+import com.pchmn.materialchips.util.ViewUtil;
+import com.pchmn.materialchips.views.ChipsInputEditText;
+import com.pchmn.materialchips.views.DetailedChipView;
+import com.pchmn.materialchips.views.FilterableListView;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+public 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;
+
+ private RecyclerView mRecycler;
+
+ public ChipsAdapter(Context context, ChipsInput chipsInput, RecyclerView recycler) {
+ mContext = context;
+ mChipsInput = chipsInput;
+ mRecycler = recycler;
+ mHintLabel = mChipsInput.getHint();
+ }
+
+ public ChipsAdapter(Context mContext, ChipsInput chipsInput, ChipsInputEditText mEditText, RecyclerView mRecyclerView) {
+ this(mContext, chipsInput, mRecyclerView);
+ this.mEditText = mEditText;
+ }
+
+ private class ItemViewHolder extends RecyclerView.ViewHolder {
+
+ 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);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mChipList.size() + 1;
+ }
+
+ private ChipInterface getItem(int position) {
+ return mChipList.get(position);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == mChipList.size()) {
+ return TYPE_EDIT_TEXT;
+ }
+
+ return TYPE_ITEM;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mChipList.get(position).hashCode();
+ }
+
+ private void autofitEditText() {
+ // min width of edit text = 50 dp
+ ViewGroup.LayoutParams params = mEditText.getLayoutParams();
+ params.width = ViewUtil.dpToPx(50);
+ mEditText.setLayoutParams(params);
+
+ // listen to change in the tree
+ mEditText.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();
+
+ // edit text will fill the space
+ ViewGroup.LayoutParams params = mEditText.getLayoutParams();
+ params.width = right - left - ViewUtil.dpToPx(8);
+ mEditText.setLayoutParams(params);
+
+ // request focus
+ mEditText.requestFocus();
+
+ // remove the listener:
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ mEditText.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ } else {
+ mEditText.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ }
+
+ });
+ }
+
+ private void handleClickOnEditText(ChipView chipView, final int position) {
+ // delete chip
+ chipView.setOnDeleteClicked(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ removeChip(position);
+ }
+ });
+
+ // show detailed chip
+ if (mChipsInput.isShowChipDetailed()) {
+ chipView.setOnChipClicked(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // get chip position
+ int[] coord = new int[2];
+ v.getLocationInWindow(coord);
+
+ final DetailedChipView detailedChipView = mChipsInput.getDetailedChipView(getItem(position));
+ setDetailedChipViewPosition(detailedChipView, coord);
+
+ // delete button
+ detailedChipView.setOnDeleteClicked(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ removeChip(position);
+ detailedChipView.fadeOut();
+ }
+ });
+ }
+ });
+ }
+ }
+
+ private void setDetailedChipViewPosition(DetailedChipView detailedChipView, int[] coord) {
+ // window width
+ ViewGroup rootView = (ViewGroup) mRecycler.getRootView();
+ int windowWidth = ViewUtil.getWindowWidth(mContext);
+
+ // chip size
+ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+ ViewUtil.dpToPx(300),
+ ViewUtil.dpToPx(100));
+
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+
+ // align left window
+ if (coord[0] <= 0) {
+ layoutParams.leftMargin = 0;
+ layoutParams.topMargin = coord[1] - ViewUtil.dpToPx(13);
+ detailedChipView.alignLeft();
+ }
+ // align right
+ else if (coord[0] + ViewUtil.dpToPx(300) > windowWidth + ViewUtil.dpToPx(13)) {
+ layoutParams.leftMargin = windowWidth - ViewUtil.dpToPx(300);
+ layoutParams.topMargin = coord[1] - ViewUtil.dpToPx(13);
+ detailedChipView.alignRight();
+ }
+ // same position as chip
+ else {
+ layoutParams.leftMargin = coord[0] - ViewUtil.dpToPx(13);
+ layoutParams.topMargin = coord[1] - ViewUtil.dpToPx(13);
+ }
+
+ // show view
+ rootView.addView(detailedChipView, layoutParams);
+ detailedChipView.fadeIn();
+ }
+
+ public void setFilterableListView(FilterableListView filterableListView) {
+ if (mEditText != null) {
+ mEditText.setFilterableListView(filterableListView);
+ }
+ }
+
+ 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());
+ }
+
+ // hide hint
+ mEditText.setHint(null);
+ // reset text
+ mEditText.setText(null);
+
+ notifyItemRangeChanged(chipsBeforeAdding, chipList.size());
+ }
+ }
+ }
+
+ public void addChip(ChipInterface chip) {
+ if (!listContains(mChipList, chip)) {
+ mChipList.add(chip);
+ // notify listener
+ mChipsInput.onChipAdded(chip, mChipList.size());
+ // hide hint
+ mEditText.setHint(null);
+ // reset text
+ mEditText.setText(null);
+ // refresh data
+ notifyItemInserted(mChipList.size());
+ }
+ }
+
+ public void removeChip(ChipInterface chip) {
+ int position = mChipList.indexOf(chip);
+ mChipList.remove(position);
+ // notify listener
+ notifyItemRangeChanged(position, getItemCount());
+ mChipsInput.onChipRemoved(chip, mChipList.size());
+ // if 0 chip
+ if (mChipList.size() == 0) {
+ mEditText.setHint(mHintLabel);
+ }
+ // refresh data
+ notifyDataSetChanged();
+ }
+
+ public void removeChip(int position) {
+ ChipInterface chip = mChipList.get(position);
+ // remove contact
+ mChipList.remove(position);
+ // notify listener
+ mChipsInput.onChipRemoved(chip, mChipList.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);
+ }
+ // refresh data
+ notifyDataSetChanged();
+ }
+
+ public void removeLastChip() {
+ if (mChipList.size() > 0) {
+ removeChip(mChipList.get(mChipList.size() - 1));
+ }
+ }
+
+ public List getChipList() {
+ return mChipList;
+ }
+
+ private boolean listContains(List contactList, ChipInterface chip) {
+
+ if (mChipsInput.getChipValidator() != null) {
+ for (ChipInterface item : contactList) {
+ if (mChipsInput.getChipValidator().areEquals(item, chip)) {
+ return true;
+ }
+ }
+ } else {
+ for (ChipInterface item : contactList) {
+ if (chip.getId() != null && chip.getId().equals(item.getId())) {
+ return true;
+ }
+ if (chip.getLabel().equals(item.getLabel())) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public ChipsInputEditText getmEditText() {
+ return mEditText;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java
new file mode 100644
index 000000000..2895a4252
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/adapter/FilterableAdapter.java
@@ -0,0 +1,253 @@
+package com.pchmn.materialchips.adapter;
+
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.TextView;
+
+import com.pchmn.materialchips.ChipsInput;
+import com.pchmn.materialchips.R;
+import com.pchmn.materialchips.model.ChipInterface;
+import com.pchmn.materialchips.util.ColorUtil;
+import com.pchmn.materialchips.util.LetterTileProvider;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import static android.view.View.GONE;
+
+public class FilterableAdapter extends RecyclerView.Adapter implements Filterable {
+
+ private static final String TAG = FilterableAdapter.class.toString();
+ // context
+ private Context mContext;
+ // list
+ private List mOriginalList = new ArrayList<>();
+ private List mChipList = new ArrayList<>();
+ private List mFilteredList = new ArrayList<>();
+ private ChipFilter mFilter;
+ private ChipsInput mChipsInput;
+ private LetterTileProvider mLetterTileProvider;
+ private ColorStateList mBackgroundColor;
+ private ColorStateList mTextColor;
+ // recycler
+ private RecyclerView mRecyclerView;
+ // sort
+ private Comparator mComparator;
+ private Collator mCollator;
+
+
+ public FilterableAdapter(Context context,
+ RecyclerView recyclerView,
+ List extends ChipInterface> chipList,
+ ChipsInput chipsInput,
+ ColorStateList backgroundColor,
+ ColorStateList textColor) {
+ mContext = context;
+ mRecyclerView = recyclerView;
+ mCollator = Collator.getInstance(Locale.getDefault());
+ mCollator.setStrength(Collator.PRIMARY);
+ mComparator = new Comparator() {
+ @Override
+ public int compare(ChipInterface o1, ChipInterface o2) {
+ return mCollator.compare(o1.getLabel(), o2.getLabel());
+ }
+ };
+ // remove chips that do not have label
+ Iterator extends ChipInterface> iterator = chipList.iterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().getLabel() == null)
+ iterator.remove();
+ }
+ sortList(chipList);
+ mOriginalList.addAll(chipList);
+ mChipList.addAll(chipList);
+ mFilteredList.addAll(chipList);
+ mLetterTileProvider = new LetterTileProvider(mContext);
+ mBackgroundColor = backgroundColor;
+ mTextColor = textColor;
+ mChipsInput = chipsInput;
+
+ mChipsInput.addChipsListener(new ChipsInput.ChipsListener() {
+ @Override
+ public void onChipAdded(ChipInterface chip, int newSize) {
+ removeChip(chip);
+ }
+
+ @Override
+ public void onChipRemoved(ChipInterface chip, int newSize) {
+ addChip(chip);
+ }
+
+ @Override
+ public void onTextChanged(CharSequence text) {
+ mRecyclerView.scrollToPosition(0);
+ }
+
+ @Override
+ public void onActionDone(CharSequence text) {
+ mRecyclerView.scrollToPosition(0);
+ }
+ });
+ }
+
+ private class ItemViewHolder extends RecyclerView.ViewHolder {
+
+ private TextView mLabel;
+ private TextView mInfo;
+
+ ItemViewHolder(View view) {
+ super(view);
+ mLabel = (TextView) view.findViewById(R.id.label);
+ mInfo = (TextView) view.findViewById(R.id.info);
+ }
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.item_list_filterable, parent, false);
+ return new ItemViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
+ final ChipInterface chip = getItem(position);
+
+ // label
+ itemViewHolder.mLabel.setText(chip.getLabel());
+
+ // info
+ if (chip.getInfo() != null) {
+ itemViewHolder.mInfo.setVisibility(View.VISIBLE);
+ itemViewHolder.mInfo.setText(chip.getInfo());
+ } else {
+ itemViewHolder.mInfo.setVisibility(GONE);
+ }
+
+ // colors
+ if (mBackgroundColor != null)
+ itemViewHolder.itemView.getBackground().setColorFilter(mBackgroundColor.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
+ if (mTextColor != null) {
+ itemViewHolder.mLabel.setTextColor(mTextColor);
+ itemViewHolder.mInfo.setTextColor(ColorUtil.alpha(mTextColor.getDefaultColor(), 150));
+ }
+
+ // onclick
+ itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mChipsInput != null)
+ mChipsInput.addChip(chip);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return mFilteredList.size();
+ }
+
+ private ChipInterface getItem(int position) {
+ return mFilteredList.get(position);
+ }
+
+ @Override
+ public Filter getFilter() {
+ if (mFilter == null)
+ mFilter = new ChipFilter(this, mChipList);
+ return mFilter;
+ }
+
+ private class ChipFilter extends Filter {
+
+ private FilterableAdapter adapter;
+ private List originalList;
+ private List filteredList;
+
+ public ChipFilter(FilterableAdapter adapter, List originalList) {
+ super();
+ this.adapter = adapter;
+ this.originalList = originalList;
+ this.filteredList = new ArrayList<>();
+ }
+
+ @Override
+ protected FilterResults performFiltering(CharSequence constraint) {
+ filteredList.clear();
+ FilterResults results = new FilterResults();
+ if (constraint.length() == 0) {
+ filteredList.addAll(originalList);
+ } else {
+ final String filterPattern = constraint.toString().toLowerCase().trim();
+ for (ChipInterface chip : originalList) {
+ if (chip.getLabel().toLowerCase().contains(filterPattern)) {
+ filteredList.add(chip);
+ } else if (chip.getInfo() != null && chip.getInfo().toLowerCase().replaceAll("\\s", "").contains(filterPattern)) {
+ filteredList.add(chip);
+ }
+ }
+ }
+
+ results.values = filteredList;
+ results.count = filteredList.size();
+ return results;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint, FilterResults results) {
+ mFilteredList.clear();
+ mFilteredList.addAll((ArrayList) results.values);
+ notifyDataSetChanged();
+ }
+ }
+
+ private void removeChip(ChipInterface chip) {
+ int position = mFilteredList.indexOf(chip);
+ if (position >= 0)
+ mFilteredList.remove(position);
+
+ position = mChipList.indexOf(chip);
+ if (position >= 0)
+ mChipList.remove(position);
+
+ notifyDataSetChanged();
+ }
+
+ private void addChip(ChipInterface chip) {
+ if (contains(chip)) {
+ mChipList.add(chip);
+ mFilteredList.add(chip);
+ // sort original list
+ sortList(mChipList);
+ // sort filtered list
+ sortList(mFilteredList);
+
+ notifyDataSetChanged();
+ }
+ }
+
+ private boolean contains(ChipInterface chip) {
+ for (ChipInterface item : mOriginalList) {
+ if (item.equals(chip))
+ return true;
+ }
+ return false;
+ }
+
+ private void sortList(List extends ChipInterface> list) {
+ Collections.sort(list, mComparator);
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java
new file mode 100644
index 000000000..e79c79cd9
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/Chip.java
@@ -0,0 +1,39 @@
+package com.pchmn.materialchips.model;
+
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class Chip implements ChipInterface {
+
+ private Object id;
+ private String label;
+ private String info;
+
+ public Chip(@NonNull Object id, @NonNull String label, @Nullable String info) {
+ this.id = id;
+ this.label = label;
+ this.info = info;
+ }
+
+
+ public Chip(@NonNull String label, @Nullable String info) {
+ this.label = label;
+ this.info = info;
+ }
+
+ @Override
+ public Object getId() {
+ return id;
+ }
+
+ @Override
+ public String getLabel() {
+ return label;
+ }
+
+ @Override
+ public String getInfo() {
+ return info;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java
new file mode 100644
index 000000000..804ef47f1
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/model/ChipInterface.java
@@ -0,0 +1,12 @@
+package com.pchmn.materialchips.model;
+
+
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+public interface ChipInterface {
+
+ Object getId();
+ String getLabel();
+ String getInfo();
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ActivityUtil.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ActivityUtil.java
new file mode 100644
index 000000000..c119fad07
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ActivityUtil.java
@@ -0,0 +1,20 @@
+package com.pchmn.materialchips.util;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+
+public class ActivityUtil {
+
+ public static Activity scanForActivity(Context context) {
+ if (context == null)
+ return null;
+ else if (context instanceof Activity)
+ return (Activity)context;
+ else if (context instanceof ContextWrapper)
+ return scanForActivity(((ContextWrapper)context).getBaseContext());
+
+ return null;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ColorUtil.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ColorUtil.java
new file mode 100644
index 000000000..c1b118c1c
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ColorUtil.java
@@ -0,0 +1,38 @@
+package com.pchmn.materialchips.util;
+
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.util.TypedValue;
+
+import com.pchmn.materialchips.R;
+
+public class ColorUtil {
+
+ public static int lighter(int color, float factor) {
+ int red = (int) ((Color.red(color) * (1 - factor) / 255 + factor) * 255);
+ int green = (int) ((Color.green(color) * (1 - factor) / 255 + factor) * 255);
+ int blue = (int) ((Color.blue(color) * (1 - factor) / 255 + factor) * 255);
+ return Color.argb(Color.alpha(color), red, green, blue);
+ }
+
+ public static int lighter(ColorStateList color, float factor) {
+ return lighter(color.getDefaultColor(), factor);
+ }
+
+ public static int alpha(int color, int alpha) {
+ return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+ }
+
+ public static boolean isColorDark(int color){
+ double darkness = 1 - (0.2126*Color.red(color) + 0.7152*Color.green(color) + 0.0722*Color.blue(color))/255;
+ return darkness >= 0.5;
+ }
+
+ public static int getThemeAccentColor (final Context context) {
+ final TypedValue value = new TypedValue ();
+ context.getTheme ().resolveAttribute (R.attr.colorAccent, value, true);
+ return value.data;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/LetterTileProvider.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/LetterTileProvider.java
new file mode 100644
index 000000000..9028a5286
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/LetterTileProvider.java
@@ -0,0 +1,221 @@
+package com.pchmn.materialchips.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
+import android.text.TextPaint;
+import android.util.Log;
+
+import com.pchmn.materialchips.R;
+
+/**
+ * Used to create a {@link Bitmap} that contains a letter used in the English
+ * alphabet or digit, if there is no letter or digit available, a default image
+ * is shown instead
+ */
+public class LetterTileProvider {
+
+ /** The number of available tile colors (see R.array.letter_tile_colors) */
+ private static final int NUM_OF_TILE_COLORS = 8;
+
+ /** The {@link TextPaint} used to draw the letter onto the tile */
+ private final TextPaint mPaint = new TextPaint();
+ /** The bounds that enclose the letter */
+ private final Rect mBounds = new Rect();
+ /** The {@link Canvas} to draw on */
+ private final Canvas mCanvas = new Canvas();
+ /** The first char of the name being displayed */
+ private final char[] mFirstChar = new char[1];
+
+ /** The background colors of the tile */
+ private final TypedArray mColors;
+ /** The font size used to display the letter */
+ private final int mTileLetterFontSize;
+ /** The default image to display */
+ private final Bitmap mDefaultBitmap;
+
+ /** Width */
+ private final int mWidth;
+ /** Height */
+ private final int mHeight;
+
+ /**
+ * Constructor for LetterTileProvider
+ *
+ * @param context The {@link Context} to use
+ */
+ public LetterTileProvider(Context context) {
+ final Resources res = context.getResources();
+
+ mPaint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
+ mPaint.setColor(Color.WHITE);
+ mPaint.setTextAlign(Paint.Align.CENTER);
+ mPaint.setAntiAlias(true);
+
+ mColors = res.obtainTypedArray(R.array.letter_tile_colors);
+ mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size);
+
+ //mDefaultBitmap = BitmapFactory.decodeResource(res, android.R.drawable.);
+ mDefaultBitmap = drawableToBitmap(ContextCompat.getDrawable(context, R.drawable.ic_person_white_24dp));
+ mWidth = res.getDimensionPixelSize(R.dimen.letter_tile_size);
+ mHeight = res.getDimensionPixelSize(R.dimen.letter_tile_size);
+ }
+
+ /**
+ * @param displayName The name used to create the letter for the tile
+ * @return A {@link Bitmap} that contains a letter used in the English
+ * alphabet or digit, if there is no letter or digit available, a
+ * default image is shown instead
+ */
+ public Bitmap getLetterTile(String displayName) {
+ // workaround
+ if(displayName == null || displayName.length() == 0)
+ return null;
+
+ final Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
+
+ final char firstChar = displayName.charAt(0);
+
+ final Canvas c = mCanvas;
+ c.setBitmap(bitmap);
+ c.drawColor(pickColor(displayName));
+
+ if (isLetterOrDigit(firstChar)) {
+ mFirstChar[0] = Character.toUpperCase(firstChar);
+ mPaint.setTextSize(mTileLetterFontSize);
+ mPaint.getTextBounds(mFirstChar, 0, 1, mBounds);
+ c.drawText(mFirstChar, 0, 1, mWidth / 2, mHeight / 2
+ + (mBounds.bottom - mBounds.top) / 2, mPaint);
+ }
+ else {
+ // (32 - 24) / 2 = 4
+ c.drawBitmap(mDefaultBitmap, ViewUtil.dpToPx(4), ViewUtil.dpToPx(4), null);
+ }
+ return bitmap;
+ }
+
+ /**
+ * @param displayName The name used to create the letter for the tile
+ * @return A circular {@link Bitmap} that contains a letter used in the English
+ * alphabet or digit, if there is no letter or digit available, a
+ * default image is shown instead
+ */
+ public Bitmap getCircularLetterTile(String displayName) {
+ // workaround
+ if(displayName == null || displayName.length() == 0)
+ displayName = ".";
+
+ final Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
+ final char firstChar = displayName.charAt(0);
+
+ final Canvas c = mCanvas;
+ c.setBitmap(bitmap);
+ c.drawColor(pickColor(displayName));
+
+ if (isLetterOrDigit(firstChar)) {
+ mFirstChar[0] = Character.toUpperCase(firstChar);
+ mPaint.setTextSize(mTileLetterFontSize);
+ mPaint.getTextBounds(mFirstChar, 0, 1, mBounds);
+ c.drawText(mFirstChar, 0, 1, mWidth / 2, mHeight / 2
+ + (mBounds.bottom - mBounds.top) / 2, mPaint);
+ } else {
+ // (32 - 24) / 2 = 4
+ c.drawBitmap(mDefaultBitmap, ViewUtil.dpToPx(4), ViewUtil.dpToPx(4), null);
+ }
+ return getCircularBitmap(bitmap);
+ }
+
+ /**
+ * @param c The char to check
+ * @return True if c
is in the English alphabet or is a digit,
+ * false otherwise
+ */
+ private static boolean isLetterOrDigit(char c) {
+ //return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9';
+ return Character.isLetterOrDigit(c);
+ }
+
+ /**
+ * @param key The key used to generate the tile color
+ * @return A new or previously chosen color for key
used as the
+ * tile background color
+ */
+ private int pickColor(String key) {
+ // String.hashCode() is not supposed to change across java versions, so
+ // this should guarantee the same key always maps to the same color
+ final int color = Math.abs(key.hashCode()) % NUM_OF_TILE_COLORS;
+ try {
+ return mColors.getColor(color, Color.BLACK);
+ } finally {
+ // bug with recycler view
+ //mColors.recycle();
+ }
+ }
+
+ private Bitmap getCircularBitmap(Bitmap bitmap) {
+ Bitmap output;
+
+ if (bitmap.getWidth() > bitmap.getHeight()) {
+ output = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+ } else {
+ output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(), Bitmap.Config.ARGB_8888);
+ }
+
+ Canvas canvas = new Canvas(output);
+
+ final int color = 0xff424242;
+ final Paint paint = new Paint();
+ final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+ float r = 0;
+
+ if (bitmap.getWidth() > bitmap.getHeight()) {
+ r = bitmap.getHeight() / 2;
+ } else {
+ r = bitmap.getWidth() / 2;
+ }
+
+ paint.setAntiAlias(true);
+ canvas.drawARGB(0, 0, 0, 0);
+ paint.setColor(color);
+ canvas.drawCircle(r, r, r, paint);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(bitmap, rect, rect, paint);
+ return output;
+ }
+
+ public static Bitmap drawableToBitmap (Drawable drawable) {
+ Bitmap bitmap = null;
+
+ if (drawable instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ if(bitmapDrawable.getBitmap() != null) {
+ return bitmapDrawable.getBitmap();
+ }
+ }
+
+ if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+ bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
+ } else {
+ bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ }
+
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/MyWindowCallback.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/MyWindowCallback.java
new file mode 100644
index 000000000..924350801
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/MyWindowCallback.java
@@ -0,0 +1,173 @@
+package com.pchmn.materialchips.util;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.view.ActionMode;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SearchEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+import com.pchmn.materialchips.views.ChipsInputEditText;
+import com.pchmn.materialchips.views.DetailedChipView;
+
+public class MyWindowCallback implements Window.Callback {
+
+ private Window.Callback mLocalCallback;
+ private Activity mActivity;
+
+ public MyWindowCallback(Window.Callback localCallback, Activity activity) {
+ mLocalCallback = localCallback;
+ mActivity = activity;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent keyEvent) {
+ return mLocalCallback.dispatchKeyEvent(keyEvent);
+ }
+
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent keyEvent) {
+ return mLocalCallback.dispatchKeyShortcutEvent(keyEvent);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent motionEvent) {
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+ View v = mActivity.getCurrentFocus();
+ if(v instanceof DetailedChipView) {
+ Rect outRect = new Rect();
+ v.getGlobalVisibleRect(outRect);
+ if (!outRect.contains((int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
+ ((DetailedChipView) v).fadeOut();
+ }
+ }
+ if (v instanceof ChipsInputEditText) {
+ Rect outRect = new Rect();
+ v.getGlobalVisibleRect(outRect);
+ if (!outRect.contains((int) motionEvent.getRawX(), (int) motionEvent.getRawY())
+ && !((ChipsInputEditText) v).isFilterableListVisible()) {
+ InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ }
+ }
+ }
+ return mLocalCallback.dispatchTouchEvent(motionEvent);
+ }
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent motionEvent) {
+ return mLocalCallback.dispatchTrackballEvent(motionEvent);
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent motionEvent) {
+ return mLocalCallback.dispatchGenericMotionEvent(motionEvent);
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
+ return mLocalCallback.dispatchPopulateAccessibilityEvent(accessibilityEvent);
+ }
+
+ @Nullable
+ @Override
+ public View onCreatePanelView(int i) {
+ return mLocalCallback.onCreatePanelView(i);
+ }
+
+ @Override
+ public boolean onCreatePanelMenu(int i, Menu menu) {
+ return mLocalCallback.onCreatePanelMenu(i, menu);
+ }
+
+ @Override
+ public boolean onPreparePanel(int i, View view, Menu menu) {
+ return mLocalCallback.onPreparePanel(i, view, menu);
+ }
+
+ @Override
+ public boolean onMenuOpened(int i, Menu menu) {
+ return mLocalCallback.onMenuOpened(i, menu);
+ }
+
+ @Override
+ public boolean onMenuItemSelected(int i, MenuItem menuItem) {
+ return mLocalCallback.onMenuItemSelected(i, menuItem);
+ }
+
+ @Override
+ public void onWindowAttributesChanged(WindowManager.LayoutParams layoutParams) {
+ mLocalCallback.onWindowAttributesChanged(layoutParams);
+ }
+
+ @Override
+ public void onContentChanged() {
+ mLocalCallback.onContentChanged();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean b) {
+ mLocalCallback.onWindowFocusChanged(b);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ mLocalCallback.onAttachedToWindow();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ mLocalCallback.onDetachedFromWindow();
+ }
+
+ @Override
+ public void onPanelClosed(int i, Menu menu) {
+ mLocalCallback.onPanelClosed(i, menu);
+ }
+
+ @Override
+ public boolean onSearchRequested() {
+ return mLocalCallback.onSearchRequested();
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ @Override
+ public boolean onSearchRequested(SearchEvent searchEvent) {
+ return mLocalCallback.onSearchRequested(searchEvent);
+ }
+
+ @Nullable
+ @Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
+ return mLocalCallback.onWindowStartingActionMode(callback);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ @Nullable
+ @Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int i) {
+ return mLocalCallback.onWindowStartingActionMode(callback, i);
+ }
+
+ @Override
+ public void onActionModeStarted(ActionMode actionMode) {
+ mLocalCallback.onActionModeStarted(actionMode);
+ }
+
+ @Override
+ public void onActionModeFinished(ActionMode actionMode) {
+ mLocalCallback.onActionModeFinished(actionMode);
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ViewUtil.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ViewUtil.java
new file mode 100644
index 000000000..1cae87da7
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/util/ViewUtil.java
@@ -0,0 +1,81 @@
+package com.pchmn.materialchips.util;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+public class ViewUtil {
+
+ private static int windowWidthPortrait = 0;
+ private static int windowWidthLandscape = 0;
+
+ public static int dpToPx(int dp) {
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
+
+ public static int pxToDp(int px) {
+ return (int) (px / Resources.getSystem().getDisplayMetrics().density);
+ }
+
+ public static int getWindowWidth(Context context) {
+ if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
+ return getWindowWidthPortrait(context);
+ }
+ else {
+ return getWindowWidthLandscape(context);
+ }
+ }
+
+ private static int getWindowWidthPortrait(Context context) {
+ if(windowWidthPortrait == 0) {
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ windowWidthPortrait = metrics.widthPixels;
+ }
+
+ return windowWidthPortrait;
+ }
+
+ private static int getWindowWidthLandscape(Context context) {
+ if(windowWidthLandscape == 0) {
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ windowWidthLandscape = metrics.widthPixels;
+ }
+
+ return windowWidthLandscape;
+ }
+
+ public static int getNavBarHeight(Context context) {
+ int result = 0;
+ boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
+ boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
+
+ if(!hasMenuKey && !hasBackKey) {
+ //The device has a navigation bar
+ Resources resources = context.getResources();
+
+ int orientation = context.getResources().getConfiguration().orientation;
+ int resourceId;
+ if (isTablet(context)){
+ resourceId = resources.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_height_landscape", "dimen", "android");
+ } else {
+ resourceId = resources.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_width", "dimen", "android");
+ }
+
+ if (resourceId > 0) {
+ return context.getResources().getDimensionPixelSize(resourceId);
+ }
+ }
+ return result;
+ }
+
+
+ private static boolean isTablet(Context context) {
+ return (context.getResources().getConfiguration().screenLayout
+ & Configuration.SCREENLAYOUT_SIZE_MASK)
+ >= Configuration.SCREENLAYOUT_SIZE_LARGE;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java
new file mode 100644
index 000000000..d3bb04f5d
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ChipsInputEditText.java
@@ -0,0 +1,31 @@
+package com.pchmn.materialchips.views;
+
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+
+public class ChipsInputEditText extends android.support.v7.widget.AppCompatEditText {
+
+ private FilterableListView filterableListView;
+
+ public ChipsInputEditText(Context context) {
+ super(context);
+ }
+
+ public ChipsInputEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean isFilterableListVisible() {
+ return filterableListView != null && filterableListView.getVisibility() == VISIBLE;
+ }
+
+ public FilterableListView getFilterableListView() {
+ return filterableListView;
+ }
+
+ public void setFilterableListView(FilterableListView filterableListView) {
+ this.filterableListView = filterableListView;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DetailedChipView.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DetailedChipView.java
new file mode 100644
index 000000000..b5a7f6eb3
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/DetailedChipView.java
@@ -0,0 +1,233 @@
+package com.pchmn.materialchips.views;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AlphaAnimation;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.pchmn.materialchips.R;
+import com.pchmn.materialchips.model.ChipInterface;
+import com.pchmn.materialchips.util.ColorUtil;
+import com.pchmn.materialchips.util.LetterTileProvider;
+
+
+public class DetailedChipView extends LinearLayout {
+
+ private static final String TAG = DetailedChipView.class.toString();
+ // context
+ private Context mContext;
+ // xml elements
+ private LinearLayout mContentLayout;
+ private TextView mNameTextView;
+ private TextView mInfoTextView;
+ private ImageButton mDeleteButton;
+ // letter tile provider
+ private static LetterTileProvider mLetterTileProvider;
+ // attributes
+ private ColorStateList mBackgroundColor;
+
+ public DetailedChipView(Context context) {
+ super(context);
+ mContext = context;
+ init(null);
+ }
+
+ public DetailedChipView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ init(attrs);
+ }
+
+ /**
+ * Inflate the view according to attributes
+ *
+ * @param attrs the attributes
+ */
+ private void init(AttributeSet attrs) {
+ // inflate layout
+ View rootView = inflate(getContext(), R.layout.detailed_chip_view, this);
+
+ mContentLayout = (LinearLayout) rootView.findViewById(R.id.content);
+ mNameTextView = (TextView) rootView.findViewById(R.id.name);
+ mInfoTextView = (TextView) rootView.findViewById(R.id.info);
+ mDeleteButton = (ImageButton) rootView.findViewById(R.id.delete_button);
+
+ // letter tile provider
+ mLetterTileProvider = new LetterTileProvider(mContext);
+
+ // hide on first
+ setVisibility(GONE);
+ // hide on touch outside
+ hideOnTouchOutside();
+ }
+
+ /**
+ * Hide the view on touch outside of it
+ */
+ private void hideOnTouchOutside() {
+ // set focusable
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ setClickable(true);
+ }
+
+ /**
+ * Fade in
+ */
+ public void fadeIn() {
+ AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
+ anim.setDuration(200);
+ startAnimation(anim);
+ setVisibility(VISIBLE);
+ // focus on the view
+ requestFocus();
+ }
+
+ /**
+ * Fade out
+ */
+ public void fadeOut() {
+ AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
+ anim.setDuration(200);
+ startAnimation(anim);
+ setVisibility(GONE);
+ // fix onclick issue
+ clearFocus();
+ setClickable(false);
+ }
+
+ public void setName(String name) {
+ mNameTextView.setText(name);
+ }
+
+ public void setInfo(String info) {
+ if(info != null) {
+ mInfoTextView.setVisibility(VISIBLE);
+ mInfoTextView.setText(info);
+ }
+ else {
+ mInfoTextView.setVisibility(GONE);
+ }
+ }
+
+ public void setTextColor(ColorStateList color) {
+ mNameTextView.setTextColor(color);
+ mInfoTextView.setTextColor(ColorUtil.alpha(color.getDefaultColor(), 150));
+ }
+
+ public void setBackGroundcolor(ColorStateList color) {
+ mBackgroundColor = color;
+ mContentLayout.getBackground().setColorFilter(color.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
+ }
+
+ public int getBackgroundColor() {
+ return mBackgroundColor == null ? ContextCompat.getColor(mContext, R.color.colorAccent) : mBackgroundColor.getDefaultColor();
+ }
+
+ public void setDeleteIconColor(ColorStateList color) {
+ mDeleteButton.getDrawable().mutate().setColorFilter(color.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
+ }
+
+ public void setOnDeleteClicked(OnClickListener onClickListener) {
+ mDeleteButton.setOnClickListener(onClickListener);
+ }
+
+ public void alignLeft() {
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mContentLayout.getLayoutParams();
+ params.leftMargin = 0;
+ mContentLayout.setLayoutParams(params);
+ }
+
+ public void alignRight() {
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mContentLayout.getLayoutParams();
+ params.rightMargin = 0;
+ mContentLayout.setLayoutParams(params);
+ }
+
+ public static class Builder {
+ private Context context;
+ private String name;
+ private String info;
+ private ColorStateList textColor;
+ private ColorStateList backgroundColor;
+ private ColorStateList deleteIconColor;
+
+ public Builder(Context context) {
+ this.context = context;
+ }
+
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder info(String info) {
+ this.info = info;
+ return this;
+ }
+
+ public Builder chip(ChipInterface chip) {
+ this.name = chip.getLabel();
+ this.info = chip.getInfo();
+ return this;
+ }
+
+ public Builder textColor(ColorStateList textColor) {
+ this.textColor = textColor;
+ return this;
+ }
+
+ public Builder backgroundColor(ColorStateList backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ return this;
+ }
+
+ public Builder deleteIconColor(ColorStateList deleteIconColor) {
+ this.deleteIconColor = deleteIconColor;
+ return this;
+ }
+
+ public DetailedChipView build() {
+ return DetailedChipView.newInstance(this);
+ }
+ }
+
+ private static DetailedChipView newInstance(Builder builder) {
+ DetailedChipView detailedChipView = new DetailedChipView(builder.context);
+ // avatar
+ // background color
+ if(builder.backgroundColor != null)
+ detailedChipView.setBackGroundcolor(builder.backgroundColor);
+
+ // text color
+ if(builder.textColor != null)
+ detailedChipView.setTextColor(builder.textColor);
+ else if(ColorUtil.isColorDark(detailedChipView.getBackgroundColor()))
+ detailedChipView.setTextColor(ColorStateList.valueOf(Color.WHITE));
+ else
+ detailedChipView.setTextColor(ColorStateList.valueOf(Color.BLACK));
+
+ // delete icon color
+ if(builder.deleteIconColor != null)
+ detailedChipView.setDeleteIconColor(builder.deleteIconColor);
+ else if(ColorUtil.isColorDark(detailedChipView.getBackgroundColor()))
+ detailedChipView.setDeleteIconColor(ColorStateList.valueOf(Color.WHITE));
+ else
+ detailedChipView.setDeleteIconColor(ColorStateList.valueOf(Color.BLACK));
+
+ detailedChipView.setName(builder.name);
+ detailedChipView.setInfo(builder.info);
+ return detailedChipView;
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java
new file mode 100644
index 000000000..ba4034fb7
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/FilterableListView.java
@@ -0,0 +1,156 @@
+package com.pchmn.materialchips.views;
+
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AlphaAnimation;
+import android.widget.Filter;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+import com.pchmn.materialchips.ChipsInput;
+import com.pchmn.materialchips.R;
+import com.pchmn.materialchips.adapter.FilterableAdapter;
+import com.pchmn.materialchips.model.ChipInterface;
+import com.pchmn.materialchips.util.ViewUtil;
+
+import java.util.List;
+
+public class FilterableListView extends RelativeLayout {
+
+ private static final String TAG = FilterableListView.class.toString();
+ private FrameLayout frameLayout;
+ private Context mContext;
+ // list
+ private RecyclerView mRecyclerView;
+ private FilterableAdapter mAdapter;
+ private List extends ChipInterface> mFilterableList;
+ // others
+ private ChipsInput mChipsInput;
+ private ViewGroup rootView;
+
+ public FilterableListView(Context context) {
+ this(context, null);
+ }
+
+ public FilterableListView(Context context, ViewGroup layout) {
+ super(context);
+ this.mContext = context;
+ this.rootView = layout;
+ init();
+ }
+
+ private void init() {
+ // inflate layout
+ View view = inflate(getContext(), R.layout.list_filterable_view, this);
+
+ mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
+
+ // recycler
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
+
+ // hide on first
+ setVisibility(GONE);
+ }
+
+ public void build(List extends ChipInterface> filterableList, ChipsInput chipsInput, ColorStateList backgroundColor, ColorStateList textColor) {
+ mFilterableList = filterableList;
+ mChipsInput = chipsInput;
+
+ // adapter
+ mAdapter = new FilterableAdapter(mContext, mRecyclerView, filterableList, chipsInput, backgroundColor, textColor);
+ mRecyclerView.setAdapter(mAdapter);
+ if(backgroundColor != null)
+ mRecyclerView.getBackground().setColorFilter(backgroundColor.getDefaultColor(), PorterDuff.Mode.SRC_ATOP);
+
+ // listen to change in the tree
+ mChipsInput.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+
+ @Override
+ public void onGlobalLayout() {
+
+ // position
+ if(rootView == null){
+ rootView = (ViewGroup) mChipsInput.getRootView();
+ }
+
+ // size
+ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+ ViewUtil.getWindowWidth(mContext),
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+
+ if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ layoutParams.bottomMargin = ViewUtil.getNavBarHeight(mContext);
+ }
+
+ //If this child view is already added to the parent rootView, then remove it first
+ ViewGroup parent = (ViewGroup) FilterableListView.this.getParent();
+ if (parent != null) {
+ parent.removeView(FilterableListView.this);
+ }
+ // add view
+ rootView.addView(FilterableListView.this, layoutParams);
+
+
+ // remove the listener:
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ mChipsInput.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ } else {
+ mChipsInput.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ }
+
+ });
+ }
+
+ public void filterList(CharSequence text) {
+ mAdapter.getFilter().filter(text, new Filter.FilterListener() {
+ @Override
+ public void onFilterComplete(int count) {
+ // show if there are results
+ if(mAdapter.getItemCount() > 0)
+ fadeIn();
+ else
+ fadeOut();
+ }
+ });
+ }
+
+ /**
+ * Fade in
+ */
+ public void fadeIn() {
+ if(getVisibility() == VISIBLE)
+ return;
+
+ AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
+ anim.setDuration(200);
+ startAnimation(anim);
+ setVisibility(VISIBLE);
+ }
+
+ /**
+ * Fade out
+ */
+ public void fadeOut() {
+ if(getVisibility() == GONE)
+ return;
+
+ AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
+ anim.setDuration(200);
+ startAnimation(anim);
+ setVisibility(GONE);
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ScrollViewMaxHeight.java b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ScrollViewMaxHeight.java
new file mode 100644
index 000000000..db212ff65
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/java/com/pchmn/materialchips/views/ScrollViewMaxHeight.java
@@ -0,0 +1,49 @@
+package com.pchmn.materialchips.views;
+
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.widget.NestedScrollView;
+import android.util.AttributeSet;
+
+import com.pchmn.materialchips.R;
+import com.pchmn.materialchips.util.ViewUtil;
+
+public class ScrollViewMaxHeight extends NestedScrollView {
+
+ private int mMaxHeight;
+ private int mWidthMeasureSpec;
+
+ public ScrollViewMaxHeight(Context context) {
+ super(context);
+ }
+
+ public ScrollViewMaxHeight(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.ScrollViewMaxHeight,
+ 0, 0);
+
+ try {
+ mMaxHeight = a.getDimensionPixelSize(R.styleable.ScrollViewMaxHeight_maxHeight, ViewUtil.dpToPx(300));
+ }
+ finally {
+ a.recycle();
+ }
+ }
+
+ public void setMaxHeight(int height) {
+ mMaxHeight = height;
+ int heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
+ measure(mWidthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mWidthMeasureSpec = widthMeasureSpec;
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/extern/MaterialChipsInput/src/main/res/drawable-v21/ripple_chip_view.xml b/extern/MaterialChipsInput/src/main/res/drawable-v21/ripple_chip_view.xml
new file mode 100644
index 000000000..aea2c3a4f
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable-v21/ripple_chip_view.xml
@@ -0,0 +1,11 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/bg_chip_view.xml b/extern/MaterialChipsInput/src/main/res/drawable/bg_chip_view.xml
new file mode 100644
index 000000000..58b375ecc
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/bg_chip_view.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/bg_chip_view_opened.xml b/extern/MaterialChipsInput/src/main/res/drawable/bg_chip_view_opened.xml
new file mode 100644
index 000000000..69dbc5bde
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/bg_chip_view_opened.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/ic_cancel_grey_24dp.xml b/extern/MaterialChipsInput/src/main/res/drawable/ic_cancel_grey_24dp.xml
new file mode 100644
index 000000000..f9b266324
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/ic_cancel_grey_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/ic_cancel_white_24dp.xml b/extern/MaterialChipsInput/src/main/res/drawable/ic_cancel_white_24dp.xml
new file mode 100644
index 000000000..e6545bf8a
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/ic_cancel_white_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/ic_person_outline_white_24dp.xml b/extern/MaterialChipsInput/src/main/res/drawable/ic_person_outline_white_24dp.xml
new file mode 100644
index 000000000..69453b4e1
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/ic_person_outline_white_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/ic_person_white_24dp.xml b/extern/MaterialChipsInput/src/main/res/drawable/ic_person_white_24dp.xml
new file mode 100644
index 000000000..22ca15668
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/ic_person_white_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/extern/MaterialChipsInput/src/main/res/drawable/ripple_chip_view.xml b/extern/MaterialChipsInput/src/main/res/drawable/ripple_chip_view.xml
new file mode 100644
index 000000000..58b375ecc
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/drawable/ripple_chip_view.xml
@@ -0,0 +1,10 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/layout/chip_view.xml b/extern/MaterialChipsInput/src/main/res/layout/chip_view.xml
new file mode 100644
index 000000000..34e73036c
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/layout/chip_view.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/layout/chips_input.xml b/extern/MaterialChipsInput/src/main/res/layout/chips_input.xml
new file mode 100644
index 000000000..f39d6fc70
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/layout/chips_input.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/layout/detailed_chip_view.xml b/extern/MaterialChipsInput/src/main/res/layout/detailed_chip_view.xml
new file mode 100644
index 000000000..0533d3e5d
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/layout/detailed_chip_view.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/layout/item_list_filterable.xml b/extern/MaterialChipsInput/src/main/res/layout/item_list_filterable.xml
new file mode 100644
index 000000000..6298b696c
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/layout/item_list_filterable.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/layout/list_filterable_view.xml b/extern/MaterialChipsInput/src/main/res/layout/list_filterable_view.xml
new file mode 100644
index 000000000..3dc228971
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/layout/list_filterable_view.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/values/attrs.xml b/extern/MaterialChipsInput/src/main/res/values/attrs.xml
new file mode 100644
index 000000000..ab9511869
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/values/attrs.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/values/colors.xml b/extern/MaterialChipsInput/src/main/res/values/colors.xml
new file mode 100644
index 000000000..9f540beb8
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+
+ #E0E0E0
+ #009688
+ #ababab
+ #b9ffffff
+ ?attr/colorAccent
+
+
\ No newline at end of file
diff --git a/extern/MaterialChipsInput/src/main/res/values/strings.xml b/extern/MaterialChipsInput/src/main/res/values/strings.xml
new file mode 100644
index 000000000..9b3be0701
--- /dev/null
+++ b/extern/MaterialChipsInput/src/main/res/values/strings.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ - #f16364
+ - #f58559
+ - #f9a43e
+ - #e4c62e
+ - #67bf74
+ - #59a2be
+ - #2093cd
+ - #ad62a7
+
+
+
+ 17sp
+
+ 32dp
+
+
diff --git a/extern/MaterialChipsInput/src/test/java/com/pchmn/materialchips/ExampleUnitTest.java b/extern/MaterialChipsInput/src/test/java/com/pchmn/materialchips/ExampleUnitTest.java
new file mode 100644
index 000000000..b68d97902
--- /dev/null
+++ b/extern/MaterialChipsInput/src/test/java/com/pchmn/materialchips/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.pchmn.materialchips;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 7c3b44eab..01b3c106c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,6 +4,7 @@ include ':extern:bouncycastle:core'
include ':extern:bouncycastle:pg'
include ':extern:bouncycastle:prov'
include ':extern:minidns'
+include ':extern:MaterialChipsInput:library'
// Workaround for Android Gradle Plugin 2.0, as described in http://stackoverflow.com/a/36544850
//include ':libkeychain'