/*
* Copyright 2012 GitHub Inc.
*
* 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.github.mobile.ui.user;
import static com.github.kevinsawicki.wishlist.ViewUpdater.FORMAT_INT;
import static com.github.mobile.util.TypefaceUtils.ICON_ADD_MEMBER;
import static com.github.mobile.util.TypefaceUtils.ICON_COMMENT;
import static com.github.mobile.util.TypefaceUtils.ICON_CREATE;
import static com.github.mobile.util.TypefaceUtils.ICON_DELETE;
import static com.github.mobile.util.TypefaceUtils.ICON_FOLLOW;
import static com.github.mobile.util.TypefaceUtils.ICON_FORK;
import static com.github.mobile.util.TypefaceUtils.ICON_GIST;
import static com.github.mobile.util.TypefaceUtils.ICON_ISSUE_CLOSE;
import static com.github.mobile.util.TypefaceUtils.ICON_ISSUE_COMMENT;
import static com.github.mobile.util.TypefaceUtils.ICON_ISSUE_OPEN;
import static com.github.mobile.util.TypefaceUtils.ICON_ISSUE_REOPEN;
import static com.github.mobile.util.TypefaceUtils.ICON_PULL_REQUEST;
import static com.github.mobile.util.TypefaceUtils.ICON_PUSH;
import static com.github.mobile.util.TypefaceUtils.ICON_STAR;
import static com.github.mobile.util.TypefaceUtils.ICON_UPLOAD;
import static com.github.mobile.util.TypefaceUtils.ICON_WIKI;
import static org.eclipse.egit.github.core.event.Event.TYPE_COMMIT_COMMENT;
import static org.eclipse.egit.github.core.event.Event.TYPE_CREATE;
import static org.eclipse.egit.github.core.event.Event.TYPE_DELETE;
import static org.eclipse.egit.github.core.event.Event.TYPE_DOWNLOAD;
import static org.eclipse.egit.github.core.event.Event.TYPE_FOLLOW;
import static org.eclipse.egit.github.core.event.Event.TYPE_FORK;
import static org.eclipse.egit.github.core.event.Event.TYPE_FORK_APPLY;
import static org.eclipse.egit.github.core.event.Event.TYPE_GIST;
import static org.eclipse.egit.github.core.event.Event.TYPE_GOLLUM;
import static org.eclipse.egit.github.core.event.Event.TYPE_ISSUES;
import static org.eclipse.egit.github.core.event.Event.TYPE_ISSUE_COMMENT;
import static org.eclipse.egit.github.core.event.Event.TYPE_MEMBER;
import static org.eclipse.egit.github.core.event.Event.TYPE_PUBLIC;
import static org.eclipse.egit.github.core.event.Event.TYPE_PULL_REQUEST;
import static org.eclipse.egit.github.core.event.Event.TYPE_PULL_REQUEST_REVIEW_COMMENT;
import static org.eclipse.egit.github.core.event.Event.TYPE_PUSH;
import static org.eclipse.egit.github.core.event.Event.TYPE_TEAM_ADD;
import static org.eclipse.egit.github.core.event.Event.TYPE_WATCH;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import com.github.kevinsawicki.wishlist.SingleTypeAdapter;
import com.github.kevinsawicki.wishlist.ViewUtils;
import com.github.mobile.R.id;
import com.github.mobile.R.layout;
import com.github.mobile.core.issue.IssueUtils;
import com.github.mobile.ui.StyledText;
import com.github.mobile.util.AvatarLoader;
import com.github.mobile.util.TimeUtils;
import com.github.mobile.util.TypefaceUtils;
import java.util.List;
import org.eclipse.egit.github.core.Comment;
import org.eclipse.egit.github.core.Commit;
import org.eclipse.egit.github.core.CommitComment;
import org.eclipse.egit.github.core.Download;
import org.eclipse.egit.github.core.Issue;
import org.eclipse.egit.github.core.PullRequest;
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.GistPayload;
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.TeamAddPayload;
/**
* Adapter for a list of news events
*/
public class NewsListAdapter extends SingleTypeAdapter<Event> {
/**
* Can the given event be rendered by this view holder?
*
* @param event
* @return true if renderable, false otherwise
*/
public static boolean isValid(final Event event) {
if (event == null)
return false;
final EventPayload payload = event.getPayload();
if (payload == null || EventPayload.class.equals(payload.getClass()))
return false;
final String type = event.getType();
if (TextUtils.isEmpty(type))
return false;
return TYPE_COMMIT_COMMENT.equals(type) //
|| (TYPE_CREATE.equals(type) //
&& ((CreatePayload) payload).getRefType() != null) //
|| TYPE_DELETE.equals(type) //
|| TYPE_DOWNLOAD.equals(type) //
|| TYPE_FOLLOW.equals(type) //
|| TYPE_FORK.equals(type) //
|| TYPE_FORK_APPLY.equals(type) //
|| (TYPE_GIST.equals(type) //
&& ((GistPayload) payload).getGist() != null) //
|| TYPE_GOLLUM.equals(type) //
|| (TYPE_ISSUE_COMMENT.equals(type) //
&& ((IssueCommentPayload) payload).getIssue() != null) //
|| (TYPE_ISSUES.equals(type) //
&& ((IssuesPayload) payload).getIssue() != null) //
|| TYPE_MEMBER.equals(type) //
|| TYPE_PUBLIC.equals(type) //
|| TYPE_PULL_REQUEST.equals(type) //
|| TYPE_PULL_REQUEST_REVIEW_COMMENT.equals(type) //
|| TYPE_PUSH.equals(type) //
|| TYPE_TEAM_ADD.equals(type) //
|| TYPE_WATCH.equals(type);
}
private static void appendComment(final StyledText details,
final Comment comment) {
if (comment != null)
appendText(details, comment.getBody());
}
private static void appendCommitComment(final StyledText details,
final CommitComment comment) {
if (comment == null)
return;
String id = comment.getCommitId();
if (!TextUtils.isEmpty(id)) {
if (id.length() > 10)
id = id.substring(0, 10);
appendText(details, "Comment in");
details.append(' ');
details.monospace(id);
details.append(':').append('\n');
}
appendComment(details, comment);
}
private static void appendText(final StyledText details, String text) {
if (text == null)
return;
text = text.trim();
if (text.length() == 0)
return;
details.append(text);
}
private static StyledText boldActor(final StyledText text, final Event event) {
return boldUser(text, event.getActor());
}
private static StyledText boldUser(final StyledText text, final User user) {
if (user != null)
text.bold(user.getLogin());
return text;
}
private static StyledText boldRepo(final StyledText text, final Event event) {
EventRepository repo = event.getRepo();
if (repo != null)
text.bold(repo.getName());
return text;
}
private static StyledText boldRepoName(final StyledText text,
final Event event) {
EventRepository repo = event.getRepo();
if (repo != null) {
String name = repo.getName();
if (!TextUtils.isEmpty(name)) {
int slash = name.indexOf('/');
if (slash != -1 && slash + 1 < name.length())
text.bold(name.substring(slash + 1));
}
}
return text;
}
private static void formatCommitComment(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" commented on ");
boldRepo(main, event);
CommitCommentPayload payload = (CommitCommentPayload) event
.getPayload();
appendCommitComment(details, payload.getComment());
}
private static void formatDownload(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" uploaded a file to ");
boldRepo(main, event);
DownloadPayload payload = (DownloadPayload) event.getPayload();
Download download = payload.getDownload();
if (download != null)
appendText(details, download.getName());
}
private static void formatCreate(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" created ");
CreatePayload payload = (CreatePayload) event.getPayload();
String refType = payload.getRefType();
main.append(refType);
main.append(' ');
if (!"repository".equals(refType)) {
main.append(payload.getRef());
main.append(" at ");
boldRepo(main, event);
} else
boldRepoName(main, event);
}
private static void formatDelete(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
DeletePayload payload = (DeletePayload) event.getPayload();
main.append(" deleted ");
main.append(payload.getRefType());
main.append(' ');
main.append(payload.getRef());
main.append(" at ");
boldRepo(main, event);
}
private static void formatFollow(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" started following ");
boldUser(main, ((FollowPayload) event.getPayload()).getTarget());
}
private static void formatFork(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" forked repository ");
boldRepo(main, event);
}
private static void formatGist(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
GistPayload payload = (GistPayload) event.getPayload();
main.append(' ');
String action = payload.getAction();
if ("create".equals(action))
main.append("created");
else if ("update".equals(action))
main.append("updated");
else
main.append(action);
main.append(" Gist ");
main.append(payload.getGist().getId());
}
private static void formatWiki(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" updated the wiki in ");
boldRepo(main, event);
}
private static void formatIssueComment(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" commented on ");
IssueCommentPayload payload = (IssueCommentPayload) event.getPayload();
Issue issue = payload.getIssue();
String number;
if (IssueUtils.isPullRequest(issue))
number = "pull request " + issue.getNumber();
else
number = "issue " + issue.getNumber();
main.bold(number);
main.append(" on ");
boldRepo(main, event);
appendComment(details, payload.getComment());
}
private static void formatIssues(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
IssuesPayload payload = (IssuesPayload) event.getPayload();
String action = payload.getAction();
Issue issue = payload.getIssue();
main.append(' ');
main.append(action);
main.append(' ');
main.bold("issue " + issue.getNumber());
main.append(" on ");
boldRepo(main, event);
appendText(details, issue.getTitle());
}
private static void formatAddMember(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" added ");
User member = ((MemberPayload) event.getPayload()).getMember();
if (member != null)
main.bold(member.getLogin());
main.append(" as a collaborator to ");
boldRepo(main, event);
}
private static void formatPublic(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" open sourced repository ");
boldRepo(main, event);
}
private static void formatWatch(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" starred ");
boldRepo(main, event);
}
private static void formatReviewComment(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" commented on ");
boldRepo(main, event);
PullRequestReviewCommentPayload payload = (PullRequestReviewCommentPayload) event
.getPayload();
appendCommitComment(details, payload.getComment());
}
private static void formatPullRequest(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
PullRequestPayload payload = (PullRequestPayload) event.getPayload();
String action = payload.getAction();
if ("synchronize".equals(action))
action = "updated";
main.append(' ');
main.append(action);
main.append(' ');
main.bold("pull request " + payload.getNumber());
main.append(" on ");
boldRepo(main, event);
if ("opened".equals(action) || "closed".equals(action)) {
PullRequest request = payload.getPullRequest();
if (request != null) {
String title = request.getTitle();
if (!TextUtils.isEmpty(title))
details.append(title);
}
}
}
private static void formatPush(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
main.append(" pushed to ");
PushPayload payload = (PushPayload) event.getPayload();
String ref = payload.getRef();
if (ref.startsWith("refs/heads/"))
ref = ref.substring(11);
main.bold(ref);
main.append(" at ");
boldRepo(main, event);
final List<Commit> commits = payload.getCommits();
int size = commits != null ? commits.size() : -1;
if (size > 0) {
if (size != 1)
details.append(FORMAT_INT.format(size)).append(" new commits");
else
details.append("1 new commit");
int max = 3;
int appended = 0;
for (Commit commit : commits) {
if (commit == null)
continue;
String sha = commit.getSha();
if (TextUtils.isEmpty(sha))
continue;
details.append('\n');
if (sha.length() > 7)
details.monospace(sha.substring(0, 7));
else
details.monospace(sha);
String message = commit.getMessage();
if (!TextUtils.isEmpty(message)) {
details.append(' ');
int newline = message.indexOf('\n');
if (newline > 0)
details.append(message.subSequence(0, newline));
else
details.append(message);
}
appended++;
if (appended == max)
break;
}
}
}
private static void formatTeamAdd(Event event, StyledText main,
StyledText details) {
boldActor(main, event);
TeamAddPayload payload = (TeamAddPayload) event.getPayload();
main.append(" added ");
User user = payload.getUser();
if (user != null)
boldUser(main, user);
else
boldRepoName(main, event);
main.append(" to team");
Team team = payload.getTeam();
String teamName = team != null ? team.getName() : null;
if (teamName != null)
main.append(' ').bold(teamName);
}
private final AvatarLoader avatars;
/**
* Create list adapter
*
* @param inflater
* @param elements
* @param avatars
*/
public NewsListAdapter(LayoutInflater inflater, Event[] elements,
AvatarLoader avatars) {
super(inflater, layout.news_item);
this.avatars = avatars;
setItems(elements);
}
/**
* Create list adapter
*
*
* @param inflater
* @param avatars
*/
public NewsListAdapter(LayoutInflater inflater, AvatarLoader avatars) {
this(inflater, null, avatars);
}
@Override
public long getItemId(final int position) {
final String id = getItem(position).getId();
return !TextUtils.isEmpty(id) ? id.hashCode() : super
.getItemId(position);
}
@Override
protected int[] getChildViewIds() {
return new int[] { id.iv_avatar, id.tv_event, id.tv_event_details,
id.tv_event_icon, id.tv_event_date };
}
@Override
protected View initialize(View view) {
view = super.initialize(view);
TypefaceUtils.setOcticons(textView(view, 3));
return view;
}
@Override
protected void update(int position, Event event) {
avatars.bind(imageView(0), event.getActor());
StyledText main = new StyledText();
StyledText details = new StyledText();
String icon = null;
String type = event.getType();
if (TYPE_COMMIT_COMMENT.equals(type)) {
icon = ICON_COMMENT;
formatCommitComment(event, main, details);
} else if (TYPE_CREATE.equals(type)) {
icon = ICON_CREATE;
formatCreate(event, main, details);
} else if (TYPE_DELETE.equals(type)) {
icon = ICON_DELETE;
formatDelete(event, main, details);
} else if (TYPE_DOWNLOAD.equals(type)) {
icon = ICON_UPLOAD;
formatDownload(event, main, details);
} else if (TYPE_FOLLOW.equals(type)) {
icon = ICON_FOLLOW;
formatFollow(event, main, details);
} else if (TYPE_FORK.equals(type)) {
icon = ICON_FORK;
formatFork(event, main, details);
} else if (TYPE_GIST.equals(type)) {
icon = ICON_GIST;
formatGist(event, main, details);
} else if (TYPE_GOLLUM.equals(type)) {
icon = ICON_WIKI;
formatWiki(event, main, details);
} else if (TYPE_ISSUE_COMMENT.equals(type)) {
icon = ICON_ISSUE_COMMENT;
formatIssueComment(event, main, details);
} else if (TYPE_ISSUES.equals(type)) {
String action = ((IssuesPayload) event.getPayload()).getAction();
if ("opened".equals(action))
icon = ICON_ISSUE_OPEN;
else if ("reopened".equals(action))
icon = ICON_ISSUE_REOPEN;
else if ("closed".equals(action))
icon = ICON_ISSUE_CLOSE;
formatIssues(event, main, details);
} else if (TYPE_MEMBER.equals(type)) {
icon = ICON_ADD_MEMBER;
formatAddMember(event, main, details);
} else if (TYPE_PUBLIC.equals(type))
formatPublic(event, main, details);
else if (TYPE_PULL_REQUEST.equals(type)) {
icon = ICON_PULL_REQUEST;
formatPullRequest(event, main, details);
} else if (TYPE_PULL_REQUEST_REVIEW_COMMENT.equals(type)) {
icon = ICON_COMMENT;
formatReviewComment(event, main, details);
} else if (TYPE_PUSH.equals(type)) {
icon = ICON_PUSH;
formatPush(event, main, details);
} else if (TYPE_TEAM_ADD.equals(type)) {
icon = ICON_ADD_MEMBER;
formatTeamAdd(event, main, details);
} else if (TYPE_WATCH.equals(type)) {
icon = ICON_STAR;
formatWatch(event, main, details);
}
if (icon != null)
ViewUtils.setGone(setText(3, icon), false);
else
setGone(3, true);
setText(1, main);
if (!TextUtils.isEmpty(details))
ViewUtils.setGone(setText(2, details), false);
else
setGone(2, true);
setText(4, TimeUtils.getRelativeTime(event.getCreatedAt()));
}
}