jenkins-bot has submitted this change and it was merged. Change subject: Tweak title pronunciation icon appearance ......................................................................
Tweak title pronunciation icon appearance * Reduce the size of the icon[0] and increase the hit area. * Seperate the view and collision concerns. [0] https://veuwer.com/i/3e7s,3e7t Bug: T114524 Change-Id: I5d506c96069584bc861441fd6612e04d17d58067 --- M app/src/main/java/org/wikipedia/richtext/AudioUrlSpan.java M app/src/main/java/org/wikipedia/richtext/ClickSpan.java A app/src/main/java/org/wikipedia/richtext/DefaultClickSpan.java M app/src/main/java/org/wikipedia/richtext/DrawableSpan.java M app/src/main/java/org/wikipedia/richtext/TextViewSpanOnTouchListener.java M app/src/main/res/values/dimens.xml 6 files changed, 170 insertions(+), 68 deletions(-) Approvals: Dbrant: Looks good to me, approved jenkins-bot: Verified diff --git a/app/src/main/java/org/wikipedia/richtext/AudioUrlSpan.java b/app/src/main/java/org/wikipedia/richtext/AudioUrlSpan.java index b7ec392..35c0972 100644 --- a/app/src/main/java/org/wikipedia/richtext/AudioUrlSpan.java +++ b/app/src/main/java/org/wikipedia/richtext/AudioUrlSpan.java @@ -1,7 +1,11 @@ package org.wikipedia.richtext; import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.graphics.drawable.LevelListDrawable; import android.support.annotation.ColorInt; @@ -18,6 +22,7 @@ import org.wikipedia.media.AvPlayer; public class AudioUrlSpan extends AnimatedImageSpan implements ClickSpan { + private static final int STOP_ICON_LEVEL = 0; private static final int PLAY_ICON_LEVEL = 1; @@ -30,6 +35,9 @@ @NonNull private final String path; + @NonNull + private final DefaultClickSpan clickSpan; + public AudioUrlSpan(@NonNull View view, @NonNull AvPlayer player, @NonNull String path, @@ -37,6 +45,7 @@ super(view, drawable(view.getContext()), verticalAlignment); this.player = player; this.path = path; + clickSpan = clickSpan(view.getResources()); } public void setTint(@ColorInt int color) { @@ -44,8 +53,13 @@ } @Override - public void onClick(TextView textView) { + public void onClick(@NonNull TextView textView) { toggle(); + } + + @Override + public boolean contains(@NonNull PointF point) { + return clickSpan.contains(point); } @Override @@ -74,6 +88,28 @@ return super.getDrawable(); } + @Override + @SuppressWarnings("checkstyle:parameternumber") + public void draw(Canvas canvas, + CharSequence text, + int start, + int end, + float x, + int top, + int y, + int bottom, + Paint paint) { + super.draw(canvas, text, start, end, x, top, y, bottom, paint); + + clickSpan.setOriginX(x + getDrawable().getBounds().centerX()); + clickSpan.setOriginY(drawY(y, bottom) + getDrawable().getBounds().centerY()); + + final boolean debugClickBounds = false; + if (debugClickBounds) { + clickSpan.draw(canvas); + } + } + private void showIcon(int level) { getDrawable().setLevel(level); } @@ -82,23 +118,37 @@ return getDrawable().getLevel(); } + @NonNull private static Drawable drawable(Context context) { LevelListDrawable levels = new AppLevelListDrawable(); levels.addLevel(PLAY_ICON_LEVEL, PLAY_ICON_LEVEL, spinnerDrawable(context)); levels.addLevel(STOP_ICON_LEVEL, STOP_ICON_LEVEL, speakerDrawable(context)); + int radius = getDimensionPixelSize(context, R.dimen.audio_url_span_loading_spinner_radius); + levels.setBounds(0, 0, radius * 2, radius * 2); return levels; } + @NonNull private static Drawable speakerDrawable(Context context) { return getDrawable(context, R.drawable.ic_volume_up_black_24dp); } + @NonNull private static Drawable spinnerDrawable(Context context) { return new CircularProgressDrawable(Color.WHITE, getDimensionPixelSize(context, R.dimen.audio_url_span_loading_spinner_border_thickness), getDimensionPixelSize(context, R.dimen.audio_url_span_loading_spinner_radius)); } + @NonNull + private DefaultClickSpan clickSpan(Resources resources) { + DefaultClickSpan span = new DefaultClickSpan(); + float leg = resources.getDimension(R.dimen.audio_url_span_click_size); + span.setWidth(leg); + span.setHeight(leg); + return span; + } + private static Drawable getDrawable(Context context, @DrawableRes int id) { return context.getResources().getDrawable(id); } diff --git a/app/src/main/java/org/wikipedia/richtext/ClickSpan.java b/app/src/main/java/org/wikipedia/richtext/ClickSpan.java index e47cbe4..d0ea480 100644 --- a/app/src/main/java/org/wikipedia/richtext/ClickSpan.java +++ b/app/src/main/java/org/wikipedia/richtext/ClickSpan.java @@ -1,7 +1,11 @@ package org.wikipedia.richtext; +import android.graphics.PointF; +import android.support.annotation.NonNull; import android.widget.TextView; public interface ClickSpan { - void onClick(TextView textView); + void onClick(@NonNull TextView textView); + /** @param point Click coordinates relative the host View. */ + boolean contains(@NonNull PointF point); } \ No newline at end of file diff --git a/app/src/main/java/org/wikipedia/richtext/DefaultClickSpan.java b/app/src/main/java/org/wikipedia/richtext/DefaultClickSpan.java new file mode 100644 index 0000000..cfa6990 --- /dev/null +++ b/app/src/main/java/org/wikipedia/richtext/DefaultClickSpan.java @@ -0,0 +1,65 @@ +package org.wikipedia.richtext; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.support.annotation.NonNull; +import android.widget.TextView; + +public class DefaultClickSpan implements ClickSpan { + // The click collision area relative the host View with origin at centerpoint. + @NonNull + private final RectF bounds = new RectF(); + + /** @param x Icon origin x coordinate relative the host View. */ + public void setOriginX(float x) { + setOrigin(x, bounds.centerY()); + } + + /** @param y Icon origin y coordinate relative the host View. */ + public void setOriginY(float y) { + setOrigin(bounds.centerX(), y); + } + + public void setOrigin(float x, float y) { + bounds.offset(x - bounds.centerX(), y - bounds.centerY()); + } + + public void setWidth(float width) { + setRect(width, bounds.height()); + } + + public void setHeight(float height) { + setRect(bounds.width(), height); + } + + public void setRect(float width, float height) { + float x = bounds.centerX(); + float y = bounds.centerY(); + + float a = width / 2; + float b = height / 2; + bounds.set(-a, -b, a, b); + + setOrigin(x, y); + } + + public void draw(Canvas canvas) { + Paint debugPaint = new Paint(); + debugPaint.setStyle(Paint.Style.STROKE); + debugPaint.setColor(Color.RED); + + canvas.drawRect(bounds, debugPaint); + } + + @Override + public void onClick(@NonNull TextView textView) { + } + + @Override + public boolean contains(@NonNull PointF point) { + return bounds.contains(point.x, point.y); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/wikipedia/richtext/DrawableSpan.java b/app/src/main/java/org/wikipedia/richtext/DrawableSpan.java index 206fa71..8f56804 100644 --- a/app/src/main/java/org/wikipedia/richtext/DrawableSpan.java +++ b/app/src/main/java/org/wikipedia/richtext/DrawableSpan.java @@ -82,22 +82,15 @@ float x, int top, int y, - int bottom, Paint paint) { + int bottom, + Paint paint) { if (drawable == null) { return; } canvas.save(); - int transY; - if (mVerticalAlignment == ALIGN_BOTTOM) { - transY = bottom; - } else { - transY = y; - } - transY -= drawable.getBounds().bottom; - - canvas.translate(x, transY); + canvas.translate(x, drawY(y, bottom)); drawable.draw(canvas); canvas.restore(); } @@ -112,6 +105,17 @@ } } + protected int drawY(int y, int bottom) { + int ret; + if (mVerticalAlignment == ALIGN_BASELINE) { + ret = y; + } else { + ret = bottom; + } + ret -= drawable == null ? 0 : drawable.getBounds().bottom; + return ret; + } + private void init() { // super.getDrawable() is convoluted: // * May return an original or a new Drawable; does not keep a reference in the latter diff --git a/app/src/main/java/org/wikipedia/richtext/TextViewSpanOnTouchListener.java b/app/src/main/java/org/wikipedia/richtext/TextViewSpanOnTouchListener.java index e40604f..1a2bc67 100644 --- a/app/src/main/java/org/wikipedia/richtext/TextViewSpanOnTouchListener.java +++ b/app/src/main/java/org/wikipedia/richtext/TextViewSpanOnTouchListener.java @@ -1,13 +1,15 @@ package org.wikipedia.richtext; -import android.graphics.Rect; +import android.graphics.PointF; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.Layout; import android.text.Spanned; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; public class TextViewSpanOnTouchListener implements View.OnTouchListener { @NonNull private TextView textView; @@ -18,53 +20,51 @@ @Override public boolean onTouch(View view, MotionEvent event) { - ClickSpan span = getSpanned() == null ? null : getEventClickSpan(getSpanned(), event); - if (span == null) { + List<ClickSpan> contains = getSpanned() == null + ? null + : filterContains(allClickSpans(getSpanned()), getEventPoint(event)); + if (contains == null || contains.isEmpty()) { return false; } + int action = event.getAction(); if (action == MotionEvent.ACTION_UP) { - span.onClick(textView); + for (ClickSpan span : contains) { + span.onClick(textView); + } } return action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN; } - @Nullable - private ClickSpan getEventClickSpan(@NonNull Spanned spanned, @NonNull MotionEvent event) { - return getEventSpan(spanned, event, ClickSpan.class); - } - - @Nullable - private <T> T getEventSpan(@NonNull Spanned spanned, - @NonNull MotionEvent event, - @NonNull Class<T> clazz) { - Integer offset = getEventCharacterOffset(event); - if (offset == null) { - return null; + @NonNull + private List<ClickSpan> filterContains(@NonNull ClickSpan[] spans, @NonNull PointF point) { + List<ClickSpan> contains = new ArrayList<>(); + for (ClickSpan span : spans) { + if (span.contains(point)) { + contains.add(span); + } } - - T[] spans = spanned.getSpans(offset, offset, clazz); - return spans.length > 0 ? spans[0] : null; + return contains; } - @Nullable - private Integer getEventCharacterOffset(@NonNull MotionEvent event) { - int x = getEventX(event); - int y = getEventY(event); - int line = getLineOffset(y); - - Rect bounds = getLineBounds(line); - return bounds.contains(x, y) ? getCharacterOffset(line, x) : null; + @NonNull + private ClickSpan[] allClickSpans(Spanned spanned) { + return spanned.getSpans(0, spanned.length(), ClickSpan.class); } - private int getEventX(@NonNull MotionEvent event) { - return Math.round(event.getX()) - getTotalPaddingLeft() + getScrollX(); + @NonNull + private PointF getEventPoint(@NonNull MotionEvent event) { + return new PointF(getEventX(event), getEventY(event)); } - private int getEventY(@NonNull MotionEvent event) { - return Math.round(event.getY()) - getTotalPaddingTop() + getScrollY(); + private float getEventX(@NonNull MotionEvent event) { + return event.getX() - getTotalPaddingLeft() + getScrollX(); + } + + private float getEventY(@NonNull MotionEvent event) { + return event.getY() - getTotalPaddingTop() + getScrollY(); } @Nullable @@ -74,28 +74,6 @@ private CharSequence getText() { return textView.getText(); - } - - private Rect getLineBounds(int line) { - Rect bounds = new Rect(); - getLayout().getLineBounds(line, bounds); - // Left and right are set to the bounds of the TextView, not the bounds of the line. See - // Layout.getLineBounds. - bounds.left = Math.round(getLayout().getLineLeft(line)); - bounds.right = Math.round(getLayout().getLineRight(line)); - return bounds; - } - - private int getCharacterOffset(int line, int x) { - return getLayout().getOffsetForHorizontal(line, x); - } - - private int getLineOffset(int y) { - return getLayout().getLineForVertical(y); - } - - private Layout getLayout() { - return textView.getLayout(); } private int getScrollX() { diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index a32ffaa..6b580c1 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -70,8 +70,9 @@ <item name="lead_subtitle_leading_scalar" format="float" type="dimen">1.35</item> <item name="lead_subtitle_paragraph_scalar" format="float" type="dimen">1.15</item> - <dimen name="audio_url_span_loading_spinner_border_thickness">3dp</dimen> - <dimen name="audio_url_span_loading_spinner_radius">12dp</dimen> + <dimen name="audio_url_span_loading_spinner_border_thickness">2dp</dimen> + <dimen name="audio_url_span_loading_spinner_radius">8dp</dimen> + <dimen name="audio_url_span_click_size">48dp</dimen> <!-- Maps --> <integer name="map_default_zoom">12</integer> -- To view, visit https://gerrit.wikimedia.org/r/255057 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I5d506c96069584bc861441fd6612e04d17d58067 Gerrit-PatchSet: 4 Gerrit-Project: apps/android/wikipedia Gerrit-Branch: master Gerrit-Owner: Niedzielski <[email protected]> Gerrit-Reviewer: BearND <[email protected]> Gerrit-Reviewer: Brion VIBBER <[email protected]> Gerrit-Reviewer: Dbrant <[email protected]> Gerrit-Reviewer: Mholloway <[email protected]> Gerrit-Reviewer: Niedzielski <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
