package me.ccrama.redditslide.Views; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Typeface; import android.os.AsyncTask; import android.support.v7.widget.AppCompatCheckBox; import android.text.Html; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import com.devspark.robototextview.util.RobotoTypefaceManager; import net.dean.jraw.models.Account; import net.dean.jraw.models.Comment; import net.dean.jraw.models.Submission; import net.dean.jraw.models.Subreddit; import net.dean.jraw.models.VoteDirection; import java.util.Arrays; import java.util.List; import java.util.Locale; import me.ccrama.redditslide.ActionStates; import me.ccrama.redditslide.Adapters.ProfileCommentViewHolder; import me.ccrama.redditslide.Adapters.SubmissionViewHolder; import me.ccrama.redditslide.Authentication; import me.ccrama.redditslide.ForceTouch.PeekViewActivity; import me.ccrama.redditslide.OpenRedditLink; import me.ccrama.redditslide.R; import me.ccrama.redditslide.Reddit; import me.ccrama.redditslide.SettingValues; import me.ccrama.redditslide.SpoilerRobotoTextView; import me.ccrama.redditslide.SubmissionViews.PopulateSubmissionViewHolder; import me.ccrama.redditslide.TimeUtils; import me.ccrama.redditslide.UserSubscriptions; import me.ccrama.redditslide.Visuals.FontPreferences; import me.ccrama.redditslide.Visuals.Palette; import me.ccrama.redditslide.util.LogUtil; import me.ccrama.redditslide.util.SubmissionParser; /** * Created by ccrama on 3/5/2015. */ public class RedditItemView extends RelativeLayout { OpenRedditLink.RedditLinkType contentType; public RedditItemView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public RedditItemView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RedditItemView(Context context) { super(context); init(); } public void loadUrl(PeekMediaView v, String url, ProgressBar progress) { this.progress = progress; url = OpenRedditLink.formatRedditUrl(url); if (url.isEmpty()) { v.doLoadLink(url); } else if (url.startsWith("np")) { url = url.substring(2); } String[] parts = url.split("/"); if (parts[parts.length - 1].startsWith("?")) parts = Arrays.copyOf(parts, parts.length - 1); contentType = OpenRedditLink.getRedditLinkType(url); switch (contentType) { case SHORTENED: { new AsyncLoadSubmission(parts[1]).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } case LIVE: { v.doLoadLink(url); } break; case WIKI: { v.doLoadLink(url); break; } case SEARCH: { v.doLoadLink(url); break; } case COMMENT_PERMALINK: { String submission = parts[4]; if (parts.length >= 7) { //is likely a comment String end = parts[6]; if (end.contains("?")) end = end.substring(0, end.indexOf("?")); if (end.length() >= 3) { new AsyncLoadComment(end).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { new AsyncLoadSubmission(submission).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } else { new AsyncLoadSubmission(submission).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } break; } case SUBMISSION: { new AsyncLoadSubmission(parts[4]).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } case SUBMISSION_WITHOUT_SUB: { new AsyncLoadSubmission(parts[2]).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } case SUBREDDIT: { new AsyncLoadSubreddit(parts[2]).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } case USER: { String name = parts[2]; new AsyncLoadProfile(name).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } case OTHER: { v.doLoadLink(url); break; } } } ProgressBar progress; public class AsyncLoadProfile extends AsyncTask<Void, Void, Account> { String id; public AsyncLoadProfile(String profileName) { this.id = profileName; } @Override protected Account doInBackground(Void... params) { return Authentication.reddit.getUser(id); } @Override protected void onPostExecute(Account account) { if (account != null) { View content = LayoutInflater.from(getContext()) .inflate(R.layout.account_pop, RedditItemView.this, false); RelativeLayout.LayoutParams params = (LayoutParams) content.getLayoutParams(); params.addRule(CENTER_IN_PARENT); addView(content); doUser(account, content); } if (progress != null) { progress.setVisibility(GONE); } } } private void doUser(Account account, View content) { String name = account.getFullName(); final TextView title = (TextView) content.findViewById(R.id.title); title.setText(name); final int currentColor = Palette.getColorUser(name); title.setBackgroundColor(currentColor); String info = getContext().getString(R.string.profile_age, TimeUtils.getTimeSince(account.getCreated().getTime(), getContext())); ((TextView) content.findViewById(R.id.moreinfo)).setText(info); ((TextView) content.findViewById(R.id.commentkarma)).setText( String.format(Locale.getDefault(), "%d", account.getCommentKarma())); ((TextView) content.findViewById(R.id.linkkarma)).setText( String.format(Locale.getDefault(), "%d", account.getLinkKarma())); } public class AsyncLoadSubreddit extends AsyncTask<Void, Void, Subreddit> { String id; public AsyncLoadSubreddit(String subredditName) { this.id = subredditName; } @Override protected Subreddit doInBackground(Void... params) { try { return Authentication.reddit.getSubreddit(id); } catch (Exception e) { return null; } } @Override protected void onPostExecute(Subreddit subreddit) { if (subreddit != null) { View content = LayoutInflater.from(getContext()) .inflate(R.layout.subreddit_pop, RedditItemView.this, false); RelativeLayout.LayoutParams params = (LayoutParams) content.getLayoutParams(); params.addRule(CENTER_IN_PARENT); addView(content); doSidebar(subreddit, content); } if (progress != null) { progress.setVisibility(GONE); } } } private void doSidebar(Subreddit subreddit, View content) { if ((!Authentication.isLoggedIn && UserSubscriptions.getSubscriptions(getContext()) .contains(subreddit.getDisplayName().toLowerCase())) || (Authentication.isLoggedIn && subreddit.isUserSubscriber())) { ((AppCompatCheckBox) content.findViewById(R.id.subscribed)).setChecked(true); } content.findViewById(R.id.header_sub) .setBackgroundColor(Palette.getColor(subreddit.getDisplayName())); ((TextView) content.findViewById(R.id.sub_infotitle)).setText(subreddit.getDisplayName()); if (!subreddit.getPublicDescription().isEmpty()) { content.findViewById(R.id.sub_title).setVisibility(View.VISIBLE); setViews(subreddit.getDataNode().get("public_description_html").asText(), subreddit.getDisplayName().toLowerCase(), ((SpoilerRobotoTextView) content.findViewById(R.id.sub_title)), (CommentOverflow) content.findViewById(R.id.sub_title_overflow)); } else { content.findViewById(R.id.sub_title).setVisibility(View.GONE); } if (subreddit.getDataNode().has("icon_img") && !subreddit.getDataNode() .get("icon_img") .asText() .isEmpty()) { ((Reddit) ((PeekViewActivity) getContext()).getApplication()).getImageLoader() .displayImage(subreddit.getDataNode().get("icon_img").asText(), (ImageView) content.findViewById(R.id.subimage)); } else { content.findViewById(R.id.subimage).setVisibility(View.GONE); } ((TextView) content.findViewById(R.id.subscribers)).setText( getContext().getString(R.string.subreddit_subscribers_string, subreddit.getLocalizedSubscriberCount())); content.findViewById(R.id.subscribers).setVisibility(View.VISIBLE); ((TextView) content.findViewById(R.id.active_users)).setText( getContext().getString(R.string.subreddit_active_users_string_new, subreddit.getLocalizedAccountsActive())); content.findViewById(R.id.active_users).setVisibility(View.VISIBLE); } public class AsyncLoadComment extends AsyncTask<Void, Void, Comment> { String id; public AsyncLoadComment(String commentId) { this.id = commentId; } @Override protected Comment doInBackground(Void... params) { return (Comment) Authentication.reddit.get("t1_" + id).get(0); } @Override protected void onPostExecute(Comment comment) { if (comment != null) { LogUtil.v("Adding view"); View content = LayoutInflater.from(getContext()) .inflate(R.layout.profile_comment, RedditItemView.this, false); RelativeLayout.LayoutParams params = (LayoutParams) content.getLayoutParams(); params.addRule(CENTER_IN_PARENT); addView(content); doComment(comment, content); } if (progress != null) { progress.setVisibility(GONE); } } } public class AsyncLoadSubmission extends AsyncTask<Void, Void, Submission> { String id; public AsyncLoadSubmission(String submissionId) { this.id = submissionId; } @Override protected Submission doInBackground(Void... params) { return Authentication.reddit.getSubmission(id); } @Override protected void onPostExecute(Submission submission) { if (submission != null) { View content = CreateCardView.CreateView(RedditItemView.this); RelativeLayout.LayoutParams params = (LayoutParams) content.getLayoutParams(); params.addRule(CENTER_IN_PARENT); addView(content); doSubmission(submission, content); } if (progress != null) { progress.setVisibility(GONE); }} } public void doComment(Comment comment, View content) { ProfileCommentViewHolder holder = new ProfileCommentViewHolder(content); String scoreText; if (comment.isScoreHidden()) { scoreText = "[" + getContext().getString(R.string.misc_score_hidden).toUpperCase() + "]"; } else { scoreText = String.format(Locale.getDefault(), "%d", comment.getScore()); } SpannableStringBuilder score = new SpannableStringBuilder(scoreText); if (score == null || score.toString().isEmpty()) { score = new SpannableStringBuilder("0"); } if (!scoreText.contains("[")) { score.append(String.format(Locale.getDefault(), " %s", getContext().getResources() .getQuantityString(R.plurals.points, comment.getScore()))); } holder.score.setText(score); if (Authentication.isLoggedIn) { if (ActionStates.getVoteDirection(comment) == VoteDirection.UPVOTE) { holder.score.setTextColor( getContext().getResources().getColor(R.color.md_orange_500)); } else if (ActionStates.getVoteDirection(comment) == VoteDirection.DOWNVOTE) { holder.score.setTextColor( getContext().getResources().getColor(R.color.md_blue_500)); } else { holder.score.setTextColor(holder.time.getCurrentTextColor()); } } String spacer = getContext().getString(R.string.submission_properties_seperator); SpannableStringBuilder titleString = new SpannableStringBuilder(); String timeAgo = TimeUtils.getTimeAgo(comment.getCreated().getTime(), getContext()); String time = ((timeAgo == null || timeAgo.isEmpty()) ? "just now" : timeAgo); //some users were crashing here time = time + (((comment.getEditDate() != null) ? " (edit " + TimeUtils.getTimeAgo( comment.getEditDate().getTime(), getContext()) + ")" : "")); titleString.append(time); titleString.append(spacer); if (comment.getSubredditName() != null) { String subname = comment.getSubredditName(); SpannableStringBuilder subreddit = new SpannableStringBuilder("/r/" + subname); if ((SettingValues.colorSubName && Palette.getColor(subname) != Palette.getDefaultColor())) { subreddit.setSpan(new ForegroundColorSpan(Palette.getColor(subname)), 0, subreddit.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); subreddit.setSpan(new StyleSpan(Typeface.BOLD), 0, subreddit.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } titleString.append(subreddit); } holder.time.setText(titleString); setViews(comment.getDataNode().get("body_html").asText(), comment.getSubredditName(), holder); int type = new FontPreferences(getContext()).getFontTypeComment().getTypeface(); Typeface typeface; if (type >= 0) { typeface = RobotoTypefaceManager.obtainTypeface(getContext(), type); } else { typeface = Typeface.DEFAULT; } holder.content.setTypeface(typeface); if (comment.getTimesGilded() > 0) { final String timesGilded = (comment.getTimesGilded() == 1) ? "" : "\u200Ax" + Integer.toString(comment.getTimesGilded()); SpannableStringBuilder gilded = new SpannableStringBuilder("\u00A0★" + timesGilded + "\u00A0"); TypedArray a = getContext().obtainStyledAttributes( new FontPreferences(getContext()).getPostFontStyle().getResId(), R.styleable.FontStyle); int fontsize = (int) (a.getDimensionPixelSize(R.styleable.FontStyle_font_cardtitle, -1) * .75); a.recycle(); Bitmap image = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.gold); float aspectRatio = (float) (1.00 * image.getWidth() / image.getHeight()); image = Bitmap.createScaledBitmap(image, (int) Math.ceil(fontsize * aspectRatio), (int) Math.ceil(fontsize), true); gilded.setSpan(new ImageSpan(getContext(), image, ImageSpan.ALIGN_BASELINE), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); gilded.setSpan(new RelativeSizeSpan(0.75f), 3, gilded.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); holder.gild.setVisibility(View.VISIBLE); ((TextView) holder.gild).setText(gilded); } else if (holder.gild.getVisibility() == View.VISIBLE) { holder.gild.setVisibility(View.GONE); } if (comment.getSubmissionTitle() != null) { holder.title.setText(Html.fromHtml(comment.getSubmissionTitle())); } else { holder.title.setText(Html.fromHtml(comment.getAuthor())); } } public void doSubmission(Submission submission, View content) { final SubmissionViewHolder holder = new SubmissionViewHolder(content); CreateCardView.resetColorCard(holder.itemView); if (submission.getSubredditName() != null) { CreateCardView.colorCard(submission.getSubredditName().toLowerCase(), holder.itemView, "no_subreddit", false); } new PopulateSubmissionViewHolder().populateSubmissionViewHolder(holder, submission, ((PeekViewActivity) getContext()), false, false, null, null, false, false, null, null); } private void init() { } private void setViews(String rawHTML, String subreddit, SpoilerRobotoTextView firstTextView, CommentOverflow commentOverflow) { if (rawHTML.isEmpty()) { return; } List<String> blocks = SubmissionParser.getBlocks(rawHTML); int startIndex = 0; // the <div class="md"> case is when the body contains a table or code block first if (!blocks.get(0).equals("<div class=\"md\">")) { firstTextView.setVisibility(View.VISIBLE); firstTextView.setTextHtml(blocks.get(0), subreddit); startIndex = 1; } else { firstTextView.setText(""); firstTextView.setVisibility(View.GONE); } if (blocks.size() > 1) { if (startIndex == 0) { commentOverflow.setViews(blocks, subreddit); } else { commentOverflow.setViews(blocks.subList(startIndex, blocks.size()), subreddit); } SidebarLayout sidebar = (SidebarLayout) findViewById(R.id.drawer_layout); for (int i = 0; i < commentOverflow.getChildCount(); i++) { View maybeScrollable = commentOverflow.getChildAt(i); if (maybeScrollable instanceof HorizontalScrollView) { sidebar.addScrollable(maybeScrollable); } } } else { commentOverflow.removeAllViews(); } } private void setViews(String rawHTML, String subredditName, ProfileCommentViewHolder holder) { if (rawHTML.isEmpty()) { return; } List<String> blocks = SubmissionParser.getBlocks(rawHTML); int startIndex = 0; // the <div class="md"> case is when the body contains a table or code block first if (!blocks.get(0).equals("<div class=\"md\">")) { holder.content.setVisibility(View.VISIBLE); holder.content.setTextHtml(blocks.get(0), subredditName); startIndex = 1; } else { holder.content.setText(""); holder.content.setVisibility(View.GONE); } if (blocks.size() > 1) { if (startIndex == 0) { holder.overflow.setViews(blocks, subredditName); } else { holder.overflow.setViews(blocks.subList(startIndex, blocks.size()), subredditName); } } else { holder.overflow.removeAllViews(); } } }