From 727dec85037410b0c5ea2be8c82d84d55a18623e Mon Sep 17 00:00:00 2001 From: Urob Oros Date: Thu, 12 Oct 2017 22:24:28 -0500 Subject: [PATCH 1/2] Modified by Gagan Singh on 8/20/2017. Added Phone Number as alternate contact information. Developer can decide between phone and email. Added Google's LetterTileDrawable to change the color of a contact chip based on the contact's ID. --- build.gradle | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- library/build.gradle | 8 +- .../com/doodle/android/chips/ChipsView.java | 102 +++++++- .../doodle/android/chips/model/Contact.java | 53 ++++- .../com/doodle/android/chips/util/Common.java | 8 + .../chips/util/LetterTileDrawable.java | 225 ++++++++++++++++++ library/src/main/res/drawable/circle.xml | 2 +- library/src/main/res/drawable/ic_person.xml | 9 + library/src/main/res/values/colors.xml | 50 ++++ library/src/main/res/values/dimens.xml | 1 + sample/build.gradle | 2 +- .../android/chips/sample/MainActivity.java | 4 +- 13 files changed, 439 insertions(+), 33 deletions(-) create mode 100644 library/src/main/java/com/doodle/android/chips/util/LetterTileDrawable.java create mode 100644 library/src/main/res/drawable/ic_person.xml diff --git a/build.gradle b/build.gradle index e941383..d67a7f7 100644 --- a/build.gradle +++ b/build.gradle @@ -2,9 +2,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.0.0-beta7' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' } } @@ -12,6 +13,7 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aae88a7..8b43897 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Feb 27 11:21:31 CET 2017 +#Wed Sep 06 13:43:21 CDT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/library/build.gradle b/library/build.gradle index eff03f5..0903d1e 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -2,22 +2,22 @@ apply plugin: 'com.android.library' android { compileSdkVersion 25 - buildToolsVersion "25.0.2" - + buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 16 targetSdkVersion 25 versionCode 4 - versionName "1.2.0" + versionName '1.3.0' setProperty("archivesBaseName", "android-material-chips-$versionName") } - buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + productFlavors { + } } dependencies { diff --git a/library/src/main/java/com/doodle/android/chips/ChipsView.java b/library/src/main/java/com/doodle/android/chips/ChipsView.java index 19b9217..033cae2 100644 --- a/library/src/main/java/com/doodle/android/chips/ChipsView.java +++ b/library/src/main/java/com/doodle/android/chips/ChipsView.java @@ -23,6 +23,7 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Build; @@ -54,6 +55,7 @@ import com.doodle.android.chips.model.Contact; import com.doodle.android.chips.util.Common; +import com.doodle.android.chips.util.LetterTileDrawable; import com.doodle.android.chips.views.ChipsEditText; import com.doodle.android.chips.views.ChipsVerticalLinearLayout; import com.squareup.picasso.Callback; @@ -63,6 +65,11 @@ import java.util.Collections; import java.util.List; +/** + * Modified by Gagan Singh on 8/20/2017. + * Added Phone Number as alternate contact information, developer can decide between phone and email. + * Added Google's LetterTileDrawable to change the color of a contact chip based on an algorithm. + */ public class ChipsView extends ScrollView implements ChipsEditText.InputConnectionWrapperInterface { // @@ -94,6 +101,7 @@ public class ChipsView extends ScrollView implements ChipsEditText.InputConnecti private int mChipsTextColorClicked; private int mChipsTextColorErrorClicked; private int mChipsPlaceholderResId; + private int mChipsWhitePlaceholderResId; private @ColorInt int mChipsPlaceholderTint; @@ -114,6 +122,7 @@ public class ChipsView extends ScrollView implements ChipsEditText.InputConnecti private Object mCurrentEditTextSpan; private ChipValidator mChipsValidator; private Typeface mTypeface; + private LetterTileDrawable letterTitleDrawable; // initials private boolean mUseInitials = false; @@ -126,17 +135,20 @@ public class ChipsView extends ScrollView implements ChipsEditText.InputConnecti // public ChipsView(Context context) { super(context); + letterTitleDrawable = new LetterTileDrawable(getContext().getResources()); init(); } public ChipsView(Context context, AttributeSet attrs) { super(context, attrs); + letterTitleDrawable = new LetterTileDrawable(getContext().getResources()); initAttr(context, attrs); init(); } public ChipsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + letterTitleDrawable = new LetterTileDrawable(getContext().getResources()); initAttr(context, attrs); init(); } @@ -144,6 +156,7 @@ public ChipsView(Context context, AttributeSet attrs, int defStyleAttr) { @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ChipsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + letterTitleDrawable = new LetterTileDrawable(getContext().getResources()); initAttr(context, attrs); init(); } @@ -151,7 +164,7 @@ public ChipsView(Context context, AttributeSet attrs, int defStyleAttr, int defS @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if(mMaxHeight != DEFAULT_MAX_HEIGHT) { + if (mMaxHeight != DEFAULT_MAX_HEIGHT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -183,6 +196,7 @@ private void initAttr(Context context, AttributeSet attrs) { mChipsTextColorErrorClicked = a.getColor(R.styleable.ChipsView_cv_text_color_clicked, Color.WHITE); mChipsTextColorIndelible = a.getColor(R.styleable.ChipsView_cv_text_color_indelible, mChipsTextColor); mChipsPlaceholderResId = a.getResourceId(R.styleable.ChipsView_cv_icon_placeholder, R.drawable.ic_person_24dp); + mChipsWhitePlaceholderResId = a.getResourceId(R.styleable.ChipsView_cv_icon_placeholder, R.drawable.ic_person); mChipsPlaceholderTint = a.getColor(R.styleable.ChipsView_cv_icon_placeholder_tint, 0); mChipsDeleteResId = a.getResourceId(R.styleable.ChipsView_cv_icon_delete, R.drawable.ic_close_24dp); mChipsHintText = a.getString(R.styleable.ChipsView_cv_text_hint); @@ -236,11 +250,11 @@ private void init() { editModeLinLayout.setOrientation(LinearLayout.HORIZONTAL); mChipsContainer.addView(editModeLinLayout); - View view = new Chip("Test Chip", null, new Contact(null, null, "Test", "asd@asd.de", null)).getView(); + View view = new Chip("Test Chip", null, new Contact(null, null, null, "Test", Contact.ContactType.EMAIL, "asd@asd.de", null)).getView(); view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); editModeLinLayout.addView(view); - View view2 = new Chip("Indelible", null, new Contact(null, null, "Test", "asd@asd.de", null), true).getView(); + View view2 = new Chip("Indelible", null, new Contact(null, null, null, "Test", Contact.ContactType.PHONE, "asd@asd.de", null), true).getView(); view2.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); editModeLinLayout.addView(view2); } @@ -327,11 +341,33 @@ public List getChips() { return Collections.unmodifiableList(mChipList); } + public void clearAllChips() { + mChipList.clear(); + if (mChipList.isEmpty()) { + mEditText.setHint(mChipsHintText); + } + onChipsChanged(true); + } + public boolean removeChipBy(Contact contact) { for (int i = 0; i < mChipList.size(); i++) { if (mChipList.get(i).mContact != null && mChipList.get(i).mContact.equals(contact)) { mChipList.remove(i); - if(mChipList.isEmpty()) { + if (mChipList.isEmpty()) { + mEditText.setHint(mChipsHintText); + } + onChipsChanged(true); + return true; + } + } + return false; + } + + public boolean removeChipBy(String id) { + for (int i = 0; i < mChipList.size(); i++) { + if (mChipList.get(i).mContact != null && mChipList.get(i).mContact.getId().equals(id)) { + mChipList.remove(i); + if (mChipList.isEmpty()) { mEditText.setHint(mChipsHintText); } onChipsChanged(true); @@ -345,7 +381,9 @@ public Contact tryToRecognizeAddress() { String text = mEditText.getText().toString(); if (!TextUtils.isEmpty(text)) { if (Common.isValidEmail(text)) { - return new Contact(text, "", null, text, null); + return new Contact(null, text, "", null, Contact.ContactType.EMAIL, text, null); + } else if (Common.isValidEmail(text)) { + return new Contact(null, text, "", null, Contact.ContactType.PHONE, text, null); } } return null; @@ -365,6 +403,7 @@ public EditText getEditText() { // // + /** * rebuild all chips and place them right */ @@ -421,9 +460,12 @@ private boolean onEnterPressed(String text) { if (Common.isValidEmail(text)) { onEmailRecognized(text); + } else if (Common.isValidPhone(text)) { + onPhoneRecognized(text); } else { shouldDeleteText = onNonEmailRecognized(text); } + if (shouldDeleteText) { mEditText.setSelection(0); } @@ -432,7 +474,7 @@ private boolean onEnterPressed(String text) { } private void onEmailRecognized(String email) { - onEmailRecognized(new Contact(email, "", null, email, null)); + onEmailRecognized(new Contact(null, email, "", null, Contact.ContactType.EMAIL, email, null)); } private void onEmailRecognized(Contact contact) { @@ -449,6 +491,24 @@ public void run() { }); } + private void onPhoneRecognized(String phone) { + onPhoneRecognized(new Contact(null, phone, "", null, Contact.ContactType.PHONE, phone, null)); + } + + private void onPhoneRecognized(Contact contact) { + Chip chip = new Chip(contact.getDisplayName(), null, contact); + mChipList.add(chip); + if (mChipsListener != null) { + mChipsListener.onChipAdded(chip); + } + post(new Runnable() { + @Override + public void run() { + onChipsChanged(true); + } + }); + } + private boolean onNonEmailRecognized(String text) { if (mChipsListener != null) { return mChipsListener.onInputNotRecognized(text); @@ -482,7 +542,7 @@ private void onChipInteraction(Chip chip, boolean nameClicked) { } onChipsChanged(true); if (nameClicked) { - mEditText.setText(chip.getContact().getEmailAddress()); + mEditText.setText(chip.getContact().getContactInfo()); addLeadingMarginSpan(); mEditText.requestFocus(); mEditText.setSelection(mEditText.length()); @@ -636,7 +696,7 @@ public Chip(String label, Uri photoUri, Contact contact, boolean isIndelible) { this.mIsIndelible = isIndelible; if (mLabel == null) { - mLabel = contact.getEmailAddress(); + mLabel = contact.getContactInfo(); } if (mLabel.length() > MAX_LABEL_LENGTH) { @@ -672,7 +732,15 @@ public View getView() { } else { ((GradientDrawable) mView.getBackground()).setColor(mChipsBgColor); } - mIconWrapper.setBackgroundResource(R.drawable.circle); + try { + mIconWrapper.setBackgroundResource(R.drawable.circle); + if (mContact.getId() != null) { + mIconWrapper.getBackground().setColorFilter(letterTitleDrawable.pickColor(mContact.getId()), PorterDuff.Mode.SRC_ATOP); + } else { + mIconWrapper.getBackground().setColorFilter(mChipsColor, PorterDuff.Mode.SRC_ATOP); + } + } catch (Exception e) {} + if (mIsIndelible) { mTextView.setTextColor(mChipsTextColorIndelible); } else { @@ -680,7 +748,12 @@ public View getView() { } // set icon resources - mPersonIcon.setImageResource(mChipsPlaceholderResId); + if (mContact.getId() == null) { + mPersonIcon.setImageResource(mChipsPlaceholderResId); + } else { + mPersonIcon.setImageResource(mChipsWhitePlaceholderResId); + } + if (mChipsPlaceholderTint != 0) { mPersonIcon.setColorFilter(mChipsPlaceholderTint, PorterDuff.Mode.SRC_ATOP); } @@ -770,7 +843,14 @@ public void onError() { ((GradientDrawable) mView.getBackground()).setColor(mChipsBgColor); mTextView.setTextColor(mChipsTextColor); } - mIconWrapper.getBackground().setColorFilter(mChipsColor, PorterDuff.Mode.SRC_ATOP); + + try { + if (mContact.getId() != null) { + mIconWrapper.getBackground().setColorFilter(letterTitleDrawable.pickColor(mContact.getId()), PorterDuff.Mode.SRC_ATOP); + } else { + mIconWrapper.getBackground().setColorFilter(mChipsColor, PorterDuff.Mode.SRC_ATOP); + } + }catch(Exception e){} if (mUseInitials) { mInitials.animate().alpha(1f).setDuration(200).setStartDelay(100).start(); diff --git a/library/src/main/java/com/doodle/android/chips/model/Contact.java b/library/src/main/java/com/doodle/android/chips/model/Contact.java index 989912f..27d23af 100644 --- a/library/src/main/java/com/doodle/android/chips/model/Contact.java +++ b/library/src/main/java/com/doodle/android/chips/model/Contact.java @@ -23,16 +23,33 @@ import java.io.Serializable; +/** + * Modified by Gagan Singh on 8/20/2017. + * Added optional ID property. When contacts are retrieved from the device, + * pass the ID from the user's contact into this contact object to set the color of the chip. + * Added ContactType and Phone Number for alternate contact information, developer can decide between phone and email. + */ public class Contact implements Comparable, Serializable { + @Nullable + private final String mId; + @Nullable private final String mFirstName; @Nullable private final String mLastName; + public enum ContactType { + EMAIL, + PHONE, + } + + @NonNull + private ContactType mContactType; + @NonNull - private final String mEmailAddress; + private final String mContactInfo; @Nullable private transient final Uri mAvatarUri; @@ -43,17 +60,20 @@ public class Contact implements Comparable, Serializable { @NonNull private final String mInitials; - public Contact(@Nullable String firstName, @Nullable String lastName, @Nullable String displayName, @NonNull String emailAddress, @Nullable Uri avatarUri) { + public Contact(@Nullable String id, @Nullable String firstName, @Nullable String lastName, @Nullable String displayName, + @NonNull ContactType contactType, @NonNull String contactInfo, @Nullable Uri avatarUri) { + mId = id; mFirstName = firstName; mLastName = lastName; mAvatarUri = avatarUri; - mEmailAddress = emailAddress; + mContactType = contactType; + mContactInfo = contactInfo; if (!TextUtils.isEmpty(displayName)) { mDisplayName = displayName; } else if (TextUtils.isEmpty(mFirstName)) { if (TextUtils.isEmpty(mLastName)) { - mDisplayName = mEmailAddress; + mDisplayName = contactInfo; } else { mDisplayName = mLastName; } @@ -73,6 +93,11 @@ public Contact(@Nullable String firstName, @Nullable String lastName, @Nullable mInitials = initialsBuilder.toString(); } + @Nullable + public String getId() { + return mId; + } + @Nullable public String getFirstName() { return mFirstName; @@ -84,8 +109,13 @@ public String getLastName() { } @NonNull - public String getEmailAddress() { - return mEmailAddress; + public ContactType getContactType() { + return mContactType; + } + + @NonNull + public String getContactInfo() { + return mContactInfo; } @Nullable @@ -149,7 +179,7 @@ public int compareTo(final Contact another) { } } - return mEmailAddress.compareTo(another.mEmailAddress); + return mContactInfo.compareTo(another.mContactInfo); } private int compare(String myString, String otherString) { @@ -171,7 +201,7 @@ public boolean matches(CharSequence searchString) { String lowerCaseSearchString = searchString.toString().toLowerCase(); return (mFirstName != null && mFirstName.toLowerCase().contains(lowerCaseSearchString)) || (mLastName != null && mLastName.toLowerCase().contains(lowerCaseSearchString)) || - mEmailAddress.toLowerCase().contains(lowerCaseSearchString); + mContactInfo.toLowerCase().contains(lowerCaseSearchString); } @@ -182,14 +212,14 @@ public boolean equals(final Object o) { Contact contact = (Contact) o; - if (!mEmailAddress.equals(contact.mEmailAddress)) return false; + if (!mContactInfo.equals(contact.mContactInfo)) return false; return true; } @Override public int hashCode() { - return mEmailAddress.hashCode(); + return mContactInfo.hashCode(); } @Override @@ -197,7 +227,8 @@ public String toString() { return "Contact{" + "mFirstName='" + mFirstName + '\'' + ", mLastName='" + mLastName + '\'' + - ", mEmailAddress='" + mEmailAddress + '\'' + + ", mContactType='" + mContactType + '\'' + + ", mContactInfo='" + mContactInfo + '\'' + ", mAvatarUri=" + mAvatarUri + ", mDisplayName='" + mDisplayName + '\'' + ", mInitials='" + mInitials + '\'' + diff --git a/library/src/main/java/com/doodle/android/chips/util/Common.java b/library/src/main/java/com/doodle/android/chips/util/Common.java index 9e0c14d..a6c65bb 100644 --- a/library/src/main/java/com/doodle/android/chips/util/Common.java +++ b/library/src/main/java/com/doodle/android/chips/util/Common.java @@ -23,4 +23,12 @@ public class Common { public static boolean isValidEmail(CharSequence target) { return !TextUtils.isEmpty(target) && android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches(); } + + /** + * Added by Gagan Singh on 8/20/2017. + * Used to validate phone number. + */ + public static boolean isValidPhone(CharSequence target) { + return !TextUtils.isEmpty(target) && android.util.Patterns.PHONE.matcher(target).matches(); + } } diff --git a/library/src/main/java/com/doodle/android/chips/util/LetterTileDrawable.java b/library/src/main/java/com/doodle/android/chips/util/LetterTileDrawable.java new file mode 100644 index 0000000..8d2acf1 --- /dev/null +++ b/library/src/main/java/com/doodle/android/chips/util/LetterTileDrawable.java @@ -0,0 +1,225 @@ +package com.doodle.android.chips.util; + +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.ColorFilter; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +//import com.google.common.base.Preconditions; +import com.doodle.android.chips.R; + +/** + * Added by Gagan Singh on 8/20/2017. + * Originally created by Google + */ + +/** + * A drawable that encapsulates all the functionality needed to display a letter tile to + * represent a contact image. + */ +public class LetterTileDrawable extends Drawable { + private final String TAG = LetterTileDrawable.class.getSimpleName(); + private final Paint mPaint; + /** Letter tile */ + private static TypedArray sColors; + private static int sDefaultColor; + private static int sTileFontColor; + private static float sLetterToTileRatio; + private static Bitmap DEFAULT_PERSON_AVATAR; + private static Bitmap DEFAULT_BUSINESS_AVATAR; + private static Bitmap DEFAULT_VOICEMAIL_AVATAR; + /** Reusable components to avoid new allocations */ + private static final Paint sPaint = new Paint(); + private static final Rect sRect = new Rect(); + private static final char[] sFirstChar = new char[1]; + /** Contact type constants */ + public static final int TYPE_PERSON = 1; + public static final int TYPE_BUSINESS = 2; + public static final int TYPE_VOICEMAIL = 3; + public static final int TYPE_DEFAULT = TYPE_PERSON; + private int mContactType = TYPE_DEFAULT; + private float mScale = 1.0f; + private float mOffset = 0.0f; + private boolean mIsCircle = false; + private int mColor; + private Character mLetter = null; + public LetterTileDrawable(final Resources res) { + if (sColors == null) { + sColors = res.obtainTypedArray(R.array.letter_tile_colors); + sDefaultColor = res.getColor(R.color.letter_tile_default_color); + sTileFontColor = res.getColor(R.color.letter_tile_font_color); + sLetterToTileRatio = res.getFraction(R.fraction.letter_to_tile_ratio, 1, 1); + DEFAULT_PERSON_AVATAR = BitmapFactory.decodeResource(res, + R.drawable.ic_person); + sPaint.setTextAlign(Align.CENTER); + sPaint.setAntiAlias(true); + } + mPaint = new Paint(); + mPaint.setFilterBitmap(true); + mPaint.setDither(true); + mColor = sDefaultColor; + } + @Override + public void draw(final Canvas canvas) { + final Rect bounds = getBounds(); + if (!isVisible() || bounds.isEmpty()) { + return; + } + // Draw letter tile. + drawLetterTile(canvas); + } + /** + * Draw the bitmap onto the canvas at the current bounds taking into account the current scale. + */ + private void drawBitmap(final Bitmap bitmap, final int width, final int height, + final Canvas canvas) { + // The bitmap should be drawn in the middle of the canvas without changing its width to + // height ratio. + final Rect destRect = copyBounds(); + // Crop the destination bounds into a square, scaled and offset as appropriate + final int halfLength = (int) (mScale * Math.min(destRect.width(), destRect.height()) / 2); + destRect.set(destRect.centerX() - halfLength, + (int) (destRect.centerY() - halfLength + mOffset * destRect.height()), + destRect.centerX() + halfLength, + (int) (destRect.centerY() + halfLength + mOffset * destRect.height())); + // Source rectangle remains the entire bounds of the source bitmap. + sRect.set(0, 0, width, height); + canvas.drawBitmap(bitmap, sRect, destRect, mPaint); + } + private void drawLetterTile(final Canvas canvas) { + // Draw background color. + sPaint.setColor(mColor); + sPaint.setAlpha(mPaint.getAlpha()); + final Rect bounds = getBounds(); + final int minDimension = Math.min(bounds.width(), bounds.height()); + if (mIsCircle) { + canvas.drawCircle(bounds.centerX(), bounds.centerY(), minDimension / 2, sPaint); + } else { + canvas.drawRect(bounds, sPaint); + } + // Draw letter/digit only if the first character is an english letter or there's a override + if (mLetter != null) { + // Draw letter or digit. + sFirstChar[0] = mLetter; + // Scale text by canvas bounds and user selected scaling factor + sPaint.setTextSize(mScale * sLetterToTileRatio * minDimension); + //sPaint.setTextSize(sTileLetterFontSize); + sPaint.getTextBounds(sFirstChar, 0, 1, sRect); + sPaint.setColor(sTileFontColor); + // Draw the letter in the canvas, vertically shifted up or down by the user-defined + // offset + canvas.drawText(sFirstChar, 0, 1, bounds.centerX(), + bounds.centerY() + mOffset * bounds.height() - sRect.exactCenterY(), + sPaint); + } else { + // Draw the default image if there is no letter/digit to be drawn + final Bitmap bitmap = getBitmapForContactType(mContactType); + drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), + canvas); + } + } + public int getColor() { + return mColor; + } + /** + * Returns a deterministic color based on the provided contact identifier string. + */ + public int pickColor(final String identifier) { + if (TextUtils.isEmpty(identifier) || mContactType == TYPE_VOICEMAIL) { + return sDefaultColor; + } + // String.hashCode() implementation is not supposed to change across java versions, so + // this should guarantee the same email address always maps to the same color. + // The email should already have been normalized by the ContactRequest. + final int color = Math.abs(identifier.hashCode()) % sColors.length(); + return sColors.getColor(color, sDefaultColor); + } + private static Bitmap getBitmapForContactType(int contactType) { + switch (contactType) { + case TYPE_PERSON: + return DEFAULT_PERSON_AVATAR; + case TYPE_BUSINESS: + return DEFAULT_BUSINESS_AVATAR; + case TYPE_VOICEMAIL: + return DEFAULT_VOICEMAIL_AVATAR; + default: + return DEFAULT_PERSON_AVATAR; + } + } + private static boolean isEnglishLetter(final char c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); + } + @Override + public void setAlpha(final int alpha) { + mPaint.setAlpha(alpha); + } + @Override + public void setColorFilter(final ColorFilter cf) { + mPaint.setColorFilter(cf); + } + @Override + public int getOpacity() { + return android.graphics.PixelFormat.OPAQUE; + } + /** + * Scale the drawn letter tile to a ratio of its default size + * + * @param scale The ratio the letter tile should be scaled to as a percentage of its default + * size, from a scale of 0 to 2.0f. The default is 1.0f. + */ + public LetterTileDrawable setScale(float scale) { + mScale = scale; + return this; + } + /** + * Assigns the vertical offset of the position of the letter tile to the ContactDrawable + * + * @param offset The provided offset must be within the range of -0.5f to 0.5f. + * If set to -0.5f, the letter will be shifted upwards by 0.5 times the height of the canvas + * it is being drawn on, which means it will be drawn with the center of the letter starting + * at the top edge of the canvas. + * If set to 0.5f, the letter will be shifted downwards by 0.5 times the height of the canvas + * it is being drawn on, which means it will be drawn with the center of the letter starting + * at the bottom edge of the canvas. + * The default is 0.0f. + */ + public LetterTileDrawable setOffset(float offset) { +// Preconditions.checkArgument(offset >= -0.5f && offset <= 0.5f); + mOffset = offset; + return this; + } + public LetterTileDrawable setLetter(Character letter){ + mLetter = letter; + return this; + } + public LetterTileDrawable setColor(int color){ + mColor = color; + return this; + } + public LetterTileDrawable setLetterAndColorFromContactDetails(final String displayName, + final String identifier) { + if (displayName != null && displayName.length() > 0 + && isEnglishLetter(displayName.charAt(0))) { + mLetter = Character.toUpperCase(displayName.charAt(0)); + }else{ + mLetter = null; + } + mColor = pickColor(identifier); + return this; + } + public LetterTileDrawable setContactType(int contactType) { + mContactType = contactType; + return this; + } + public LetterTileDrawable setIsCircular(boolean isCircle) { + mIsCircle = isCircle; + return this; + } +} diff --git a/library/src/main/res/drawable/circle.xml b/library/src/main/res/drawable/circle.xml index 04883c3..90a1c31 100644 --- a/library/src/main/res/drawable/circle.xml +++ b/library/src/main/res/drawable/circle.xml @@ -2,6 +2,6 @@ - + \ No newline at end of file diff --git a/library/src/main/res/drawable/ic_person.xml b/library/src/main/res/drawable/ic_person.xml new file mode 100644 index 0000000..fb5b1fd --- /dev/null +++ b/library/src/main/res/drawable/ic_person.xml @@ -0,0 +1,9 @@ + + + diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml index f817a43..9644ea9 100644 --- a/library/src/main/res/values/colors.xml +++ b/library/src/main/res/values/colors.xml @@ -13,5 +13,55 @@ #eaeaea #c1c1c1 + #FFFFFFFF + + + + #DB4437 + #E91E63 + #9C27B0 + #673AB7 + #3F51B5 + #4285F4 + #039BE5 + #0097A7 + #009688 + #0F9D58 + #689F38 + #EF6C00 + #FF5722 + #757575 + + + + #C53929 + #C2185B + #7B1FA2 + #512DA8 + #303F9F + #3367D6 + #0277BD + #006064 + #00796B + #0B8043 + #33691E + #E65100 + #E64A19 + #424242 + + + #607D8B + + #455A64 + #cccccc + #ffffff diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml index 812cb7b..4c32713 100644 --- a/library/src/main/res/values/dimens.xml +++ b/library/src/main/res/values/dimens.xml @@ -3,4 +3,5 @@ 16dp 16dp 16dp + 67% diff --git a/sample/build.gradle b/sample/build.gradle index a5be44b..d56f5a1 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 25 - buildToolsVersion "25.0.2" + buildToolsVersion '26.0.2' defaultConfig { applicationId "com.doodle.android.chips.sample" diff --git a/sample/src/main/java/com/doodle/android/chips/sample/MainActivity.java b/sample/src/main/java/com/doodle/android/chips/sample/MainActivity.java index 5fc0b43..6f94828 100644 --- a/sample/src/main/java/com/doodle/android/chips/sample/MainActivity.java +++ b/sample/src/main/java/com/doodle/android/chips/sample/MainActivity.java @@ -109,7 +109,7 @@ public boolean onInputNotRecognized(String text) { chipsEmailDialogFragment.setEmailListener(new ChipsEmailDialogFragment.EmailListener() { @Override public void onDialogEmailEntered(String text, String displayName) { - mChipsView.addChip(displayName, null, new Contact(null, null, displayName, text, null), false); + mChipsView.addChip(displayName, null, new Contact(null, null, null, displayName, Contact.ContactType.EMAIL, text, null), false); mChipsView.clearText(); } }); @@ -198,7 +198,7 @@ public void onClick(View v) { public void onClick(View v) { String email = name.getText().toString(); Uri imgUrl = Math.random() > .7d ? null : Uri.parse("https://robohash.org/" + Math.abs(email.hashCode())); - Contact contact = new Contact(null, null, null, email, imgUrl); + Contact contact = new Contact(null, null, null, null, Contact.ContactType.EMAIL, email, imgUrl); if (selection.isChecked()) { boolean indelibe = Math.random() > 0.8f; From 63641a4c61ad486bc68d7a7416260148d0329725 Mon Sep 17 00:00:00 2001 From: Urob Oros Date: Thu, 12 Oct 2017 22:32:02 -0500 Subject: [PATCH 2/2] Modified by Gagan Singh on 8/20/2017. Added Phone Number as alternate contact information. Developer can decide between phone and email. Added Google's LetterTileDrawable to change the color of a contact chip based on the contact's ID. --- library/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/build.gradle b/library/build.gradle index 0903d1e..83862e5 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -7,7 +7,7 @@ android { minSdkVersion 16 targetSdkVersion 25 versionCode 4 - versionName '1.3.0' + versionName '1.4.0' setProperty("archivesBaseName", "android-material-chips-$versionName") } buildTypes {