/*
* Copyright (c) 2011, 2012 Roberto Tyley
*
* This file is part of 'Agit' - an Android Git client.
*
* Agit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Agit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/ .
*/
package com.madgag.agit;
import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static android.view.animation.AnimationUtils.loadAnimation;
import static com.google.common.collect.Maps.newEnumMap;
import static com.madgag.agit.BranchViewer.branchViewerIntentFor;
import static com.madgag.agit.GitIntents.COMMIT;
import static com.madgag.agit.GitIntents.GITDIR;
import static com.madgag.agit.GitIntents.UNTIL_REVS;
import static com.madgag.agit.R.anim.pull_child_in;
import static com.madgag.agit.R.anim.pull_parent_in;
import static com.madgag.agit.R.anim.push_child_out;
import static com.madgag.agit.R.anim.push_parent_out;
import static com.madgag.agit.RepositoryViewerActivity.manageRepoIntent;
import static com.madgag.agit.git.Repos.niceNameFor;
import static com.madgag.agit.git.model.Relation.CHILD;
import static com.madgag.agit.git.model.Relation.PARENT;
import static com.madgag.android.ActionBarUtil.fixImageTilingOn;
import static com.madgag.android.ActionBarUtil.homewardsWith;
import static com.madgag.android.ActionBarUtil.setPrefixedTitleOn;
import static com.madgag.android.ViewPagerUtil.onSearchRequestedForCurrentFragment;
import static org.eclipse.jgit.lib.Repository.shortenRefName;
import android.content.Intent;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.style.CharacterStyle;
import android.text.style.TypefaceSpan;
import android.util.Log;
import android.view.animation.Animation;
import com.actionbarsherlock.view.MenuItem;
import com.google.common.base.Stopwatch;
import com.google.inject.Inject;
import com.madgag.agit.CommitNavigationView.CommitSelectedListener;
import com.madgag.agit.git.model.Relation;
import java.io.IOException;
import java.util.Map;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revplot.PlotCommit;
import org.eclipse.jgit.revplot.PlotCommitList;
import org.eclipse.jgit.revplot.PlotLane;
import org.eclipse.jgit.revplot.PlotWalk;
import org.eclipse.jgit.revwalk.RevCommit;
public class CommitViewerActivity extends RepoScopedActivityBase implements CommitSelectedListener {
private static final String TAG = "CVA";
public static GitIntentBuilder commitViewIntentFor(Bundle sourceArgs) {
return new GitIntentBuilder("commit.VIEW", sourceArgs, GITDIR, UNTIL_REVS, COMMIT);
}
public static Intent commitViewIntentFor(Repository repository, Ref ref) {
return new GitIntentBuilder("commit.VIEW").repository(repository).untilRevs(ref).commit(ref.getObjectId()).toIntent();
}
public static Intent commitViewIntentFor(Repository repository, RevCommit commit) {
return new GitIntentBuilder("commit.VIEW").repository(repository).commit(commit).toIntent();
}
@Inject
LogStartProvider logStartProvider;
private PlotWalk plotWalk;
private PlotCommit<PlotLane> commit;
CommitView currentCommitView, nextCommitView;
public static final CharacterStyle MONOSPACE_SPAN = new TypefaceSpan("monospace");
private Map<Relation, RelationAnimations> relationAnimations = newEnumMap(Relation.class);
@Override
public void onCommitSelected(Relation relation, PlotCommit<PlotLane> commit) {
moveToCommit(commit, relation);
}
@Override
public PlotCommit<PlotLane> plotCommitFor(ObjectId objectId) throws IOException {
return (PlotCommit<PlotLane>) plotWalk.parseCommit(objectId);
}
private class RelationAnimations {
private final Animation animateOldViewOut, animateNewViewIn;
public RelationAnimations(int animateOldViewOutId, int animateNewViewInId) {
animateOldViewOut = loadAnimation(CommitViewerActivity.this, animateOldViewOutId);
animateNewViewIn = loadAnimation(CommitViewerActivity.this, animateNewViewInId);
}
void animateViews() {
currentCommitView.startAnimation(animateOldViewOut);
nextCommitView.startAnimation(animateNewViewIn);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fixImageTilingOn(getSupportActionBar());
setContentView(R.layout.commit_navigation_animation_layout);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
relationAnimations.put(PARENT, new RelationAnimations(push_child_out, pull_parent_in));
relationAnimations.put(CHILD, new RelationAnimations(push_parent_out, pull_child_in));
currentCommitView = (CommitView) findViewById(R.id.commit_nav_current_commit);
nextCommitView = (CommitView) findViewById(R.id.commit_nav_next_commit);
try {
ObjectId revisionId = GitIntents.commitIdFrom(getIntent());
Log.d(TAG, revisionId.getName());
plotWalk = generatePlotWalk();
setCurrentCommit(plotCommitFor(revisionId));
setup(currentCommitView, plotWalk);
setup(nextCommitView, plotWalk);
currentCommitView.setCommit(commit);
setCurrentCommitViewVisible();
} catch (Exception e) {
Log.e(TAG, "Problem my friend", e);
}
}
private void setup(CommitView commitView, PlotWalk revWalk) {
commitView.setRepositoryContext(repo(), revWalk);
}
private void setCurrentCommitViewVisible() {
currentCommitView.setVisibility(VISIBLE);
nextCommitView.setVisibility(GONE);
}
public void moveToCommit(PlotCommit<PlotLane> newCommit, Relation relation) {
setCurrentCommit(newCommit);
try {
nextCommitView.setCommit(newCommit);
} catch (Exception e) {
throw new RuntimeException(e);
}
relationAnimations.get(relation).animateViews();
swapCommitViewVars();
setCurrentCommitViewVisible();
}
private void swapCommitViewVars() {
CommitView oldCurrent = currentCommitView;
currentCommitView = nextCommitView;
nextCommitView = oldCurrent;
}
private void setCurrentCommit(PlotCommit<PlotLane> commit) {
this.commit = commit;
Log.d(TAG, "setCurrentCommit : commit=" + commit);
setActionBarTitles();
}
private void setActionBarTitles() {
SpannableStringBuilder prefixTitle = new SpannableStringBuilder(commit.name().substring(0, 4));
prefixTitle.setSpan(MONOSPACE_SPAN, 0, 4, SPAN_EXCLUSIVE_EXCLUSIVE);
String pathPrefix = niceNameFor(repo()) + " • ";
String currentRef = logStartProvider.getCurrentRef();
if (currentRef != null) {
pathPrefix = pathPrefix + shortenRefName(currentRef) + " • ";
}
prefixTitle.insert(0, pathPrefix);
setPrefixedTitleOn(getSupportActionBar(), prefixTitle, commit.getShortMessage());
}
private PlotWalk generatePlotWalk() throws IOException {
Stopwatch stopwatch = new Stopwatch().start();
PlotWalk revWalk = new PlotWalk(repo());
logStartProvider.markStartsOn(revWalk);
PlotCommitList<PlotLane> plotCommitList = new PlotCommitList<PlotLane>();
plotCommitList.source(revWalk);
plotCommitList.fillTo(Integer.MAX_VALUE);
Log.d(TAG, "generatePlotWalk duration" + stopwatch.stop());
return revWalk;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
String ref = logStartProvider.getCurrentRef();
Intent intent = (ref == null) ? manageRepoIntent(gitdir()) : branchViewerIntentFor(gitdir(), ref);
return homewardsWith(this, intent);
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onSearchRequested() { // Search key pressed.
onSearchRequestedForCurrentFragment(currentCommitView.pager);
return true;
}
}