package com.alorma.github.ui.fragment.commit;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.alorma.github.R;
import com.alorma.github.sdk.bean.info.CommitInfo;
import com.alorma.github.sdk.bean.info.RepoInfo;
import com.alorma.github.sdk.services.client.GithubListClient;
import com.alorma.github.sdk.services.commit.ListCommitsClient;
import com.alorma.github.ui.activity.CompareRepositoryCommitsActivity;
import com.alorma.github.ui.adapter.commit.CommitsAdapter;
import com.alorma.github.ui.fragment.base.LoadingListFragment;
import com.alorma.github.ui.fragment.detail.repo.BackManager;
import com.alorma.github.ui.fragment.detail.repo.BranchManager;
import com.alorma.github.ui.fragment.detail.repo.PermissionsManager;
import com.alorma.github.utils.AttributesUtils;
import com.alorma.gitskarios.core.Pair;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.octicons_typeface_library.Octicons;
import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration;
import core.repositories.Commit;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
public class CommitsListFragment extends LoadingListFragment<CommitsAdapter>
implements BranchManager, PermissionsManager, BackManager, CommitsAdapter.CommitsAdapterListener,
Observer<List<Commit>> {
private static final String REPO_INFO = "REPO_INFO";
private static final String PATH = "PATH";
private RepoInfo repoInfo;
private String path;
private boolean isInCompareMode = false;
private String baseCompare = null;
private String headCompare = null;
private CommitSelectedCallback commitSelectedCallback;
public static CommitsListFragment newInstance(RepoInfo repoInfo) {
Bundle bundle = new Bundle();
bundle.putParcelable(REPO_INFO, repoInfo);
CommitsListFragment fragment = new CommitsListFragment();
fragment.setArguments(bundle);
return fragment;
}
public static CommitsListFragment newInstance(RepoInfo repoInfo, String path) {
Bundle bundle = new Bundle();
bundle.putParcelable(REPO_INFO, repoInfo);
bundle.putString(PATH, path);
CommitsListFragment fragment = new CommitsListFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
protected void loadArguments() {
if (getArguments() != null) {
repoInfo = getArguments().getParcelable(REPO_INFO);
path = getArguments().getString(PATH);
}
}
@Override
protected void executeRequest() {
super.executeRequest();
CommitInfo commitInfo = new CommitInfo();
commitInfo.repoInfo = repoInfo;
commitInfo.sha = repoInfo.branch;
setAction(new ListCommitsClient(commitInfo, path, 0));
}
private void setAction(final GithubListClient<List<Commit>> listCommitsClient) {
listCommitsClient.observable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map((Func1<Pair<List<Commit>, Integer>, List<Commit>>) listIntegerPair -> {
setPage(listIntegerPair.second);
return listIntegerPair.first;
})
.map(orderCommits())
.subscribe(this);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof CommitSelectedCallback) {
commitSelectedCallback = (CommitSelectedCallback) context;
}
}
@Override
public void onDetach() {
commitSelectedCallback = commit -> {
};
super.onDetach();
}
@Override
protected int getLightTheme() {
return R.style.AppTheme_Repository;
}
@Override
protected int getDarkTheme() {
return R.style.AppTheme_Dark_Repository;
}
@Override
protected void executePaginatedRequest(int page) {
super.executePaginatedRequest(page);
CommitInfo commitInfo = new CommitInfo();
commitInfo.repoInfo = repoInfo;
setAction(new ListCommitsClient(commitInfo, path, page));
}
@Override
public void onCompleted() {
stopRefresh();
}
@Override
public void onError(Throwable e) {
stopRefresh();
if (getAdapter() == null || getAdapter().getItemCount() == 0) {
setEmpty();
}
}
@Override
public void onNext(List<Commit> commits) {
if (commits.size() > 0) {
hideEmpty();
if (refreshing || getAdapter() == null) {
CommitsAdapter commitsAdapter = new CommitsAdapter(LayoutInflater.from(getActivity()), false);
commitsAdapter.addAll(commits);
commitsAdapter.setCallback(item -> {
if (!isInCompareMode) {
commitSelectedCallback.onCommitSelected(item);
} else {
selectCommit(item);
}
});
commitsAdapter.setCommitsAdapterListener(this);
setAdapter(commitsAdapter);
} else {
getAdapter().addAll(commits);
}
removeDecorations();
StickyRecyclerHeadersDecoration headersDecoration = new StickyRecyclerHeadersDecoration(getAdapter());
addItemDecoration(headersDecoration);
} else if (getAdapter() == null || getAdapter().getItemCount() == 0) {
setEmpty();
} else {
getAdapter().clear();
setEmpty();
}
}
private void selectCommit(Commit item) {
if (baseCompare == null) {
baseCompare = item.shortSha();
} else {
headCompare = item.shortSha();
}
if (extraToolbar != null) {
if (baseCompare != null ) {
MenuItem menuItem = extraToolbar.getMenu().findItem(R.id.action_compare_commits);
if (menuItem != null) {
menuItem.setEnabled(baseCompare != null && headCompare != null);
}
}
extraToolbar.setTitle(baseCompare + " ... " + (headCompare != null ? headCompare : ":head"));
}
}
private Func1<List<Commit>, List<Commit>> orderCommits() {
return commits -> {
List<Commit> newCommits = new ArrayList<>();
for (Commit commit : commits) {
if (commit.commit.author.date != null) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
DateTime dt = formatter.parseDateTime(commit.commit.committer.date);
Days days = Days.daysBetween(dt.withTimeAtStartOfDay(), new DateTime(System.currentTimeMillis()).withTimeAtStartOfDay());
commit.days = days.getDays();
newCommits.add(commit);
}
}
return newCommits;
};
}
@Override
public void setEmpty(boolean withError, int statusCode) {
super.setEmpty(withError, statusCode);
if (fab != null) {
fab.setVisibility(View.INVISIBLE);
}
}
@Override
public void hideEmpty() {
super.hideEmpty();
if (fab != null) {
fab.setVisibility(View.VISIBLE);
}
}
@Override
public void setPermissions(boolean admin, boolean push, boolean pull) {
}
@Override
public boolean onBackPressed() {
if (extraToolbar != null && extraToolbar.getVisibility() == View.VISIBLE) {
hideExtraToolbar();
isInCompareMode = false;
checkFAB();
return false;
} else {
return true;
}
}
@Override
protected Octicons.Icon getNoDataIcon() {
return Octicons.Icon.oct_diff;
}
@Override
protected int getNoDataText() {
return R.string.no_commits;
}
@Override
protected boolean useFAB() {
return !isInCompareMode;
}
@Override
protected Octicons.Icon getFABGithubIcon() {
return Octicons.Icon.oct_git_compare;
}
@Override
protected void fabClick() {
isInCompareMode = !isInCompareMode;
checkFAB();
if (getActivity() != null) {
showExtraToolbar();
extraToolbar.setTitle(":base ... :head");
Menu menu = extraToolbar.getMenu();
if (menu != null) {
menu.clear();
}
extraToolbar.inflateMenu(R.menu.menu_commits_compare);
extraToolbar.setOnMenuItemClickListener(this::onExtraMenuItemSelected);
if (extraToolbar.getMenu() != null) {
prepareCompareMenu(extraToolbar.getMenu());
}
}
}
private boolean onExtraMenuItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_compare_commits) {
isInCompareMode = false;
if (extraToolbar.getVisibility() == View.VISIBLE) {
hideExtraToolbar();
checkFAB();
}
Intent intent = CompareRepositoryCommitsActivity.launcherIntent(getActivity(), repoInfo, baseCompare, headCompare);
startActivity(intent);
baseCompare = null;
headCompare = null;
}
return false;
}
private void prepareCompareMenu(Menu menu) {
int primaryColor = AttributesUtils.getPrimaryColor(getActivity());
MenuItem itemCompare = menu.findItem(R.id.action_compare_commits);
if (itemCompare != null) {
IconicsDrawable iconicsDrawable = new IconicsDrawable(getActivity(), Octicons.Icon.oct_git_compare).actionBar().color(primaryColor);
itemCompare.setIcon(iconicsDrawable);
itemCompare.setEnabled(false);
}
}
@Override
public void setCurrentBranch(String branch) {
if (repoInfo != null) {
repoInfo.branch = branch;
if (getAdapter() != null) {
getAdapter().clear();
}
startRefresh();
refreshing = true;
executeRequest();
}
}
@Override
public boolean onCommitLongClick(Commit commit) {
copy(commit.shortSha());
Toast.makeText(getActivity(), getString(R.string.sha_copied, commit.shortSha()), Toast.LENGTH_SHORT).show();
return true;
}
public void copy(String text) {
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("Gitskarios", text);
clipboard.setPrimaryClip(clip);
}
public interface CommitSelectedCallback {
void onCommitSelected(Commit commit);
}
}