/** * Wire * Copyright (C) 2016 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.waz.zclient.pages.main.pickuser; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.text.TextPaint; import android.text.TextUtils; import com.waz.zclient.R; import com.waz.zclient.ui.utils.MathUtils; import com.waz.zclient.ui.utils.TypefaceUtils; import com.waz.zclient.ui.text.SpannableEditText; public class UserTokenSpan extends SpannableEditText.TokenSpan { private final String userId; private final String userName; private final String deleteIconString; private int lineWidth; private float spanWidth; private Rect textBounds; private float textWidth; private Rect deleteIconBounds; private int paddingHorizontal; private int paddingRightFix; private int textOffsetTop; private int spaceForCursor; private float backgroundRadius; private float backgroundHeight; private float backgroundBottomPadding; // When true, shows cross button and truncates text private boolean deleteMode; // make clickable area slightly bigger than delete button private TextPaint textPaint; private TextPaint deleteModeTextPaint; private Paint backgroundPaint; public UserTokenSpan(String userId, String userName, Context context, boolean deleteMode, int lineWidth) { this.userId = userId; this.userName = userName; this.deleteMode = deleteMode; this.lineWidth = lineWidth; paddingHorizontal = context.getResources().getDimensionPixelSize(R.dimen.people_picker__input_person_token__padding_horizontal); paddingRightFix = context.getResources().getDimensionPixelSize(R.dimen.people_picker__input_person_token__padding_right_fix); textOffsetTop = 0; spaceForCursor = context.getResources().getDimensionPixelSize(R.dimen.people_picker__input_person_token__extra_space_for_cursor); backgroundHeight = context.getResources().getDimensionPixelSize(R.dimen.wire__padding__16); backgroundBottomPadding = context.getResources().getDimensionPixelSize(R.dimen.wire__padding__4); backgroundRadius = backgroundBottomPadding + backgroundHeight / 2; int tokenBackgroundColor; int textColor; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { //noinspection deprecation tokenBackgroundColor = context.getResources().getColor(R.color.people_picker__input_person_token__background_color); //noinspection deprecation textColor = context.getResources().getColor(R.color.text__primary_light); } else { tokenBackgroundColor = context.getResources().getColor(R.color.people_picker__input_person_token__background_color, context.getTheme()); textColor = context.getResources().getColor(R.color.text__primary_light, context.getTheme()); } int textSize = context.getResources().getDimensionPixelSize(R.dimen.wire__text_size__regular); // Paints textPaint = new TextPaint(); textPaint.setAntiAlias(true); textPaint.setColor(textColor); textPaint.setTextSize(textSize); textPaint.setTypeface(TypefaceUtils.getTypeface(context.getResources().getString(R.string.wire__typeface__regular))); deleteModeTextPaint = new TextPaint(); deleteModeTextPaint.setAntiAlias(true); deleteModeTextPaint.setColor(tokenBackgroundColor); deleteModeTextPaint.setTextSize(textSize); deleteModeTextPaint.setTypeface(TypefaceUtils.getTypeface(context.getResources().getString(R.string.wire__typeface__light))); backgroundPaint = new Paint(); backgroundPaint.setColor(Color.WHITE); backgroundPaint.setAntiAlias(true); // Measure bounds of text and delete icon textBounds = new Rect(); textPaint.getTextBounds(userName, 0, userName.length(), textBounds); textWidth = textPaint.measureText(userName, 0, userName.length()); deleteIconString = context.getResources().getString(R.string.glyph__close); deleteIconBounds = new Rect(); textPaint.getTextBounds(deleteIconString, 0, 1, deleteIconBounds); } public void setTextColor(int textColor) { textPaint.setColor(textColor); } public void setDeleteModeTextColor(int color) { deleteModeTextPaint.setColor(color); } @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { float textPosX = x + paddingHorizontal; float textPosY = y + textOffsetTop; CharSequence truncatedText = TextUtils.ellipsize(userName, textPaint, availableTextSpace(), TextUtils.TruncateAt.END); canvas.drawRoundRect( new RectF(textPosX - paddingHorizontal, textPosY - backgroundHeight, textPosX + textBounds.width() + paddingHorizontal, textPosY + backgroundBottomPadding), backgroundRadius, backgroundRadius, backgroundPaint); if (deleteMode) { canvas.drawText(truncatedText.toString(), textPosX, textPosY, deleteModeTextPaint); } else { canvas.drawText(truncatedText.toString(), textPosX, textPosY, textPaint); } } @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { if (MathUtils.floatEqual(spanWidth, 0f)) { spanWidth = tokenWidth(); } return (int) spanWidth; } public String getId() { return userId; } public String getText() { return userName; } public Boolean getDeleteMode() { return deleteMode; } public void setDeleteMode(boolean deleteMode) { this.deleteMode = deleteMode; } /** * @param clickPosition X position of click inside this span * @return Returns true if this span was clicked */ public Boolean spanClicked(int clickPosition) { return clickPosition <= spanWidth; } private float tokenWidth() { float tokenWidth = textWidth + 2 * paddingHorizontal + paddingRightFix; // Ensure token fits into one line float totalWidth = tokenWidth; if (totalWidth > lineWidth) { tokenWidth = lineWidth - spaceForCursor; } return tokenWidth; } private float availableTextSpace() { return tokenWidth() - 2 * paddingHorizontal - paddingRightFix; } }