<commit_before>package com.btmura.android.reddit.widget;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.BoringLayout;
import android.text.Layout;
import android.text.Layout.Alignment;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;

import com.btmura.android.reddit.BuildConfig;
import com.btmura.android.reddit.R;
import com.btmura.android.reddit.accounts.AccountUtils;
import com.btmura.android.reddit.database.Things;
import com.btmura.android.reddit.text.Formatter;
import com.btmura.android.reddit.text.RelativeTime;

public class ThingView extends CustomView implements OnGestureListener {

    public static final String TAG = "ThingView";

    private static final Formatter FORMATTER = new Formatter();

    private final GestureDetector detector;
    private OnVoteListener listener;

    private int kind;
    private int likes;
    private String linkTitle;
    private int thingBodyWidth;
    private String thumbnailUrl;
    private String thingId;
    private String title;

    private Bitmap bitmap;
    private boolean drawVotingArrows;
    private boolean drawScore;

    private CharSequence bodyText;
    private String scoreText;
    private final SpannableStringBuilder statusText = new SpannableStringBuilder();
    private final SpannableStringBuilder longDetailsText = new SpannableStringBuilder();
    private String shortDetailsText;

    private Layout linkTitleLayout;
    private Layout titleLayout;
    private Layout bodyLayout;
    private Layout statusLayout;
    private Layout detailsLayout;

    private Rect scoreBounds;
    private RectF bodyBounds;
    private int rightHeight;
    private int minHeight;

    public ThingView(Context context) {
        this(context, null);
    }

