package com.alorma.github.ui.fragment.detail.repo;
import android.Manifest;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.AppCompatDrawableManager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.alorma.github.R;
import com.alorma.github.sdk.bean.dto.response.Content;
import com.alorma.github.sdk.bean.info.FileInfo;
import com.alorma.github.sdk.bean.info.RepoInfo;
import com.alorma.github.sdk.services.content.GetFileContentClient;
import com.alorma.github.sdk.services.repo.GetRepoContentsClient;
import com.alorma.github.ui.actions.ShareAction;
import com.alorma.github.ui.actions.ViewInAction;
import com.alorma.github.ui.activity.ContentCommitsActivity;
import com.alorma.github.ui.activity.FileActivity;
import com.alorma.github.ui.activity.NewContentActivity;
import com.alorma.github.ui.adapter.detail.repo.RepoSourceAdapter;
import com.alorma.github.ui.fragment.base.LoadingListFragment;
import com.alorma.github.ui.view.LinearBreadcrumb;
import com.alorma.gitskarios.core.Pair;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.single.EmptyPermissionListener;
import com.karumi.dexter.listener.single.PermissionListener;
import com.mikepenz.octicons_typeface_library.Octicons;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import retrofit.RetrofitError;
import rx.Observer;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import static com.alorma.github.sdk.bean.dto.response.ContentType.file;
public class RepositorySourceListFragment extends LoadingListFragment<RepoSourceAdapter>
implements BranchManager, LinearBreadcrumb.SelectionCallback, BackManager, RepoSourceAdapter.SourceAdapterListener {
private static final String REPO_INFO = "REPO_INFO";
private static final int RESULT_NEW_FILE = 111;
private RepoInfo repoInfo;
private LinearBreadcrumb breadCrumbs;
private String currentPath;
private Observer<Pair<List<Content>, Integer>> subscriber;
public static RepositorySourceListFragment newInstance(RepoInfo repoInfo) {
Bundle bundle = new Bundle();
bundle.putParcelable(REPO_INFO, repoInfo);
RepositorySourceListFragment f = new RepositorySourceListFragment();
f.setArguments(bundle);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
subscriber = new Observer<Pair<List<Content>, Integer>>() {
@Override
public void onCompleted() {
stopRefresh();
}
@Override
public void onError(Throwable e) {
stopRefresh();
if (getActivity() != null) {
if (getAdapter() == null || getAdapter().getItemCount() == 0) {
if (e != null && e instanceof RetrofitError && ((RetrofitError) e).getResponse() != null) {
setEmpty(true, ((RetrofitError) e).getResponse().getStatus());
}
}
}
}
@Override
public void onNext(Pair<List<Content>, Integer> listIntegerPair) {
onContentLoaded(listIntegerPair.first);
}
};
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.source_list_fragment, null, false);
}
@Override
protected int getLightTheme() {
return R.style.AppTheme_Repository;
}
@Override
protected int getDarkTheme() {
return R.style.AppTheme_Dark_Repository;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
breadCrumbs = (LinearBreadcrumb) view.findViewById(R.id.breadCrumbs);
breadCrumbs.setCallback(this);
if (getArguments() != null) {
getContent();
}
}
private void navigateUp() {
if (currentPath != null) {
String[] paths = currentPath.split("/");
paths = Arrays.copyOf(paths, paths.length - 1);
StringBuilder builder = new StringBuilder();
if (paths.length > 0) {
for (String path : paths) {
builder.append(path);
builder.append("/");
}
String path = builder.toString();
getPathContent(path.substring(0, path.length() - 1));
} else {
getContent();
}
}
}
@Override
protected void loadArguments() {
if (getArguments() != null) {
repoInfo = getArguments().getParcelable(REPO_INFO);
}
}
private void getContent() {
currentPath = "/";
if (getAdapter() != null) {
getAdapter().clear();
}
setAdapter(null);
breadCrumbs.initRootCrumb();
GetRepoContentsClient repoContentsClient = new GetRepoContentsClient(repoInfo);
repoContentsClient.observable().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(subscriber);
}
@Override
protected Octicons.Icon getNoDataIcon() {
return Octicons.Icon.oct_file_text;
}
@Override
protected int getNoDataText() {
return R.string.no_content;
}
private void displayContent(List<Content> contents) {
if (getActivity() != null) {
stopRefresh();
if (currentPath != null) {
breadCrumbs.addPath(currentPath, "/");
}
RepoSourceAdapter contentAdapter = new RepoSourceAdapter(getActivity(), LayoutInflater.from(getActivity()), repoInfo);
contentAdapter.setSourceAdapterListener(this);
contentAdapter.addAll(contents);
setAdapter(contentAdapter);
}
}
@Override
public void onContentClick(Content item) {
if (item.isDir()) {
getPathContent(item.path);
} else if (item.isFile()) {
FileInfo fileInfo = new FileInfo();
fileInfo.repoInfo = repoInfo;
fileInfo.head = item.sha;
fileInfo.name = item.name;
fileInfo.path = item.path;
Intent intent = FileActivity.createLauncherIntent(getActivity(), fileInfo);
startActivity(intent);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.source_list_fragment, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem menuItem = menu.findItem(R.id.action_content_download);
try {
if (menuItem != null) {
Drawable drawable = AppCompatDrawableManager.get().getDrawable(getActivity(), R.drawable.cloud_download);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable = DrawableCompat.wrap(drawable);
drawable.setTint(Color.WHITE);
}
menuItem.setIcon(drawable);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_content_download:
downloadRepo();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void downloadRepo() {
Toast.makeText(getContext(), "Not implemented", Toast.LENGTH_SHORT).show();
/*
String archive_url = currentRepo.getArchiveUrl();
GitskariosSettings settings = new GitskariosSettings(getContext());
String zipBall = getString(R.string.download_zip_value);
String fileType = settings.getDownloadFileType(zipBall);
archive_url = archive_url.replace("{archive_format}", fileType);
archive_url = archive_url.replace("{/ref}", "/" + currentRepo.getDefaultBranch());
GitskariosDownloadManager gitskariosDownloadManager = new GitskariosDownloadManager();
gitskariosDownloadManager.download(this, archive_url,
currentRepo.name + "_" + currentRepo.getDefaultBranch() + "." + getExtensionFromFileType(fileType), text -> {
Snackbar snackbar = Snackbar.make(recyclerView, getString(text), Snackbar.LENGTH_LONG);
snackbar.setActionAndAuthor(getString(R.string.external_storage_permission_request_action),
v -> gitskariosDownloadManager.openSettings(getContext()));
snackbar.show();
});
*/
}
private String getExtensionFromFileType(String fileType) {
if ("zipball".equals(fileType)) {
return "zip";
} else if ("tarball".equals(fileType)) {
return "tar.gz";
}
return null;
}
@Override
public void onContentMenuAction(Content content, MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_content_share:
new ShareAction(getActivity(), repoInfo.owner + "/" + repoInfo.name, content._links.html).setType(getString(R.string.source_code))
.execute();
break;
case R.id.action_content_open:
new ViewInAction(getActivity(), content._links.html).setType(getString(R.string.source_code)).execute();
break;
case R.id.action_copy_content_url:
copy(content._links.html);
Toast.makeText(getActivity(), getString(R.string.url_of_copied, content.name), Toast.LENGTH_SHORT).show();
break;
case R.id.action_content_history:
Intent intent = ContentCommitsActivity.createLauncherIntent(getActivity(), repoInfo, content.path, content.name);
startActivity(intent);
break;
case R.id.action_content_download:
if (file.equals(content.type)) {
checkPermissionsAndDownload(content);
} else {
Toast.makeText(getActivity(), R.string.download_only_files, Toast.LENGTH_LONG).show();
}
break;
}
}
private void checkPermissionsAndDownload(Content content) {
PermissionListener listener = new EmptyPermissionListener() {
@Override
public void onPermissionGranted(PermissionGrantedResponse response) {
super.onPermissionGranted(response);
downloadFile(content);
}
@Override
public void onPermissionDenied(PermissionDeniedResponse response) {
super.onPermissionDenied(response);
Toast.makeText(getActivity(), R.string.external_storage_permission_request, Toast.LENGTH_SHORT).show();
}
@Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
token.continuePermissionRequest();
}
};
Dexter.checkPermission(listener, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
private void downloadFile(Content content) {
FileInfo info = new FileInfo();
info.repoInfo = repoInfo;
info.path = content.path;
info.name = content.name;
new GetFileContentClient(info).observable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Content>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Content content) {
File downloadFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/gitskarios");
if (!downloadFolder.exists()) {
downloadFolder.mkdir();
}
File file =
new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/gitskarios", content.name);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileOutputStream outputStream;
try {
outputStream = new FileOutputStream(file);
outputStream.write(decodeContent(content.content).getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(getContext(), content.name + " has been download at Downloads/gitskarios/" + content.name, Toast.LENGTH_SHORT)
.show();
}
});
}
public void copy(String text) {
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("Gitskarios", text);
clipboard.setPrimaryClip(clip);
}
@Override
public void setEmpty(boolean withError, int statusCode) {
super.setEmpty(withError, statusCode);
}
@Override
public void hideEmpty() {
super.hideEmpty();
}
@Override
public void setCurrentBranch(String branch) {
loadArguments();
repoInfo.branch = branch;
getContent();
}
private void getPathContent(String path) {
currentPath = path;
startRefresh();
GetRepoContentsClient repoContentsClient = new GetRepoContentsClient(repoInfo, path);
repoContentsClient.observable().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(subscriber);
}
private void onContentLoaded(List<Content> contents) {
if (getActivity() != null) {
if (contents != null && contents.size() > 0) {
hideEmpty();
Collections.sort(contents);
Collections.reverse(contents);
displayContent(contents);
} else if (getAdapter() == null || getAdapter().getItemCount() == 0) {
setEmpty();
}
}
}
@Override
protected boolean useFAB() {
return repoInfo != null && repoInfo.permissions != null && repoInfo.permissions.push;
}
@Override
protected Octicons.Icon getFABGithubIcon() {
return Octicons.Icon.oct_plus;
}
@Override
protected void fabClick() {
super.fabClick();
createFile();
}
private void createFile() {
Intent launcherIntent = NewContentActivity.createLauncherIntent(getActivity(), repoInfo, currentPath);
startActivityForResult(launcherIntent, RESULT_NEW_FILE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == RESULT_NEW_FILE) {
onRefresh();
}
}
}
@Override
public void onRefresh() {
if (currentPath == null || currentPath.equals("/")) {
getContent();
} else {
getPathContent(currentPath);
}
}
@Override
public void onCrumbSelection(LinearBreadcrumb.Crumb crumb, String absolutePath, int count, int index) {
if (crumb.getPath() != null && crumb.getPath().equals("/")) {
getContent();
} else {
getPathContent(breadCrumbs.getAbsolutePath(crumb, "/"));
}
breadCrumbs.setActive(crumb);
}
@Override
public void loadMoreItems() {
}
private void downloadContent(Content content) {
if (file.equals(content.type)) {
FileInfo info = new FileInfo();
info.repoInfo = repoInfo;
info.path = content.path;
info.name = content.name;
new GetFileContentClient(info).observable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Content>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Content content) {
File downloadFolder =
new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/gitskarios");
if (!downloadFolder.exists()) {
downloadFolder.mkdirs();
}
File file =
new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/gitskarios", content.name);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileOutputStream outputStream;
try {
outputStream = new FileOutputStream(file);
outputStream.write(decodeContent(content.content).getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(getContext(), content.name + " has been download at Download/gitskarios/" + content.name, Toast.LENGTH_SHORT)
.show();
}
});
} else {
Toast.makeText(getActivity(), R.string.download_only_files, Toast.LENGTH_LONG).show();
}
}
private String decodeContent(String encoded) {
String decoded = encoded;
byte[] data = android.util.Base64.decode(encoded, android.util.Base64.DEFAULT);
try {
decoded = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return decoded;
}
@Override
public boolean onBackPressed() {
if (breadCrumbs != null && breadCrumbs.size() == 1) {
return true;
} else {
navigateUp();
return false;
}
}
}