/* * Copyright 2011 Azwan Adli Abdullah * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gh4a.adapter; import java.util.List; import org.eclipse.egit.github.core.Commit; import org.eclipse.egit.github.core.CommitComment; import org.eclipse.egit.github.core.Gist; import org.eclipse.egit.github.core.GollumPage; import org.eclipse.egit.github.core.Issue; import org.eclipse.egit.github.core.PullRequest; import org.eclipse.egit.github.core.Release; import org.eclipse.egit.github.core.Repository; import org.eclipse.egit.github.core.Team; import org.eclipse.egit.github.core.User; import org.eclipse.egit.github.core.event.CommitCommentPayload; import org.eclipse.egit.github.core.event.CreatePayload; import org.eclipse.egit.github.core.event.DeletePayload; import org.eclipse.egit.github.core.event.DownloadPayload; import org.eclipse.egit.github.core.event.Event; import org.eclipse.egit.github.core.event.EventPayload; import org.eclipse.egit.github.core.event.EventRepository; import org.eclipse.egit.github.core.event.FollowPayload; import org.eclipse.egit.github.core.event.ForkPayload; import org.eclipse.egit.github.core.event.GistPayload; import org.eclipse.egit.github.core.event.GollumPayload; import org.eclipse.egit.github.core.event.IssueCommentPayload; import org.eclipse.egit.github.core.event.IssuesPayload; import org.eclipse.egit.github.core.event.MemberPayload; import org.eclipse.egit.github.core.event.PullRequestPayload; import org.eclipse.egit.github.core.event.PullRequestReviewCommentPayload; import org.eclipse.egit.github.core.event.PushPayload; import org.eclipse.egit.github.core.event.ReleasePayload; import org.eclipse.egit.github.core.event.TeamAddPayload; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.graphics.Typeface; import android.support.v7.widget.RecyclerView; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.TextAppearanceSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.gh4a.R; import com.gh4a.activities.UserActivity; import com.gh4a.utils.ApiHelpers; import com.gh4a.utils.AvatarHandler; import com.gh4a.utils.StringUtils; import com.gh4a.widget.CustomTypefaceSpan; import com.gh4a.widget.EllipsizeLineSpan; import com.gh4a.widget.StyleableTextView; public class EventAdapter extends RootAdapter<Event, EventAdapter.EventViewHolder> { public EventAdapter(Context context) { super(context); } @Override public EventViewHolder onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) { View v = inflater.inflate(R.layout.row_event, parent, false); EventViewHolder holder = new EventViewHolder(v); holder.ivGravatar.setOnClickListener(this); return holder; } @Override public void onBindViewHolder(EventViewHolder holder, Event event) { User actor = event.getActor(); AvatarHandler.assignAvatar(holder.ivGravatar, actor); holder.ivGravatar.setTag(actor); holder.tvActor.setText(ApiHelpers.getUserLogin(mContext, actor)); StringUtils.applyBoldTagsAndSetText(holder.tvTitle, formatTitle(event)); holder.tvCreatedAt.setText(StringUtils.formatRelativeTime( mContext, event.getCreatedAt(), false)); CharSequence content = formatDescription(event, holder.tvDesc.getTypefaceValue()); holder.tvDesc.setText(content); holder.tvDesc.setVisibility(content != null ? View.VISIBLE : View.GONE); } @Override public void onClick(View v) { if (v.getId() == R.id.iv_gravatar) { User actor = (User) v.getTag(); Intent intent = UserActivity.makeIntent(mContext, actor); if (intent != null) { mContext.startActivity(intent); } } else { super.onClick(v); } } @Override public boolean isCardStyle() { return true; } private CharSequence formatDescription(Event event, int typefaceValue) { String eventType = event.getType(); EventRepository eventRepo = event.getRepo(); if (hasInvalidPayload(event)) { return event.getType(); } Resources res = mContext.getResources(); if (Event.TYPE_COMMIT_COMMENT.equals(eventType)) { CommitCommentPayload payload = (CommitCommentPayload) event.getPayload(); CommitComment comment = payload.getComment(); if (comment != null) { return comment.getBody(); } } else if (Event.TYPE_CREATE.equals(eventType)) { CreatePayload payload = (CreatePayload) event.getPayload(); String refType = payload.getRefType(); if (CreatePayload.REF_TYPE_REPO.equals(refType)) { return res.getString(R.string.event_create_repo_desc, eventRepo.getName()); } } else if (Event.TYPE_DOWNLOAD.equals(eventType)) { DownloadPayload payload = (DownloadPayload) event.getPayload(); if (payload.getDownload() != null) { return payload.getDownload().getName(); } } else if (Event.TYPE_FOLLOW.equals(eventType)) { FollowPayload payload = (FollowPayload) event.getPayload(); User target = payload.getTarget(); if (target != null) { return res.getString(R.string.event_follow_desc, target.getLogin(), target.getPublicRepos(), target.getFollowers()); } } else if (Event.TYPE_FORK.equals(eventType)) { ForkPayload payload = (ForkPayload) event.getPayload(); return res.getString(R.string.event_fork_desc, formatToRepoName(payload.getForkee())); } else if (Event.TYPE_GOLLUM.equals(eventType)) { GollumPayload payload = (GollumPayload) event.getPayload(); List<GollumPage> pages = payload.getPages(); if (pages != null && !pages.isEmpty()) { return res.getString(R.string.event_gollum_desc, pages.get(0).getPageName()); } } else if (Event.TYPE_ISSUE_COMMENT.equals(eventType)) { IssueCommentPayload payload = (IssueCommentPayload) event.getPayload(); if (payload != null && payload.getComment() != null) { return payload.getComment().getBody(); } } else if (Event.TYPE_ISSUES.equals(eventType)) { IssuesPayload eventPayload = (IssuesPayload) event.getPayload(); return eventPayload.getIssue().getTitle(); } else if (Event.TYPE_PUBLIC.equals(eventType)) { return null; } else if (Event.TYPE_PULL_REQUEST.equals(eventType)) { PullRequestPayload payload = (PullRequestPayload) event.getPayload(); PullRequest pullRequest = payload.getPullRequest(); if (!StringUtils.isBlank(pullRequest.getTitle())) { return res.getString(R.string.event_pull_request_desc, pullRequest.getTitle(), pullRequest.getCommits(), pullRequest.getAdditions(), pullRequest.getDeletions()); } } else if (Event.TYPE_PULL_REQUEST_REVIEW_COMMENT.equals(eventType)) { PullRequestReviewCommentPayload payload = (PullRequestReviewCommentPayload) event.getPayload(); CommitComment comment = payload.getComment(); if (comment != null) { return comment.getBody(); } } else if (Event.TYPE_PUSH.equals(eventType)) { PushPayload payload = (PushPayload) event.getPayload(); List<Commit> commits = payload.getCommits(); if (commits != null && !commits.isEmpty()) { SpannableStringBuilder ssb = new SpannableStringBuilder(); float density = mContext.getResources().getDisplayMetrics().density; int bottomMargin = Math.round(2 /* dp */ * density); int count = payload.getSize(); int maxLines = mContext.getResources().getInteger(R.integer.event_description_max_lines); int max = Math.min(count > maxLines ? maxLines - 1 : count, commits.size()); for (int i = 0; i < max; i++) { Commit commit = commits.get(i); if (i != 0) { ssb.append("\n"); } int lastLength = ssb.length(); String sha = commit.getSha().substring(0, 7); ssb.append(sha); ssb.setSpan(new TextAppearanceSpan(mContext, R.style.small_highlighted_sha), ssb.length() - sha.length(), ssb.length(), 0); ssb.append(" "); ssb.append(getFirstLine(commit.getMessage())); ssb.setSpan(new EllipsizeLineSpan(i == (count - 1) ? 0 : bottomMargin), lastLength, ssb.length(), 0); } if (count > maxLines) { String text = res.getString(R.string.event_push_desc, count - max); ssb.append("\n"); ssb.append(text); ssb.setSpan(new CustomTypefaceSpan(mContext, typefaceValue, Typeface.ITALIC), ssb.length() - text.length(), ssb.length(), 0); } return ssb; } else if (eventRepo == null) { return mContext.getString(R.string.deleted); } } else if (Event.TYPE_RELEASE.equals(eventType)) { ReleasePayload payload = (ReleasePayload) event.getPayload(); Release release = payload.getRelease(); if (release != null) { if (!TextUtils.isEmpty(release.getName())) { return release.getName(); } return release.getTagName(); } } else if (Event.TYPE_TEAM_ADD.equals(eventType)) { TeamAddPayload payload = (TeamAddPayload) event.getPayload(); Team team = payload.getTeam(); if (team != null) { return res.getString(R.string.event_team_add_desc, team.getName(), team.getMembersCount(), team.getReposCount()); } } return null; } private String getFirstLine(String input) { if (input == null) { return null; } int pos = input.indexOf('\n'); if (pos < 0) { return input; } return input.substring(0, pos); } private String formatTitle(Event event) { String eventType = event.getType(); EventRepository eventRepo = event.getRepo(); Resources res = mContext.getResources(); if (hasInvalidPayload(event)) { return event.getType(); } if (Event.TYPE_COMMIT_COMMENT.equals(eventType)) { CommitCommentPayload payload = (CommitCommentPayload) event.getPayload(); return res.getString(R.string.event_commit_comment_title, payload.getComment().getCommitId().substring(0, 7), formatFromRepoName(eventRepo)); } else if (Event.TYPE_CREATE.equals(eventType)) { CreatePayload payload = (CreatePayload) event.getPayload(); String type = payload.getRefType(); if (CreatePayload.REF_TYPE_REPO.equals(type)) { return res.getString(R.string.event_create_repo_title); } else if (CreatePayload.REF_TYPE_BRANCH.equals(type) || CreatePayload.REF_TYPE_TAG.equals(type)) { int resId = CreatePayload.REF_TYPE_BRANCH.equals(type) ? R.string.event_create_branch_title : R.string.event_create_tag_title; return res.getString(resId, payload.getRef(), formatFromRepoName(eventRepo)); } } else if (Event.TYPE_DELETE.equals(eventType)) { DeletePayload payload = (DeletePayload) event.getPayload(); String type = payload.getRefType(); if (DeletePayload.REF_TYPE_BRANCH.equals(type) || DeletePayload.REF_TYPE_TAG.equals(type)) { int resId = CreatePayload.REF_TYPE_BRANCH.equals(type) ? R.string.event_delete_branch_title : R.string.event_delete_tag_title; return res.getString(resId, payload.getRef(), formatFromRepoName(eventRepo)); } } else if (Event.TYPE_DOWNLOAD.equals(eventType)) { return res.getString(R.string.event_download_title, formatFromRepoName(eventRepo)); } else if (Event.TYPE_FOLLOW.equals(eventType)) { FollowPayload payload = (FollowPayload) event.getPayload(); return res.getString(R.string.event_follow_title, ApiHelpers.getUserLogin(mContext, payload.getTarget())); } else if (Event.TYPE_FORK.equals(event.getType())) { return res.getString(R.string.event_fork_title, formatFromRepoName(eventRepo)); } else if (Event.TYPE_FORK_APPLY.equals(eventType)) { return res.getString(R.string.event_fork_apply_title, formatFromRepoName(eventRepo)); } else if (Event.TYPE_GIST.equals(eventType)) { GistPayload payload = (GistPayload) event.getPayload(); Gist gist = payload.getGist(); String id = gist != null ? gist.getId() : mContext.getString(R.string.deleted); int resId = TextUtils.equals(payload.getAction(), GistPayload.ACTION_UPDATE) ? R.string.event_update_gist_title : R.string.event_create_gist_title; return res.getString(resId, id); } else if (Event.TYPE_GOLLUM.equals(eventType)) { GollumPayload payload = (GollumPayload) event.getPayload(); List<GollumPage> pages = payload.getPages(); int count = pages == null ? 0 : pages.size(); return res.getString(R.string.event_gollum_title, res.getQuantityString(R.plurals.page, count, count), formatFromRepoName(eventRepo)); } else if (Event.TYPE_ISSUE_COMMENT.equals(eventType)) { IssueCommentPayload payload = (IssueCommentPayload) event.getPayload(); Issue issue = payload.getIssue(); if (issue != null) { int formatResId = issue.getPullRequest() != null ? R.string.event_pull_request_comment : R.string.event_issue_comment; return res.getString(formatResId, issue.getNumber(), formatFromRepoName(eventRepo)); } } else if (Event.TYPE_ISSUES.equals(eventType)) { IssuesPayload payload = (IssuesPayload) event.getPayload(); final int resId; switch (payload.getAction()) { case IssuesPayload.ACTION_OPEN: resId = R.string.event_issues_open_title; break; case IssuesPayload.ACTION_CLOSE: resId = R.string.event_issues_close_title; break; case IssuesPayload.ACTION_REOPEN: resId = R.string.event_issues_reopen_title; break; default: return ""; } return res.getString(resId, payload.getIssue().getNumber(), formatFromRepoName(eventRepo)); } else if (Event.TYPE_MEMBER.equals(eventType)) { MemberPayload payload = (MemberPayload) event.getPayload(); return res.getString(R.string.event_member_title, ApiHelpers.getUserLogin(mContext, payload.getMember()), formatFromRepoName(eventRepo)); } else if (Event.TYPE_PUBLIC.equals(eventType)) { return res.getString(R.string.event_public_title, formatFromRepoName(eventRepo)); } else if (Event.TYPE_PULL_REQUEST.equals(eventType)) { PullRequestPayload payload = (PullRequestPayload) event.getPayload(); PullRequest pr = payload.getPullRequest(); final int resId; switch (payload.getAction()) { case PullRequestPayload.ACTION_OPEN: resId = R.string.event_pr_open_title; break; case PullRequestPayload.ACTION_CLOSE: resId = pr.isMerged() ? R.string.event_pr_merge_title : R.string.event_pr_close_title; break; case PullRequestPayload.ACTION_REOPEN: resId = R.string.event_pr_reopen_title; break; case PullRequestPayload.ACTION_SYNCHRONIZE: resId = R.string.event_pr_update_title; break; default: return ""; } return res.getString(resId, payload.getNumber(), formatFromRepoName(eventRepo)); } else if (Event.TYPE_PULL_REQUEST_REVIEW_COMMENT.equals(eventType)) { PullRequestReviewCommentPayload payload = (PullRequestReviewCommentPayload) event.getPayload(); PullRequest pr = payload.getPullRequest(); CommitComment comment = payload.getComment(); if (pr != null) { return res.getString(R.string.event_pull_request_review_comment_title, pr.getNumber(), formatFromRepoName(eventRepo)); } else if (comment != null) { return res.getString(R.string.event_commit_comment_title, comment.getCommitId().substring(0, 7), formatFromRepoName(eventRepo)); } } else if (Event.TYPE_PUSH.equals(eventType)) { PushPayload payload = (PushPayload) event.getPayload(); String ref = payload.getRef(); if (ref.startsWith("refs/heads/")) { ref = ref.substring(11); } return res.getString(R.string.event_push_title, ref, formatFromRepoName(eventRepo)); } else if (Event.TYPE_RELEASE.equals(eventType)) { return res.getString(R.string.event_release_title, formatFromRepoName(eventRepo)); } else if (Event.TYPE_TEAM_ADD.equals(eventType)) { TeamAddPayload payload = (TeamAddPayload) event.getPayload(); Team team = payload.getTeam(); if (team != null) { Repository repo = payload.getRepo(); if (repo != null) { return res.getString(R.string.event_team_repo_add, formatToRepoName(repo), team.getName()); } else { return res.getString(R.string.event_team_user_add, ApiHelpers.getUserLogin(mContext, payload.getUser()), team.getName()); } } } else if (Event.TYPE_WATCH.equals(eventType)) { return res.getString(R.string.event_watch_title, formatFromRepoName(eventRepo)); } return ""; } public static boolean hasInvalidPayload(Event event) { EventPayload payload = event.getPayload(); if (payload == null) { return true; } // we only accept and work with derived classes; if the base class // is returned, something went wrong during deserialization return EventPayload.class.equals(payload.getClass()); } private String formatFromRepoName(EventRepository repository) { if (repository != null) { return repository.getName(); } return mContext.getString(R.string.deleted); } private String formatToRepoName(Repository repository) { if (repository != null && repository.getOwner() != null) { return repository.getOwner().getLogin() + "/" + repository.getName(); } return mContext.getString(R.string.deleted); } /** * The Class ViewHolder. */ public static class EventViewHolder extends RecyclerView.ViewHolder { private EventViewHolder(View view) { super(view); ivGravatar = (ImageView) view.findViewById(R.id.iv_gravatar); tvActor = (TextView) view.findViewById(R.id.tv_actor); tvTitle = (StyleableTextView) view.findViewById(R.id.tv_title); tvDesc = (StyleableTextView) view.findViewById(R.id.tv_desc); tvCreatedAt = (TextView) view.findViewById(R.id.tv_created_at); } private final ImageView ivGravatar; private final TextView tvActor; private final StyleableTextView tvTitle; private final StyleableTextView tvDesc; private final TextView tvCreatedAt; } }