    public ThingView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ThingView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        detector = new GestureDetector(context, this);
        init(context);
    }

    private void init(Context context) {
        VotingArrows.init(context);
        Thumbnail.init(context);
    }

    public void setOnVoteListener(OnVoteListener listener) {
        this.listener = listener;
    }

    public void setThumbnailBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        invalidate();
    }

    public void setData(String accountName,
            String author,
            String body,
            long createdUtc,
            String domain,
            int downs,
            int kind,
            int likes,
            String linkTitle,
            long nowTimeMs,
            int numComments,
            boolean over18,
            String parentSubreddit,
            int score,
            String subreddit,
            int thingBodyWidth,
            String thingId,
            String thumbnailUrl,
            String title,
            int ups) {
        this.kind = kind;
        this.likes = likes;
        this.linkTitle = linkTitle;
        this.thingBodyWidth = thingBodyWidth;
        this.thingId = thingId;
        this.thumbnailUrl = thumbnailUrl;
        this.title = title;

        drawVotingArrows = AccountUtils.isAccount(accountName);
        drawScore = drawVotingArrows && kind == Things.KIND_LINK;
        if (drawScore) {
            if (scoreBounds == null) {
                scoreBounds = new Rect();
            }
            scoreText = VotingArrows.getScoreText(score);
        }

        setStatusText(author, createdUtc, kind, nowTimeMs, numComments, over18,
                parentSubreddit, score, subreddit, drawVotingArrows);
        setDetailsText(domain, downs, ups);

        if (!TextUtils.isEmpty(body)) {
            bodyText = FORMATTER.formatSpans(getContext(), body);
            if (bodyBounds == null) {
                bodyBounds = new RectF();
            }
        } else {
            bodyText = null;
        }

        requestLayout();
    }

    private void setStatusText(String author, long createdUtc, int kind, long nowTimeMs,
            int numComments, boolean over18, String parentSubreddit, int score, String subreddit,
            boolean votable) {
        Context c = getContext();
        Resources r = getResources();

        statusText.clear();
        statusText.clearSpans();

        if (over18) {
            String nsfw = c.getString(R.string.nsfw);
            statusText.append(nsfw).append("  ");
            statusText.setSpan(new ForegroundColorSpan(Color.RED), 0, nsfw.length(), 0);
        }

        if (!subreddit.equalsIgnoreCase(parentSubreddit)) {
            statusText.append(subreddit).append("  ");
        }

        statusText.append(author).append("  ");

        if (!votable) {
            statusText.append(r.getQuantityString(R.plurals.points, score, score)).append("  ");
        }

        statusText.append(RelativeTime.format(c, nowTimeMs, createdUtc)).append("  ");

        if (kind == Things.KIND_LINK) {
            statusText.append(r.getQuantityString(R.plurals.comments, numComments, numComments));
        }
    }

    private void setDetailsText(String domain, int downs, int ups) {
        Resources r = getResources();

        longDetailsText.clear();
        longDetailsText.append(r.getQuantityString(R.plurals.votes_up, ups, ups))
                .append("  ");
        longDetailsText.append(r.getQuantityString(R.plurals.votes_down, downs, downs))
                .append("  ");

        if (!TextUtils.isEmpty(domain)) {
            longDetailsText.append(domain);
            shortDetailsText = domain;
        } else {
            shortDetailsText = "";
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredWidth = 0;
        int measuredHeight = 0;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (widthMode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                measuredWidth = widthSize;
                break;

            case MeasureSpec.UNSPECIFIED:
                measuredWidth = getSuggestedMinimumWidth();
                break;
        }


        int linkTitleWidth;
        int titleWidth;
        int detailsWidth;
        CharSequence detailsText;

        if (thingBodyWidth > 0) {
            linkTitleWidth = titleWidth = Math.min(measuredWidth, thingBodyWidth) - PADDING * 2;
            int remainingWidth = measuredWidth - thingBodyWidth - PADDING * 2;<commit_msg>Issue #86: fix some rendering issues for messages<commit_after>package com.btmura.android.reddit.widget;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.BoringLayout;
import android.text.Layout;
import android.text.Layout.Alignment;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;

import com.btmura.android.reddit.BuildConfig;
import com.btmura.android.reddit.R;
import com.btmura.android.reddit.accounts.AccountUtils;
import com.btmura.android.reddit.database.Things;
import com.btmura.android.reddit.text.Formatter;
import com.btmura.android.reddit.text.RelativeTime;

public class ThingView extends CustomView implements OnGestureListener {

    public static final String TAG = "ThingView";

    private static final Formatter FORMATTER = new Formatter();

    private final GestureDetector detector;
    private OnVoteListener listener;

    private int kind;
    private int likes;
    private String linkTitle;
    private int thingBodyWidth;
    private String thumbnailUrl;
    private String thingId;
    private String title;

    private Bitmap bitmap;
    private boolean drawVotingArrows;
    private boolean drawScore;

    private CharSequence bodyText;
    private String scoreText;
    private final SpannableStringBuilder statusText = new SpannableStringBuilder();
    private final SpannableStringBuilder longDetailsText = new SpannableStringBuilder();
    private String shortDetailsText;

    private Layout linkTitleLayout;
    private Layout titleLayout;
    private Layout bodyLayout;
    private Layout statusLayout;
    private Layout detailsLayout;

    private Rect scoreBounds;
    private RectF bodyBounds;
    private int rightHeight;
    private int minHeight;

    public ThingView(Context context) {
        this(context, null);
    }

    public ThingView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ThingView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        detector = new GestureDetector(context, this);
        init(context);
    }

    private void init(Context context) {
        VotingArrows.init(context);
        Thumbnail.init(context);
    }

    public void setOnVoteListener(OnVoteListener listener) {
        this.listener = listener;
    }

    public void setThumbnailBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        invalidate();
    }

    public void setData(String accountName,
            String author,
            String body,
            long createdUtc,
            String domain,
            int downs,
            int kind,
            int likes,
            String linkTitle,
            long nowTimeMs,
            int numComments,
            boolean over18,
            String parentSubreddit,
            int score,
            String subreddit,
            int thingBodyWidth,
            String thingId,
            String thumbnailUrl,
            String title,
            int ups) {
        this.kind = kind;
        this.likes = likes;
        this.linkTitle = linkTitle;
        this.thingBodyWidth = thingBodyWidth;
        this.thingId = thingId;
        this.thumbnailUrl = thumbnailUrl;
        this.title = title;

        drawVotingArrows = AccountUtils.isAccount(accountName) && kind != Things.KIND_MESSAGE;
        drawScore = drawVotingArrows && kind == Things.KIND_LINK;
        if (drawScore) {
            if (scoreBounds == null) {
                scoreBounds = new Rect();
            }
            scoreText = VotingArrows.getScoreText(score);
        }

        boolean showSubreddit = !TextUtils.isEmpty(subreddit)
                && !subreddit.equalsIgnoreCase(parentSubreddit);
        boolean showPoints = !drawVotingArrows && kind != Things.KIND_MESSAGE;
        boolean showNumComments = kind == Things.KIND_LINK;
        setStatusText(over18, showSubreddit, showPoints, showNumComments,
                author, createdUtc, nowTimeMs, numComments, score, subreddit);
        setDetailsText(showPoints, domain, downs, ups);

        if (!TextUtils.isEmpty(body)) {
            bodyText = FORMATTER.formatSpans(getContext(), body);
            if (bodyBounds == null) {
                bodyBounds = new RectF();
            }
        } else {
            bodyText = null;
        }

        requestLayout();
    }

    private void setStatusText(boolean showNsfw, boolean showSubreddit, boolean showPoints,
            boolean showNumComments, String author, long createdUtc, long nowTimeMs,
            int numComments, int score, String subreddit) {
        Context c = getContext();
        Resources r = getResources();

        statusText.clear();
        statusText.clearSpans();

        if (showNsfw) {
            String nsfw = c.getString(R.string.nsfw);
            statusText.append(nsfw).append("  ");
            statusText.setSpan(new ForegroundColorSpan(Color.RED), 0, nsfw.length(), 0);
        }

        if (showSubreddit) {
            statusText.append(subreddit).append("  ");
        }

        statusText.append(author).append("  ");

        if (showPoints) {
            statusText.append(r.getQuantityString(R.plurals.points, score, score)).append("  ");
        }

        statusText.append(RelativeTime.format(c, nowTimeMs, createdUtc)).append("  ");

        if (showNumComments) {
            statusText.append(r.getQuantityString(R.plurals.comments, numComments, numComments));
        }
    }

    private void setDetailsText(boolean showPoints, String domain, int downs, int ups) {
        Resources r = getResources();

        if (showPoints) {
            longDetailsText.clear();
            longDetailsText.append(r.getQuantityString(R.plurals.votes_up, ups, ups))
                    .append("  ");
            longDetailsText.append(r.getQuantityString(R.plurals.votes_down, downs, downs))
                    .append("  ");
        }

        if (!TextUtils.isEmpty(domain)) {
            longDetailsText.append(domain);
            shortDetailsText = domain;
        } else {
            shortDetailsText = "";
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredWidth = 0;
        int measuredHeight = 0;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (widthMode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                measuredWidth = widthSize;
                break;

            case MeasureSpec.UNSPECIFIED:
                measuredWidth = getSuggestedMinimumWidth();
                break;
        }

        int linkTitleWidth;
        int titleWidth;
        int detailsWidth;
        CharSequence detailsText;

        if (thingBodyWidth > 0) {
            linkTitleWidth = titleWidth = Math.min(measuredWidth, thingBodyWidth) - PADDING * 2;
            int remainingWidth = measuredWidth - thingBodyWidth - PADDING * 2;
{'fraction_non_alphanumeric': 0.08484438430311231, 'fraction_numerical': 0.0020297699594046007, 'mean_word_length': 2.4951525183258454, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2397451', 'n_tokens_mistral': 4071, 'n_tokens_neox': 3918, 'n_words': 929}