package com.seafile.seadroid2.ui.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.view.ActionMode;
import android.util.Log;
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.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.cocosw.bottomsheet.BottomSheet;
import com.google.common.collect.Maps;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.SeafConnection;
import com.seafile.seadroid2.SeafException;
import com.seafile.seadroid2.SettingsManager;
import com.seafile.seadroid2.account.Account;
import com.seafile.seadroid2.data.DataManager;
import com.seafile.seadroid2.data.SeafCachedFile;
import com.seafile.seadroid2.data.SeafDirent;
import com.seafile.seadroid2.data.SeafGroup;
import com.seafile.seadroid2.data.SeafItem;
import com.seafile.seadroid2.data.SeafRepo;
import com.seafile.seadroid2.ssl.CertsManager;
import com.seafile.seadroid2.transfer.TransferService;
import com.seafile.seadroid2.ui.CopyMoveContext;
import com.seafile.seadroid2.ui.NavContext;
import com.seafile.seadroid2.ui.activity.BrowserActivity;
import com.seafile.seadroid2.ui.adapter.SeafItemAdapter;
import com.seafile.seadroid2.ui.dialog.SslConfirmDialog;
import com.seafile.seadroid2.ui.dialog.TaskDialog;
import com.seafile.seadroid2.util.ConcurrentAsyncTask;
import com.seafile.seadroid2.util.Utils;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;
public class ReposFragment extends ListFragment {
private static final String DEBUG_TAG = "ReposFragment";
private static final String KEY_REPO_SCROLL_POSITION = "repo_scroll_position";
private static final int REFRESH_ON_RESUME = 0;
private static final int REFRESH_ON_PULL = 1;
private static final int REFRESH_ON_CLICK = 2;
private static final int REFRESH_ON_OVERFLOW_MENU = 3;
private static int mRefreshType = -1;
/**
* flag to stop refreshing when nav to other directory
*/
private static int mPullToRefreshStopRefreshing = 0;
private SeafItemAdapter adapter;
private BrowserActivity mActivity = null;
private ActionMode mActionMode;
private CopyMoveContext copyMoveContext;
private Map<String, ScrollState> scrollPostions;
public static final int FILE_ACTION_EXPORT = 0;
public static final int FILE_ACTION_COPY = 1;
public static final int FILE_ACTION_MOVE = 2;
public static final int FILE_ACTION_STAR = 3;
private SwipeRefreshLayout refreshLayout;
private ListView mListView;
private ImageView mEmptyView;
private View mProgressContainer;
private View mListContainer;
private TextView mErrorText;
private boolean isTimerStarted;
private final Handler mTimer = new Handler();
private DataManager getDataManager() {
return mActivity.getDataManager();
}
private NavContext getNavContext() {
return mActivity.getNavContext();
}
public SeafItemAdapter getAdapter() {
return adapter;
}
public ImageView getEmptyView() {
return mEmptyView;
}
public interface OnFileSelectedListener {
void onFileSelected(SeafDirent fileName);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d(DEBUG_TAG, "ReposFragment Attached");
mActivity = (BrowserActivity) activity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.repos_fragment, container, false);
refreshLayout = (SwipeRefreshLayout) root.findViewById(R.id.swiperefresh);
mListView = (ListView) root.findViewById(android.R.id.list);
mEmptyView = (ImageView) root.findViewById(R.id.empty);
mListContainer = root.findViewById(R.id.listContainer);
mErrorText = (TextView) root.findViewById(R.id.error_message);
mProgressContainer = root.findViewById(R.id.progressContainer);
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
startContextualActionMode(position);
return true;
}
});
refreshLayout.setColorSchemeResources(R.color.fancy_orange);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mRefreshType = REFRESH_ON_PULL;
refreshView(true, true);
}
});
return root;
}
/**
* Start action mode for selecting and process multiple files/folders.
* The contextual action mode is a system implementation of ActionMode
* that focuses user interaction toward performing contextual actions.
* When a user enables this mode by selecting an item,
* a contextual action bar appears at the top of the screen
* to present actions the user can perform on the currently selected item(s).
* <p>
* While this mode is enabled,
* the user can select multiple items (if you allow it), deselect items,
* and continue to navigate within the activity (as much as you're willing to allow).
* <p>
* The action mode is disabled and the contextual action bar disappears
* when the user deselects all items, presses the BACK button, or selects the Done action on the left side of the bar.
* <p>
* see http://developer.android.com/guide/topics/ui/menus.html#CAB
*/
public void startContextualActionMode(int position) {
startContextualActionMode();
NavContext nav = getNavContext();
if (adapter == null || !nav.inRepo()) return;
adapter.toggleSelection(position);
updateContextualActionBar();
}
public void startContextualActionMode() {
NavContext nav = getNavContext();
if (!nav.inRepo()) return;
if (mActionMode == null) {
// start the actionMode
mActionMode = mActivity.startSupportActionMode(new ActionModeCallback());
}
}
public void showRepoBottomSheet(final SeafRepo repo) {
final BottomSheet.Builder builder = new BottomSheet.Builder(mActivity);
builder.title(repo.getName()).sheet(R.menu.bottom_sheet_op_repo).listener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case R.id.rename_repo:
mActivity.renameRepo(repo.getID(), repo.getName());
break;
case R.id.delete_repo:
mActivity.deleteRepo(repo.getID());
break;
}
}
}).show();
}
public void showFileBottomSheet(String title, final SeafDirent dirent) {
final String repoName = getNavContext().getRepoName();
final String repoID = getNavContext().getRepoID();
final String dir = getNavContext().getDirPath();
final String path = Utils.pathJoin(dir, dirent.name);
final String filename = dirent.name;
final String localPath = getDataManager().getLocalRepoFile(repoName, repoID, path).getPath();
final BottomSheet.Builder builder = new BottomSheet.Builder(mActivity);
builder.title(title).sheet(R.menu.bottom_sheet_op_file).listener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case R.id.share:
mActivity.shareFile(repoID, path, false);
break;
case R.id.share_encrypt:
mActivity.shareFile(repoID, path, true);
break;
case R.id.delete:
mActivity.deleteFile(repoID, repoName, path);
break;
case R.id.copy:
mActivity.copyFile(repoID, repoName, dir, filename, false);
break;
case R.id.move:
mActivity.moveFile(repoID, repoName, dir, filename, false);
break;
case R.id.rename:
mActivity.renameFile(repoID, repoName, path);
break;
case R.id.update:
mActivity.addUpdateTask(repoID, repoName, dir, localPath);
break;
case R.id.download:
mActivity.downloadFile(dir, dirent.name);
break;
case R.id.export:
mActivity.exportFile(dirent.name, dirent.size);
break;
case R.id.star:
mActivity.starFile(repoID, dir, filename);
break;
}
}
});
if (!dirent.hasWritePermission()) {
Menu menu = builder.build().getMenu();
menu.findItem(R.id.rename).setVisible(false);
menu.findItem(R.id.delete).setVisible(false);
menu.findItem(R.id.move).setVisible(false);
}
builder.show();
SeafRepo repo = getDataManager().getCachedRepoByID(repoID);
if (repo != null && repo.encrypted) {
builder.remove(R.id.share);
}
SeafCachedFile cf = getDataManager().getCachedFile(repoName, repoID, path);
if (cf != null) {
builder.remove(R.id.download);
} else {
builder.remove(R.id.update);
}
}
public void showDirBottomSheet(String title, final SeafDirent dirent) {
final String repoName = getNavContext().getRepoName();
final String repoID = getNavContext().getRepoID();
final String dir = getNavContext().getDirPath();
final String path = Utils.pathJoin(dir, dirent.name);
final String filename = dirent.name;
final BottomSheet.Builder builder = new BottomSheet.Builder(mActivity);
builder.title(title).sheet(R.menu.bottom_sheet_op_dir).listener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case R.id.share:
mActivity.shareDir(repoID, path, false);
break;
case R.id.share_encrypt:
mActivity.shareDir(repoID, path, true);
break;
case R.id.delete:
mActivity.deleteDir(repoID, repoName, path);
break;
case R.id.copy:
mActivity.copyFile(repoID, repoName, dir, filename, false);
break;
case R.id.move:
mActivity.moveFile(repoID, repoName, dir, filename, false);
break;
case R.id.rename:
mActivity.renameDir(repoID, repoName, path);
break;
case R.id.download:
mActivity.downloadDir(dir, dirent.name, true);
break;
}
}
});
Menu menu = builder.build().getMenu();
if (!dirent.hasWritePermission()) {
menu.findItem(R.id.rename).setVisible(false);
menu.findItem(R.id.delete).setVisible(false);
menu.findItem(R.id.move).setVisible(false);
}
builder.show();
SeafRepo repo = getDataManager().getCachedRepoByID(repoID);
if (repo != null && repo.encrypted) {
builder.remove(R.id.share);
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(DEBUG_TAG, "ReposFragment onActivityCreated");
scrollPostions = Maps.newHashMap();
adapter = new SeafItemAdapter(mActivity);
mListView.setAdapter(adapter);
}
@Override
public void onStart() {
// Log.d(DEBUG_TAG, "ReposFragment onStart");
super.onStart();
}
@Override
public void onStop() {
// Log.d(DEBUG_TAG, "ReposFragment onStop");
super.onStop();
stopTimer();
}
@Override
public void onResume() {
super.onResume();
// Log.d(DEBUG_TAG, "ReposFragment onResume");
// refresh the view (loading data)
refreshView();
mRefreshType = REFRESH_ON_RESUME;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDetach() {
mActivity = null;
// Log.d(DEBUG_TAG, "ReposFragment detached");
super.onDetach();
}
public void refresh() {
mRefreshType = REFRESH_ON_OVERFLOW_MENU;
refreshView(true, false);
}
public void refreshView() {
refreshView(false, false);
}
public void refreshView(boolean restorePosition) {
refreshView(false, restorePosition);
}
public void refreshView(boolean forceRefresh, boolean restorePosition) {
if (mActivity == null)
return;
mErrorText.setVisibility(View.GONE);
mListContainer.setVisibility(View.VISIBLE);
NavContext navContext = getNavContext();
if (navContext.inRepo()) {
if (mActivity.getCurrentPosition() == BrowserActivity.INDEX_LIBRARY_TAB) {
mActivity.enableUpButton();
}
navToDirectory(forceRefresh, restorePosition);
} else {
mActivity.disableUpButton();
navToReposView(forceRefresh, restorePosition);
}
mActivity.supportInvalidateOptionsMenu();
}
public void navToReposView(boolean forceRefresh, boolean restorePosition) {
//stopTimer();
mPullToRefreshStopRefreshing++;
if (mPullToRefreshStopRefreshing > 1) {
refreshLayout.setRefreshing(false);
mPullToRefreshStopRefreshing = 0;
}
forceRefresh = forceRefresh || isReposRefreshTimeOut();
if (!Utils.isNetworkOn() || !forceRefresh) {
List<SeafRepo> repos = getDataManager().getReposFromCache();
if (repos != null) {
if (mRefreshType == REFRESH_ON_PULL) {
refreshLayout.setRefreshing(false);
mPullToRefreshStopRefreshing = 0;
}
updateAdapterWithRepos(repos, restorePosition);
return;
}
}
ConcurrentAsyncTask.execute(new LoadTask(getDataManager()));
}
public void navToDirectory(boolean forceRefresh, boolean restorePosition) {
startTimer();
mPullToRefreshStopRefreshing++;
if (mPullToRefreshStopRefreshing > 1) {
refreshLayout.setRefreshing(false);
mPullToRefreshStopRefreshing = 0;
}
NavContext nav = getNavContext();
DataManager dataManager = getDataManager();
SeafRepo repo = getDataManager().getCachedRepoByID(nav.getRepoID());
if (repo != null) {
adapter.setEncryptedRepo(repo.encrypted);
if (nav.getDirPath().equals(BrowserActivity.ACTIONBAR_PARENT_PATH)) {
mActivity.setUpButtonTitle(nav.getRepoName());
} else
mActivity.setUpButtonTitle(nav.getDirPath().substring(
nav.getDirPath().lastIndexOf(BrowserActivity.ACTIONBAR_PARENT_PATH) + 1));
}
forceRefresh = forceRefresh || isDirentsRefreshTimeOut(nav.getRepoID(), nav.getDirPath());
if (!Utils.isNetworkOn() || !forceRefresh) {
List<SeafDirent> dirents = dataManager.getCachedDirents(
nav.getRepoID(), nav.getDirPath());
if (dirents != null) {
if (mRefreshType == REFRESH_ON_PULL) {
refreshLayout.setRefreshing(false);
mPullToRefreshStopRefreshing = 0;
}
updateAdapterWithDirents(dirents, restorePosition);
return;
}
}
ConcurrentAsyncTask.execute(new LoadDirTask(getDataManager()),
nav.getRepoName(),
nav.getRepoID(),
nav.getDirPath());
}
// refresh list by mTimer
public void startTimer() {
if (isTimerStarted)
return;
isTimerStarted = true;
Log.d(DEBUG_TAG, "timer started");
mTimer.postDelayed(new Runnable() {
@Override
public void run() {
if (mActivity == null) return;
TransferService ts = mActivity.getTransferService();
String repoID = getNavContext().getRepoID();
String repoName = getNavContext().getRepoName();
String currentDir = getNavContext().getDirPath();
adapter.setDownloadTaskList(ts.getDownloadTaskInfosByPath(repoID, currentDir));
// Log.d(DEBUG_TAG, "timer post refresh signal " + System.currentTimeMillis());
mTimer.postDelayed(this, 1 * 3500);
}
}, 1 * 3500);
}
public void stopTimer() {
Log.d(DEBUG_TAG, "timer stopped");
mTimer.removeCallbacksAndMessages(null);
isTimerStarted = false;
}
/**
* calculate if repo refresh time is expired, the expiration is 10 mins
*/
private boolean isReposRefreshTimeOut() {
if (getDataManager().isReposRefreshTimeout()) {
return true;
}
return false;
}
/**
* calculate if dirent refresh time is expired, the expiration is 10 mins
*
* @param repoID
* @param path
* @return true if refresh time expired, false otherwise
*/
private boolean isDirentsRefreshTimeOut(String repoID, String path) {
if (getDataManager().isDirentsRefreshTimeout(repoID, path)) {
return true;
}
return false;
}
public void sortFiles(int type, int order) {
adapter.sortFiles(type, order);
adapter.notifyDataSetChanged();
// persist sort settings
SettingsManager.instance().saveSortFilesPref(type, order);
}
private void updateAdapterWithRepos(List<SeafRepo> repos, boolean restoreScrollPosition) {
adapter.clear();
if (repos.size() > 0) {
addReposToAdapter(repos);
adapter.sortFiles(SettingsManager.instance().getSortFilesTypePref(),
SettingsManager.instance().getSortFilesOrderPref());
adapter.notifyChanged();
mListView.setVisibility(View.VISIBLE);
restoreRepoScrollPosition(restoreScrollPosition);
mEmptyView.setVisibility(View.GONE);
} else {
mListView.setVisibility(View.GONE);
mEmptyView.setVisibility(View.VISIBLE);
}
// Collapses the currently open view
//mListView.collapse();
}
private void updateAdapterWithDirents(final List<SeafDirent> dirents, boolean restoreScrollPosition) {
adapter.clear();
if (dirents.size() > 0) {
for (SeafDirent dirent : dirents) {
adapter.add(dirent);
}
NavContext nav = getNavContext();
final String repoName = nav.getRepoName();
final String repoID = nav.getRepoID();
final String dirPath = nav.getDirPath();
adapter.sortFiles(SettingsManager.instance().getSortFilesTypePref(),
SettingsManager.instance().getSortFilesOrderPref());
adapter.notifyChanged();
mListView.setVisibility(View.VISIBLE);
restoreDirentScrollPosition(restoreScrollPosition, repoID, dirPath);
mEmptyView.setVisibility(View.GONE);
} else {
// Directory is empty
mListView.setVisibility(View.GONE);
mEmptyView.setVisibility(View.VISIBLE);
}
// Collapses the currently open view
//mListView.collapse();
}
/**
* update state of contextual action bar (CAB)
*/
public void updateContextualActionBar() {
if (mActionMode == null) {
// there are some selected items, start the actionMode
mActionMode = mActivity.startSupportActionMode(new ActionModeCallback());
} else {
// Log.d(DEBUG_TAG, "mActionMode.setTitle " + adapter.getCheckedItemCount());
mActionMode.setTitle(getResources().getQuantityString(
R.plurals.transfer_list_items_selected,
adapter.getCheckedItemCount(),
adapter.getCheckedItemCount()));
}
}
@Override
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
if (Utils.isFastTapping()) return;
// handle action mode selections
if (mActionMode != null) {
// add or remove selection for current list item
if (adapter == null) return;
adapter.toggleSelection(position);
updateContextualActionBar();
return;
}
SeafRepo repo = null;
final NavContext nav = getNavContext();
if (nav.inRepo()) {
repo = getDataManager().getCachedRepoByID(nav.getRepoID());
mActivity.setUpButtonTitle(repo.getName());
} else {
SeafItem item = adapter.getItem(position);
if (item instanceof SeafRepo) {
repo = (SeafRepo) item;
}
}
if (repo == null) {
return;
}
if (repo.encrypted && !getDataManager().getRepoPasswordSet(repo.id)) {
String password = getDataManager().getRepoPassword(repo.id);
mActivity.showPasswordDialog(repo.name, repo.id,
new TaskDialog.TaskDialogListener() {
@Override
public void onTaskSuccess() {
onListItemClick(l, v, position, id);
}
}, password);
return;
}
mRefreshType = REFRESH_ON_CLICK;
if (nav.inRepo()) {
if (adapter.getItem(position) instanceof SeafDirent) {
final SeafDirent dirent = (SeafDirent) adapter.getItem(position);
if (dirent.isDir()) {
String currentPath = nav.getDirPath();
String newPath = currentPath.endsWith("/") ?
currentPath + dirent.name : currentPath + "/" + dirent.name;
nav.setDir(newPath, dirent.id);
nav.setDirPermission(dirent.permission);
saveDirentScrollPosition(repo.getID(), currentPath);
refreshView();
mActivity.setUpButtonTitle(dirent.name);
} else {
mActivity.onFileSelected(dirent);
}
} else
return;
} else {
nav.setDirPermission(repo.permission);
nav.setRepoID(repo.id);
nav.setRepoName(repo.getName());
nav.setDir("/", repo.root);
saveRepoScrollPosition();
refreshView();
}
}
private class ScrollState {
public int index;
public int top;
public ScrollState(int index, int top) {
this.index = index;
this.top = top;
}
}
private void saveDirentScrollPosition(String repoId, String currentPath) {
final String pathJoin = Utils.pathJoin(repoId, currentPath);
final int index = mListView.getFirstVisiblePosition();
final View v = mListView.getChildAt(0);
final int top = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
final ScrollState state = new ScrollState(index, top);
scrollPostions.put(pathJoin, state);
}
private void saveRepoScrollPosition() {
final int index = mListView.getFirstVisiblePosition();
final View v = mListView.getChildAt(0);
final int top = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
final ScrollState state = new ScrollState(index, top);
scrollPostions.put(KEY_REPO_SCROLL_POSITION, state);
}
private void restoreDirentScrollPosition(boolean restore, String repoId, String dirPath) {
final String pathJoin = Utils.pathJoin(repoId, dirPath);
if (restore) {
ScrollState state = scrollPostions.get(pathJoin);
if (state != null) {
mListView.setSelectionFromTop(state.index, state.top);
} else {
mListView.setSelectionAfterHeaderView();
}
} else {
mListView.setSelectionAfterHeaderView();
}
}
private void restoreRepoScrollPosition(boolean restore) {
if (restore) {
ScrollState state = scrollPostions.get(KEY_REPO_SCROLL_POSITION);
if (state != null) {
mListView.setSelectionFromTop(state.index, state.top);
} else {
mListView.setSelectionAfterHeaderView();
}
} else {
mListView.setSelectionAfterHeaderView();
}
}
private void addReposToAdapter(List<SeafRepo> repos) {
if (repos == null)
return;
Map<String, List<SeafRepo>> map = Utils.groupRepos(repos);
List<SeafRepo> personalRepos = map.get(Utils.PERSONAL_REPO);
if (personalRepos != null) {
SeafGroup personalGroup = new SeafGroup(mActivity.getResources().getString(R.string.personal));
adapter.add(personalGroup);
for (SeafRepo repo : personalRepos)
adapter.add(repo);
}
List<SeafRepo> sharedRepos = map.get(Utils.SHARED_REPO);
if (sharedRepos != null) {
SeafGroup sharedGroup = new SeafGroup(mActivity.getResources().getString(R.string.shared));
adapter.add(sharedGroup);
for (SeafRepo repo : sharedRepos)
adapter.add(repo);
}
for (Map.Entry<String, List<SeafRepo>> entry : map.entrySet()) {
String key = entry.getKey();
if (!key.equals(Utils.PERSONAL_REPO)
&& !key.endsWith(Utils.SHARED_REPO)) {
SeafGroup group = new SeafGroup(key);
adapter.add(group);
for (SeafRepo repo : entry.getValue()) {
adapter.add(repo);
}
}
}
}
private class LoadTask extends AsyncTask<Void, Void, List<SeafRepo>> {
SeafException err = null;
DataManager dataManager;
public LoadTask(DataManager dataManager) {
this.dataManager = dataManager;
}
@Override
protected void onPreExecute() {
if (mRefreshType == REFRESH_ON_CLICK
|| mRefreshType == REFRESH_ON_OVERFLOW_MENU
|| mRefreshType == REFRESH_ON_RESUME) {
showLoading(true);
} else if (mRefreshType == REFRESH_ON_PULL) {
}
}
@Override
protected List<SeafRepo> doInBackground(Void... params) {
try {
return dataManager.getReposFromServer();
} catch (SeafException e) {
err = e;
return null;
}
}
private void displaySSLError() {
if (mActivity == null)
return;
if (getNavContext().inRepo()) {
return;
}
showError(R.string.ssl_error);
}
private void resend() {
if (mActivity == null)
return;
if (getNavContext().inRepo()) {
return;
}
ConcurrentAsyncTask.execute(new LoadTask(dataManager));
}
// onPostExecute displays the results of the AsyncTask.
@Override
protected void onPostExecute(List<SeafRepo> rs) {
if (mActivity == null)
// this occurs if user navigation to another activity
return;
if (mRefreshType == REFRESH_ON_CLICK
|| mRefreshType == REFRESH_ON_OVERFLOW_MENU
|| mRefreshType == REFRESH_ON_RESUME) {
showLoading(false);
} else if (mRefreshType == REFRESH_ON_PULL) {
String lastUpdate = getDataManager().getLastPullToRefreshTime(DataManager.PULL_TO_REFRESH_LAST_TIME_FOR_REPOS_FRAGMENT);
//mListView.onRefreshComplete(lastUpdate);
refreshLayout.setRefreshing(false);
getDataManager().saveLastPullToRefreshTime(System.currentTimeMillis(), DataManager.PULL_TO_REFRESH_LAST_TIME_FOR_REPOS_FRAGMENT);
mPullToRefreshStopRefreshing = 0;
}
if (getNavContext().inRepo()) {
// this occurs if user already navigate into a repo
return;
}
// Prompt the user to accept the ssl certificate
if (err == SeafException.sslException) {
SslConfirmDialog dialog = new SslConfirmDialog(dataManager.getAccount(),
new SslConfirmDialog.Listener() {
@Override
public void onAccepted(boolean rememberChoice) {
Account account = dataManager.getAccount();
CertsManager.instance().saveCertForAccount(account, rememberChoice);
resend();
}
@Override
public void onRejected() {
displaySSLError();
}
});
dialog.show(getFragmentManager(), SslConfirmDialog.FRAGMENT_TAG);
return;
} else if (err == SeafException.remoteWipedException) {
mActivity.completeRemoteWipe();
}
if (err != null) {
if (err.getCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
// Token expired, should login again
mActivity.showShortToast(mActivity, R.string.err_token_expired);
mActivity.logoutWhenTokenExpired();
} else {
Log.e(DEBUG_TAG, "failed to load repos: " + err.getMessage());
showError(R.string.error_when_load_repos);
return;
}
}
if (rs != null) {
getDataManager().setReposRefreshTimeStamp();
updateAdapterWithRepos(rs, false);
} else {
Log.i(DEBUG_TAG, "failed to load repos");
showError(R.string.error_when_load_repos);
}
}
}
private void showError(int strID) {
showError(mActivity.getResources().getString(strID));
}
private void showError(String msg) {
mProgressContainer.setVisibility(View.GONE);
mListContainer.setVisibility(View.GONE);
adapter.clear();
adapter.notifyChanged();
mErrorText.setText(msg);
mErrorText.setVisibility(View.VISIBLE);
mErrorText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
refresh();
}
});
}
public void showLoading(boolean show) {
mErrorText.setVisibility(View.GONE);
if (show) {
mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
mActivity, android.R.anim.fade_in));
mListContainer.startAnimation(AnimationUtils.loadAnimation(
mActivity, android.R.anim.fade_out));
mProgressContainer.setVisibility(View.VISIBLE);
mListContainer.setVisibility(View.INVISIBLE);
} else {
mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
mActivity, android.R.anim.fade_out));
mListContainer.startAnimation(AnimationUtils.loadAnimation(
mActivity, android.R.anim.fade_in));
mProgressContainer.setVisibility(View.GONE);
mListContainer.setVisibility(View.VISIBLE);
}
}
private class LoadDirTask extends AsyncTask<String, Void, List<SeafDirent>> {
SeafException err = null;
String myRepoName;
String myRepoID;
String myPath;
DataManager dataManager;
public LoadDirTask(DataManager dataManager) {
this.dataManager = dataManager;
}
@Override
protected void onPreExecute() {
if (mRefreshType == REFRESH_ON_CLICK
|| mRefreshType == REFRESH_ON_OVERFLOW_MENU
|| mRefreshType == REFRESH_ON_RESUME) {
showLoading(true);
} else if (mRefreshType == REFRESH_ON_PULL) {
// mHeadProgress.setVisibility(ProgressBar.VISIBLE);
}
}
@Override
protected List<SeafDirent> doInBackground(String... params) {
if (params.length != 3) {
Log.d(DEBUG_TAG, "Wrong params to LoadDirTask");
return null;
}
myRepoName = params[0];
myRepoID = params[1];
myPath = params[2];
try {
return dataManager.getDirentsFromServer(myRepoID, myPath);
} catch (SeafException e) {
err = e;
return null;
}
}
private void resend() {
if (mActivity == null)
return;
NavContext nav = mActivity.getNavContext();
if (!myRepoID.equals(nav.getRepoID()) || !myPath.equals(nav.getDirPath())) {
return;
}
ConcurrentAsyncTask.execute(new LoadDirTask(dataManager), myRepoName, myRepoID, myPath);
}
private void displaySSLError() {
if (mActivity == null)
return;
NavContext nav = mActivity.getNavContext();
if (!myRepoID.equals(nav.getRepoID()) || !myPath.equals(nav.getDirPath())) {
return;
}
showError(R.string.ssl_error);
}
// onPostExecute displays the results of the AsyncTask.
@Override
protected void onPostExecute(List<SeafDirent> dirents) {
if (mActivity == null)
// this occurs if user navigation to another activity
return;
if (mRefreshType == REFRESH_ON_CLICK
|| mRefreshType == REFRESH_ON_OVERFLOW_MENU
|| mRefreshType == REFRESH_ON_RESUME) {
showLoading(false);
} else if (mRefreshType == REFRESH_ON_PULL) {
String lastUpdate = getDataManager().getLastPullToRefreshTime(DataManager.PULL_TO_REFRESH_LAST_TIME_FOR_REPOS_FRAGMENT);
//mListView.onRefreshComplete(lastUpdate);
refreshLayout.setRefreshing(false);
getDataManager().saveLastPullToRefreshTime(System.currentTimeMillis(), DataManager.PULL_TO_REFRESH_LAST_TIME_FOR_REPOS_FRAGMENT);
mPullToRefreshStopRefreshing = 0;
}
NavContext nav = mActivity.getNavContext();
if (!myRepoID.equals(nav.getRepoID()) || !myPath.equals(nav.getDirPath())) {
return;
}
if (err == SeafException.sslException) {
SslConfirmDialog dialog = new SslConfirmDialog(dataManager.getAccount(),
new SslConfirmDialog.Listener() {
@Override
public void onAccepted(boolean rememberChoice) {
Account account = dataManager.getAccount();
CertsManager.instance().saveCertForAccount(account, rememberChoice);
resend();
}
@Override
public void onRejected() {
displaySSLError();
}
});
dialog.show(getFragmentManager(), SslConfirmDialog.FRAGMENT_TAG);
return;
} else if (err == SeafException.remoteWipedException) {
mActivity.completeRemoteWipe();
}
if (err != null) {
if (err.getCode() == SeafConnection.HTTP_STATUS_REPO_PASSWORD_REQUIRED) {
showPasswordDialog();
} else if (err.getCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
// Token expired, should login again
mActivity.showShortToast(mActivity, R.string.err_token_expired);
mActivity.logoutWhenTokenExpired();
} else if (err.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
final String message = String.format(getString(R.string.op_exception_folder_deleted), myPath);
mActivity.showShortToast(mActivity, message);
} else {
Log.d(DEBUG_TAG, "failed to load dirents: " + err.getMessage());
err.printStackTrace();
showError(R.string.error_when_load_dirents);
}
return;
}
if (dirents == null) {
showError(R.string.error_when_load_dirents);
Log.i(DEBUG_TAG, "failed to load dir");
return;
}
getDataManager().setDirsRefreshTimeStamp(myRepoID, myPath);
updateAdapterWithDirents(dirents, false);
}
}
private void showPasswordDialog() {
NavContext nav = mActivity.getNavContext();
String repoName = nav.getRepoName();
String repoID = nav.getRepoID();
mActivity.showPasswordDialog(repoName, repoID, new TaskDialog.TaskDialogListener() {
@Override
public void onTaskSuccess() {
refreshView();
}
});
}
/**
* Represents a contextual mode of the user interface.
* Action modes can be used to provide alternative interaction modes and replace parts of the normal UI until finished.
* A Callback configures and handles events raised by a user's interaction with an action mode.
*/
class ActionModeCallback implements ActionMode.Callback {
private boolean allItemsSelected;
public ActionModeCallback() {
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate the menu for the contextual action bar (CAB)
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.repos_fragment_menu, menu);
if (adapter == null) return true;
adapter.setActionModeOn(true);
// to hidden "r" permissions files or folder
String permission = getNavContext().getDirPermission();
if (permission != null && permission.indexOf("w") == -1) {
menu.findItem(R.id.action_mode_delete).setVisible(false);
menu.findItem(R.id.action_mode_move).setVisible(false);
}
adapter.notifyDataSetChanged();
return true;
}
@SuppressLint("NewApi")
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
/*
* The ActionBarPolicy determines how many action button to place in the ActionBar
* and the default amount is 2.
*/
menu.findItem(R.id.action_mode_delete).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.findItem(R.id.action_mode_copy).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.findItem(R.id.action_mode_select_all).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
// Here you can perform updates to the contextual action bar (CAB) due to
// an invalidate() request
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Respond to clicks on the actions in the contextual action bar (CAB)
NavContext nav = mActivity.getNavContext();
String repoID = nav.getRepoID();
String repoName = nav.getRepoName();
String dirPath = nav.getDirPath();
final List<SeafDirent> selectedDirents = adapter.getSelectedItemsValues();
if (selectedDirents.size() == 0
|| repoID == null
|| dirPath == null) {
if (item.getItemId() != R.id.action_mode_select_all) {
mActivity.showShortToast(mActivity, R.string.action_mode_no_items_selected);
return true;
}
}
switch (item.getItemId()) {
case R.id.action_mode_select_all:
if (!allItemsSelected) {
if (adapter == null) return true;
adapter.selectAllItems();
updateContextualActionBar();
} else {
if (adapter == null) return true;
adapter.deselectAllItems();
updateContextualActionBar();
}
allItemsSelected = !allItemsSelected;
break;
case R.id.action_mode_delete:
mActivity.deleteFiles(repoID, dirPath, selectedDirents);
break;
case R.id.action_mode_copy:
mActivity.copyFiles(repoID, repoName, dirPath, selectedDirents);
break;
case R.id.action_mode_move:
mActivity.moveFiles(repoID, repoName, dirPath, selectedDirents);
break;
case R.id.action_mode_download:
mActivity.downloadFiles(repoID, repoName, dirPath, selectedDirents);
break;
default:
return false;
}
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
if (adapter == null) return;
adapter.setActionModeOn(false);
adapter.deselectAllItems();
// Here you can make any necessary updates to the activity when
// the contextual action bar (CAB) is removed. By default, selected items are deselected/unchecked.
mActionMode = null;
}
}
}