/* * 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 android.content.Context; import android.content.Intent; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.TypefaceSpan; import android.view.View; import android.widget.ImageView; import com.gh4a.R; import com.gh4a.activities.CommitActivity; import com.gh4a.activities.PullRequestDiffViewerActivity; import com.gh4a.loader.IssueEventHolder; import com.gh4a.utils.ApiHelpers; import com.gh4a.utils.FileUtils; import com.gh4a.utils.HttpImageGetter; import com.gh4a.utils.StringUtils; import com.gh4a.utils.UiUtils; import com.gh4a.widget.IntentSpan; import com.gh4a.widget.IssueLabelSpan; import com.gh4a.widget.StyleableTextView; import org.eclipse.egit.github.core.CommitComment; import org.eclipse.egit.github.core.CommitFile; import org.eclipse.egit.github.core.IssueEvent; import org.eclipse.egit.github.core.Label; import org.eclipse.egit.github.core.Rename; import org.eclipse.egit.github.core.User; import java.util.Date; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class IssueEventAdapter extends CommentAdapterBase<IssueEventHolder> { private static final Pattern COMMIT_URL_REPO_NAME_AND_OWNER_PATTERN = Pattern.compile(".*github.com\\/repos\\/([^\\/]+)\\/([^\\/]+)\\/commits"); private static final HashMap<String, Integer> EVENT_ICONS = new HashMap<>(); static { EVENT_ICONS.put(IssueEvent.TYPE_CLOSED, R.attr.issueEventClosedIcon); EVENT_ICONS.put(IssueEvent.TYPE_REOPENED, R.attr.issueEventReopenedIcon); EVENT_ICONS.put(IssueEvent.TYPE_MERGED, R.attr.issueEventMergedIcon); EVENT_ICONS.put(IssueEvent.TYPE_REFERENCED, R.attr.issueEventReferencedIcon); EVENT_ICONS.put(IssueEvent.TYPE_ASSIGNED, R.attr.issueEventAssignedIcon); EVENT_ICONS.put(IssueEvent.TYPE_UNASSIGNED, R.attr.issueEventUnassignedIcon); EVENT_ICONS.put(IssueEvent.TYPE_LABELED, R.attr.issueEventLabeledIcon); EVENT_ICONS.put(IssueEvent.TYPE_UNLABELED, R.attr.issueEventUnlabeledIcon); EVENT_ICONS.put(IssueEvent.TYPE_LOCKED, R.attr.issueEventLockedIcon); EVENT_ICONS.put(IssueEvent.TYPE_UNLOCKED, R.attr.issueEventUnlockedIcon); EVENT_ICONS.put(IssueEvent.TYPE_MILESTONED, R.attr.issueEventMilestonedIcon); EVENT_ICONS.put(IssueEvent.TYPE_DEMILESTONED, R.attr.issueEventDemilestonedIcon); EVENT_ICONS.put(IssueEvent.TYPE_RENAMED, R.attr.issueEventRenamedIcon); } private final int mIssueId; private boolean mLocked; public IssueEventAdapter(Context context, String repoOwner, String repoName, int issueId, OnCommentAction actionCallback) { super(context, repoOwner, repoName, actionCallback); mIssueId = issueId; } public void setLocked(boolean locked) { mLocked = locked; notifyDataSetChanged(); } @Override protected User getUser(IssueEventHolder item) { return item.getUser(); } @Override protected Date getCreatedAt(IssueEventHolder item) { return item.getCreatedAt(); } @Override protected Date getUpdatedAt(IssueEventHolder item) { return item.getUpdatedAt(); } @Override protected String getUrl(IssueEventHolder item) { return item.comment != null ? item.comment.getHtmlUrl() : null; } @Override protected String getShareSubject(IssueEventHolder item) { return mContext.getString(R.string.share_comment_subject, item.comment.getId(), mIssueId, mRepoOwner + "/" + mRepoName); } @Override protected void bindBodyView(IssueEventHolder item, StyleableTextView view, HttpImageGetter imageGetter) { if (item.comment != null) { imageGetter.bind(view, item.comment.getBodyHtml(), item.comment.getId()); } else { imageGetter.unbind(view); view.setText(formatEvent(item.event, item.getUser(), view.getTypefaceValue(), item.isPullRequestEvent)); } } @Override protected void bindExtraView(IssueEventHolder item, StyleableTextView view) { String login = ApiHelpers.getUserLogin(mContext, item.getUser()); StringUtils.applyBoldTagsAndSetText(view, mContext.getString(R.string.issue_comment_header, login)); } @Override protected void bindFileView(IssueEventHolder item, StyleableTextView view) { if (item.comment instanceof CommitComment) { final CommitComment commitComment = (CommitComment) item.comment; SpannableStringBuilder text = StringUtils.applyBoldTags(mContext, mContext.getString(R.string.issue_commit_comment_file), view.getTypefaceValue()); int pos = text.toString().indexOf("[file]"); if (pos >= 0) { String fileName = FileUtils.getFileName(commitComment.getPath()); final CommitFile file = item.file; text.replace(pos, pos + 6, fileName); if (file != null) { text.setSpan(new IntentSpan(mContext) { @Override protected Intent getIntent() { return PullRequestDiffViewerActivity.makeIntent(mContext, mRepoOwner, mRepoName, mIssueId, commitComment.getCommitId(), commitComment.getPath(), file.getPatch(), null, commitComment.getPosition(), -1, -1, false); } }, pos, pos + fileName.length(), 0); } } view.setVisibility(View.VISIBLE); view.setText(text); view.setMovementMethod(UiUtils.CHECKING_LINK_METHOD); } else { view.setVisibility(View.GONE); } } @Override protected void bindEventIcon(IssueEventHolder item, ImageView view) { Integer eventIconAttr = item.event != null ? EVENT_ICONS.get(item.event.getEvent()) : null; if (eventIconAttr != null) { view.setImageResource(UiUtils.resolveDrawable(mContext, eventIconAttr)); view.setVisibility(View.VISIBLE); } else { view.setVisibility(View.GONE); } } @Override protected boolean hasActionMenu(IssueEventHolder item) { return item.comment != null; } @Override protected boolean canQuote(IssueEventHolder item) { return item.comment != null && !mLocked; } private CharSequence formatEvent(final IssueEvent event, final User user, int typefaceValue, boolean isPullRequestEvent) { String textBase = null; int textResId = 0; switch (event.getEvent()) { case IssueEvent.TYPE_CLOSED: if (isPullRequestEvent) { textResId = event.getCommitId() != null ? R.string.pull_request_event_closed_with_commit : R.string.pull_request_event_closed; } else { textResId = event.getCommitId() != null ? R.string.issue_event_closed_with_commit : R.string.issue_event_closed; } break; case IssueEvent.TYPE_REOPENED: textResId = isPullRequestEvent ? R.string.pull_request_event_reopened : R.string.issue_event_reopened; break; case IssueEvent.TYPE_MERGED: textResId = event.getCommitId() != null ? R.string.pull_request_event_merged_with_commit : R.string.pull_request_event_merged; break; case IssueEvent.TYPE_REFERENCED: if (isPullRequestEvent) { textResId = event.getCommitId() != null ? R.string.pull_request_event_referenced_with_commit : R.string.pull_request_event_referenced; } else { textResId = event.getCommitId() != null ? R.string.issue_event_referenced_with_commit : R.string.issue_event_referenced; } break; case IssueEvent.TYPE_ASSIGNED: case IssueEvent.TYPE_UNASSIGNED: { boolean isAssign = TextUtils.equals(event.getEvent(), IssueEvent.TYPE_ASSIGNED); String actorLogin = user != null ? user.getLogin() : null; String assigneeLogin = event.getAssignee() != null ? event.getAssignee().getLogin() : null; if (assigneeLogin != null && assigneeLogin.equals(actorLogin)) { if (isPullRequestEvent) { textResId = isAssign ? R.string.pull_request_event_assigned_self : R.string.pull_request_event_unassigned_self; } else { textResId = isAssign ? R.string.issue_event_assigned_self : R.string.issue_event_unassigned_self; } } else { if (isPullRequestEvent) { textResId = isAssign ? R.string.pull_request_event_assigned : R.string.pull_request_event_unassigned; } else { textResId = isAssign ? R.string.issue_event_assigned : R.string.issue_event_unassigned; } textBase = mContext.getString(textResId, ApiHelpers.getUserLogin(mContext, user), ApiHelpers.getUserLogin(mContext, event.getAssignee())); } break; } case IssueEvent.TYPE_LABELED: textResId = R.string.issue_event_labeled; break; case IssueEvent.TYPE_UNLABELED: textResId = R.string.issue_event_unlabeled; break; case IssueEvent.TYPE_LOCKED: textResId = isPullRequestEvent ? R.string.pull_request_event_locked : R.string.issue_event_locked; break; case IssueEvent.TYPE_UNLOCKED: textResId = isPullRequestEvent ? R.string.pull_request_event_unlocked : R.string.issue_event_unlocked; break; case IssueEvent.TYPE_MILESTONED: case IssueEvent.TYPE_DEMILESTONED: textResId = TextUtils.equals(event.getEvent(), IssueEvent.TYPE_MILESTONED) ? R.string.issue_event_milestoned : R.string.issue_event_demilestoned; textBase = mContext.getString(textResId, event.getMilestone().getTitle(), ApiHelpers.getUserLogin(mContext, user)); break; case IssueEvent.TYPE_RENAMED: { Rename rename = event.getRename(); textBase = mContext.getString(R.string.issue_event_renamed, rename.getFrom(), rename.getTo(), ApiHelpers.getUserLogin(mContext, user)); break; } default: return null; } if (textBase == null) { textBase = mContext.getString(textResId, ApiHelpers.getUserLogin(mContext, user)); } SpannableStringBuilder text = StringUtils.applyBoldTags(mContext, textBase, typefaceValue); int pos = text.toString().indexOf("[commit]"); if (event.getCommitId() != null && pos >= 0) { text.replace(pos, pos + 8, event.getCommitId().substring(0, 7)); text.setSpan(new TypefaceSpan("monospace"), pos, pos + 7, 0); text.setSpan(new IntentSpan(mContext) { @Override protected Intent getIntent() { // The commit might be in a different repo. The API doesn't provide // that information directly, so get it indirectly by parsing the URL String repoOwner = mRepoOwner, repoName = mRepoName; String url = event.getCommitUrl(); if (url != null) { Matcher matcher = COMMIT_URL_REPO_NAME_AND_OWNER_PATTERN.matcher(url); if (matcher.find()) { repoOwner = matcher.group(1); repoName = matcher.group(2); } } return CommitActivity.makeIntent(mContext, repoOwner, repoName, event.getCommitId()); } }, pos, pos + 7, 0); } pos = text.toString().indexOf("[label]"); Label label = event.getLabel(); if (label != null && pos >= 0) { int length = label.getName().length(); text.replace(pos, pos + 7, label.getName()); text.setSpan(new IssueLabelSpan(mContext, label, false), pos, pos + length, 0); } return text; } }