Merge remote-tracking branch 'remotes/upstream/avoidDuplicateFiles' into beta
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / fragment / OCFileListFragment.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author Bartek Przybylski
5 * @author masensio
6 * @author David A. Velasco
7 * Copyright (C) 2011 Bartek Przybylski
8 * Copyright (C) 2015 ownCloud Inc.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23 package com.owncloud.android.ui.fragment;
24
25 import android.accounts.Account;
26 import android.app.Activity;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.content.SharedPreferences;
31 import android.os.Build;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.preference.PreferenceManager;
35 import android.support.v4.widget.SwipeRefreshLayout;
36 import android.view.ActionMode;
37 import android.support.v7.app.AlertDialog;
38 import android.view.ContextMenu;
39 import android.view.Menu;
40 import android.view.MenuInflater;
41 import android.view.MenuItem;
42 import android.view.View;
43 import android.widget.AbsListView;
44 import android.widget.AdapterView;
45 import android.widget.AdapterView.AdapterContextMenuInfo;
46 import android.widget.PopupMenu;
47 import android.widget.TextView;
48 import android.widget.Toast;
49
50 import com.owncloud.android.MainApp;
51 import com.owncloud.android.R;
52 import com.owncloud.android.authentication.AccountUtils;
53 import com.owncloud.android.datamodel.FileDataStorageManager;
54 import com.owncloud.android.datamodel.OCFile;
55 import com.owncloud.android.files.FileMenuFilter;
56 import com.owncloud.android.lib.common.utils.Log_OC;
57 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
58 import com.owncloud.android.media.MediaService;
59 import com.owncloud.android.ui.activity.FileActivity;
60 import com.owncloud.android.ui.activity.FileDisplayActivity;
61 import com.owncloud.android.ui.activity.FolderPickerActivity;
62 import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
63 import com.owncloud.android.ui.activity.UploadFilesActivity;
64 import com.owncloud.android.ui.adapter.FileListListAdapter;
65 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
66 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
67 import com.owncloud.android.ui.dialog.FileActionsDialogFragment;
68 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
69 import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
70 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
71 import com.owncloud.android.ui.dialog.UploadSourceDialogFragment;
72 import com.owncloud.android.ui.preview.PreviewImageFragment;
73 import com.owncloud.android.ui.preview.PreviewMediaFragment;
74 import com.owncloud.android.utils.DisplayUtils;
75 import com.owncloud.android.utils.ExceptionHandler;
76 import com.owncloud.android.utils.FileStorageUtils;
77 import com.owncloud.android.ui.preview.PreviewTextFragment;
78 import com.owncloud.android.utils.FileStorageUtils;
79
80 import java.io.File;
81 import java.util.ArrayList;
82
83 /**
84 * A Fragment that lists all files and folders in a given path.
85 *
86 * TODO refactor to get rid of direct dependency on FileDisplayActivity
87 */
88 public class OCFileListFragment extends ExtendedListFragment {
89
90 private static final String TAG = OCFileListFragment.class.getSimpleName();
91
92 private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ?
93 OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
94
95 public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
96 public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
97 public final static String ARG_HIDE_FAB = MY_PACKAGE + ".HIDE_FAB";
98
99 private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
100 private static final String KEY_FAB_EVER_CLICKED = "FAB_EVER_CLICKED";
101
102 private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
103
104 private FileFragment.ContainerActivity mContainerActivity;
105
106 private OCFile mFile = null;
107 private FileListListAdapter mAdapter;
108 private boolean mJustFolders;
109
110 private OCFile mTargetFile;
111
112 private boolean miniFabClicked = false;
113
114 /**
115 * {@inheritDoc}
116 */
117 @Override
118 public void onAttach(Activity activity) {
119 super.onAttach(activity);
120 Log_OC.e(TAG, "onAttach");
121 try {
122 mContainerActivity = (FileFragment.ContainerActivity) activity;
123
124 } catch (ClassCastException e) {
125 throw new ClassCastException(activity.toString() + " must implement " +
126 FileFragment.ContainerActivity.class.getSimpleName());
127 }
128 try {
129 setOnRefreshListener((OnEnforceableRefreshListener) activity);
130
131 } catch (ClassCastException e) {
132 throw new ClassCastException(activity.toString() + " must implement " +
133 SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
134 }
135 }
136
137
138 @Override
139 public void onDetach() {
140 setOnRefreshListener(null);
141 mContainerActivity = null;
142 super.onDetach();
143 }
144
145 /**
146 * {@inheritDoc}
147 */
148 @Override
149 public void onActivityCreated(Bundle savedInstanceState) {
150 super.onActivityCreated(savedInstanceState);
151 Log_OC.e(TAG, "onActivityCreated() start");
152
153 if (savedInstanceState != null) {
154 mFile = savedInstanceState.getParcelable(KEY_FILE);
155 }
156
157 if (mJustFolders) {
158 setFooterEnabled(false);
159 } else {
160 setFooterEnabled(true);
161 }
162
163 Bundle args = getArguments();
164 mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
165 mAdapter = new FileListListAdapter(
166 mJustFolders,
167 getActivity(),
168 mContainerActivity
169 );
170 setListAdapter(mAdapter);
171
172 registerLongClickListener();
173
174 boolean hideFab = (args != null) && args.getBoolean(ARG_HIDE_FAB, false);
175 if (hideFab) {
176 setFabEnabled(false);
177 } else {
178 setFabEnabled(true);
179 registerFabListeners();
180
181 // detect if a mini FAB has ever been clicked
182 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
183 if(prefs.getLong(KEY_FAB_EVER_CLICKED, 0) > 0) {
184 miniFabClicked = true;
185 }
186
187 // add labels to the min FABs when none of them has ever been clicked on
188 if(!miniFabClicked) {
189 setFabLabels();
190 } else {
191 removeFabLabels();
192 }
193 }
194 }
195
196 /**
197 * adds labels to all mini FABs.
198 */
199 private void setFabLabels() {
200 getFabUpload().setTitle(getResources().getString(R.string.actionbar_upload));
201 getFabMkdir().setTitle(getResources().getString(R.string.actionbar_mkdir));
202 getFabUploadFromApp().setTitle(getResources().getString(R.string.actionbar_upload_from_apps));
203 }
204
205 /**
206 * registers all listeners on all mini FABs.
207 */
208 private void registerFabListeners() {
209 registerFabUploadListeners();
210 registerFabMkDirListeners();
211 registerFabUploadFromAppListeners();
212 }
213
214 /**
215 * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
216 * on the Upload mini FAB for the linked action and {@link Toast} showing the underlying action.
217 */
218 private void registerFabUploadListeners() {
219 getFabUpload().setOnClickListener(new View.OnClickListener() {
220 @Override
221 public void onClick(View v) {
222 Intent action = new Intent(getActivity(), UploadFilesActivity.class);
223 action.putExtra(
224 UploadFilesActivity.EXTRA_ACCOUNT,
225 ((FileActivity) getActivity()).getAccount()
226 );
227 getActivity().startActivityForResult(action, UploadSourceDialogFragment.ACTION_SELECT_MULTIPLE_FILES);
228 getFabMain().collapse();
229 recordMiniFabClick();
230 }
231 });
232
233 getFabUpload().setOnLongClickListener(new View.OnLongClickListener() {
234 @Override
235 public boolean onLongClick(View v) {
236 Toast.makeText(getActivity(), R.string.actionbar_upload, Toast.LENGTH_SHORT).show();
237 return true;
238 }
239 });
240 }
241
242 /**
243 * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
244 * on the 'Create Dir' mini FAB for the linked action and {@link Toast} showing the underlying action.
245 */
246 private void registerFabMkDirListeners() {
247 getFabMkdir().setOnClickListener(new View.OnClickListener() {
248 @Override
249 public void onClick(View v) {
250 CreateFolderDialogFragment dialog =
251 CreateFolderDialogFragment.newInstance(mFile);
252 dialog.show(getActivity().getSupportFragmentManager(), FileDisplayActivity.DIALOG_CREATE_FOLDER);
253 getFabMain().collapse();
254 recordMiniFabClick();
255 }
256 });
257
258 getFabMkdir().setOnLongClickListener(new View.OnLongClickListener() {
259 @Override
260 public boolean onLongClick(View v) {
261 Toast.makeText(getActivity(), R.string.actionbar_mkdir, Toast.LENGTH_SHORT).show();
262 return true;
263 }
264 });
265 }
266
267 /**
268 * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
269 * on the Upload from App mini FAB for the linked action and {@link Toast} showing the underlying action.
270 */
271 private void registerFabUploadFromAppListeners() {
272 getFabUploadFromApp().setOnClickListener(new View.OnClickListener() {
273 @Override
274 public void onClick(View v) {
275 Intent action = new Intent(Intent.ACTION_GET_CONTENT);
276 action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
277
278 //Intent.EXTRA_ALLOW_MULTIPLE is only supported on api level 18+, Jelly Bean
279 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
280 action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
281 }
282
283 getActivity().startActivityForResult(
284 Intent.createChooser(action, getString(R.string.upload_chooser_title)),
285 UploadSourceDialogFragment.ACTION_SELECT_CONTENT_FROM_APPS
286 );
287 getFabMain().collapse();
288 recordMiniFabClick();
289 }
290 });
291
292 getFabUploadFromApp().setOnLongClickListener(new View.OnLongClickListener() {
293 @Override
294 public boolean onLongClick(View v) {
295 Toast.makeText(getActivity(),
296 R.string.actionbar_upload_from_apps,
297 Toast.LENGTH_SHORT).show();
298 return true;
299 }
300 });
301 }
302
303 /**
304 * records a click on a mini FAB and thus:
305 * <ol>
306 * <li>persists the click fact</li>
307 * <li>removes the mini FAB labels</li>
308 * </ol>
309 */
310 private void recordMiniFabClick() {
311 // only record if it hasn't been done already at some other time
312 if(!miniFabClicked) {
313 final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
314 sp.edit().putLong(KEY_FAB_EVER_CLICKED, 1).commit();
315 miniFabClicked = true;
316 }
317 }
318
319 /**
320 * removes the labels on all known min FABs.
321 */
322 private void removeFabLabels() {
323 getFabUpload().setTitle(null);
324 getFabMkdir().setTitle(null);
325 getFabUploadFromApp().setTitle(null);
326 ((TextView) getFabUpload().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
327 ((TextView) getFabMkdir().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
328 ((TextView) getFabUploadFromApp().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
329 }
330
331 private void registerLongClickListener() {
332 getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
333 private Menu menu;
334
335 @Override
336 public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
337 final int checkedCount = getListView().getCheckedItemCount();
338 // TODO Tobi extract to values
339 mode.setTitle(checkedCount + " selected");
340
341 if (checked) {
342 mAdapter.setNewSelection(position, checked);
343 } else {
344 mAdapter.removeSelection(position);
345 }
346
347 // TODO maybe change: only recreate menu if count changes
348 menu.clear();
349 if (checkedCount == 1) {
350 createContextMenu(menu);
351 } else {
352 // download, move, copy, delete
353 getActivity().getMenuInflater().inflate(R.menu.multiple_file_actions_menu, menu);
354 }
355
356 }
357
358 @Override
359 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
360 this.menu = menu;
361 return true;
362 }
363
364 @Override
365 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
366 return false;
367 }
368
369 @Override
370 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
371 return onFileActionChosen(item.getItemId());
372 }
373
374 @Override
375 public void onDestroyActionMode(ActionMode mode) {
376 mAdapter.removeSelection();
377 }
378 });
379 }
380
381
382 private void showFileAction(int fileIndex) {
383 Bundle args = getArguments();
384 PopupMenu pm = new PopupMenu(getActivity(),null);
385 Menu menu = pm.getMenu();
386
387 boolean allowContextualActions =
388 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
389
390 if (allowContextualActions) {
391 MenuInflater inflater = getActivity().getMenuInflater();
392
393 inflater.inflate(R.menu.file_actions_menu, menu);
394 OCFile targetFile = (OCFile) mAdapter.getItem(fileIndex);
395
396 if (mContainerActivity.getStorageManager() != null) {
397 FileMenuFilter mf = new FileMenuFilter(
398 targetFile,
399 mContainerActivity.getStorageManager().getAccount(),
400 mContainerActivity,
401 getActivity()
402 );
403 mf.filter(menu);
404 }
405
406 /// TODO break this direct dependency on FileDisplayActivity... if possible
407 MenuItem item = menu.findItem(R.id.action_open_file_with);
408 FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
409 if (frag != null && frag instanceof FileDetailFragment &&
410 frag.getFile().getFileId() == targetFile.getFileId()) {
411 item = menu.findItem(R.id.action_see_details);
412 if (item != null) {
413 item.setVisible(false);
414 item.setEnabled(false);
415 }
416 }
417
418 FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu,
419 fileIndex, targetFile.getFileName());
420 dialog.setTargetFragment(this, 0);
421 dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
422 }
423 }
424
425 /**
426 * Saves the current listed folder.
427 */
428 @Override
429 public void onSaveInstanceState(Bundle outState) {
430 super.onSaveInstanceState(outState);
431 outState.putParcelable(KEY_FILE, mFile);
432 }
433
434 /**
435 * Call this, when the user presses the up button.
436 * <p>
437 * Tries to move up the current folder one level. If the parent folder was removed from the
438 * database, it continues browsing up until finding an existing folders.
439 * </p>
440 * @return Count of folder levels browsed up.
441 */
442 public int onBrowseUp() {
443 OCFile parentDir = null;
444 int moveCount = 0;
445
446 if (mFile != null) {
447 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
448
449 String parentPath = null;
450 if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
451 parentPath = new File(mFile.getRemotePath()).getParent();
452 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
453 parentPath + OCFile.PATH_SEPARATOR;
454 parentDir = storageManager.getFileByPath(parentPath);
455 moveCount++;
456 } else {
457 parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);
458 }
459 while (parentDir == null) {
460 parentPath = new File(parentPath).getParent();
461 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
462 parentPath + OCFile.PATH_SEPARATOR;
463 parentDir = storageManager.getFileByPath(parentPath);
464 moveCount++;
465 } // exit is granted because storageManager.getFileByPath("/") never returns null
466 mFile = parentDir;
467
468 listDirectory(mFile, MainApp.getOnlyOnDevice());
469
470 onRefresh(false);
471
472 // restore index and top position
473 restoreIndexAndTopPosition();
474
475 } // else - should never happen now
476
477 return moveCount;
478 }
479
480 @Override
481 public void onItemClick(AdapterView<?> l, View v, int position, long id) {
482 OCFile file = (OCFile) mAdapter.getItem(position);
483 if (file != null) {
484 if (file.isFolder()) {
485 // update state and view of this fragment
486 listDirectory(file, MainApp.getOnlyOnDevice());
487 // then, notify parent activity to let it update its state and view
488 mContainerActivity.onBrowsedDownTo(file);
489 // save index and top position
490 saveIndexAndTopPosition(position);
491
492 } else { /// Click on a file
493 if (PreviewImageFragment.canBePreviewed(file)) {
494 // preview image - it handles the download, if needed
495 ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
496 } else if (PreviewTextFragment.canBePreviewed(file)){
497 ((FileDisplayActivity)mContainerActivity).startTextPreview(file);
498 } else if (PreviewMediaFragment.canBePreviewed(file)) {
499 // media preview
500 ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true);
501 } else if (file.isDown()) {
502 mContainerActivity.getFileOperationsHelper().openFile(file);
503 } else {
504 // automatic download, preview on finish
505 ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file);
506 }
507 }
508 } else {
509 Log_OC.d(TAG, "Null object in ListAdapter!!");
510 }
511 }
512
513 /**
514 * {@inheritDoc}
515 */
516 // TODO Tobi needed?
517 public void createContextMenu(Menu menu) {
518 Bundle args = getArguments();
519 boolean allowContextualActions =
520 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
521 if (allowContextualActions) {
522 MenuInflater inflater = getActivity().getMenuInflater();
523 inflater.inflate(R.menu.file_actions_menu, menu);
524 OCFile targetFile = null;
525 if (mAdapter.getCheckedItems().size() == 1){
526 targetFile = mAdapter.getCheckedItems().get(0);
527 }
528
529 if (mContainerActivity.getStorageManager() != null) {
530 FileMenuFilter mf = new FileMenuFilter(
531 targetFile,
532 mContainerActivity.getStorageManager().getAccount(),
533 mContainerActivity,
534 getActivity()
535 );
536 mf.filter(menu);
537 }
538
539 /// TODO break this direct dependency on FileDisplayActivity... if possible
540 MenuItem item = menu.findItem(R.id.action_open_file_with);
541 FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
542 if (frag != null && frag instanceof FileDetailFragment &&
543 frag.getFile().getFileId() == targetFile.getFileId()) {
544 item = menu.findItem(R.id.action_see_details);
545 if (item != null) {
546 item.setVisible(false);
547 item.setEnabled(false);
548 }
549 }
550
551 // String.format(mContext.getString(R.string.subject_token),
552 // getClient().getCredentials().getUsername(), file.getFileName()));
553 }
554 }
555
556 public boolean onFileActionChosen(int menuId) {
557 if (mAdapter.getCheckedItems().size() == 1){
558 OCFile mTargetFile = mAdapter.getCheckedItems().get(0);
559
560 switch (menuId) {
561 case R.id.action_share_file: {
562 mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
563 return true;
564 }
565 case R.id.action_share_with_users: {
566 mContainerActivity.getFileOperationsHelper().showShareFile(mTargetFile);
567 return true;
568 }
569 case R.id.action_open_file_with: {
570 mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
571 return true;
572 }
573 case R.id.action_unshare_file: {
574 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
575 return true;
576 }
577 case R.id.action_rename_file: {
578 RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
579 dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
580 return true;
581 }
582 case R.id.action_remove_file: {
583 RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
584 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
585 return true;
586 }
587 case R.id.action_download_file:
588 case R.id.action_sync_file: {
589 mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
590 return true;
591 }
592 case R.id.action_cancel_sync: {
593 ((FileDisplayActivity) mContainerActivity).cancelTransference(mTargetFile);
594 return true;
595 }
596 case R.id.action_see_details: {
597 mContainerActivity.showDetails(mTargetFile);
598 return true;
599 }
600 case R.id.action_send_file: {
601 // Obtain the file
602 if (!mTargetFile.isDown()) { // Download the file
603 Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
604 ((FileDisplayActivity) mContainerActivity).startDownloadForSending(mTargetFile);
605 return true;
606 } else {
607 mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
608 }
609 }
610 case R.id.action_stream_file: {
611 Account account = ((FileActivity)mContainerActivity).getAccount();
612 Context context = MainApp.getAppContext();
613 String uri = PreviewMediaFragment.generateUrlWithCredentials(account, context, mTargetFile);
614 MediaService.streamWithExternalApp(uri, getActivity()).show();
615 return true;
616 }
617 case R.id.action_move: {
618 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
619 ArrayList files = new ArrayList();
620 files.add(mTargetFile);
621 action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, files);
622 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
623 return true;
624 }
625 case R.id.action_favorite_file: {
626 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, true);
627 return true;
628 }
629 case R.id.action_unfavorite_file: {
630 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, false);
631 return true;
632 }
633 case R.id.action_copy:
634 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
635 ArrayList files = new ArrayList();
636 files.add(mTargetFile);
637 action.putExtra(FolderPickerActivity.EXTRA_FILES, files);
638 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
639 return true;
640 default:
641 return false;
642 }
643 } else {
644 ArrayList<OCFile> mTargetFiles = mAdapter.getCheckedItems();
645
646 switch (menuId) {
647 case R.id.action_remove_file: {
648 RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(mTargetFiles);
649 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
650 return true;
651 }
652 case R.id.action_download_file:
653 case R.id.action_sync_file: {
654 mContainerActivity.getFileOperationsHelper().syncFiles(mTargetFiles);
655 return true;
656 }
657 case R.id.action_move: {
658 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
659 action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, mTargetFiles);
660 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
661 return true;
662 }
663 case R.id.action_favorite_file: {
664 mContainerActivity.getFileOperationsHelper().toggleFavorites(mTargetFiles, true);
665 return true;
666 }
667 case R.id.action_unfavorite_file: {
668 mContainerActivity.getFileOperationsHelper().toggleFavorites(mTargetFiles, false);
669 return true;
670 }
671 case R.id.action_copy:
672 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
673 action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, mTargetFiles);
674 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
675 return true;
676 default:
677 return false;
678 }
679 }
680 }
681
682 /**
683 * {@inhericDoc}
684 */
685 @Override
686 public boolean onContextItemSelected (MenuItem item) {
687 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
688 boolean matched = onFileActionChosen(item.getItemId()) ;
689 if(!matched) {
690 return super.onContextItemSelected(item);
691 } else {
692 return matched;
693 }
694 }
695
696
697 /**
698 * Use this to query the {@link OCFile} that is currently
699 * being displayed by this fragment
700 *
701 * @return The currently viewed OCFile
702 */
703 public OCFile getCurrentFile() {
704 return mFile;
705 }
706
707 /**
708 * Calls {@link OCFileListFragment#listDirectory(OCFile, boolean)} with a null parameter
709 */
710 public void listDirectory(boolean onlyOnDevice){
711 listDirectory(null, onlyOnDevice);
712 }
713
714 public void refreshDirectory(){
715 listDirectory(getCurrentFile(), MainApp.getOnlyOnDevice());
716 }
717
718 /**
719 * Lists the given directory on the view. When the input parameter is null,
720 * it will either refresh the last known directory. list the root
721 * if there never was a directory.
722 *
723 * @param directory File to be listed
724 */
725 public void listDirectory(OCFile directory, boolean onlyOnDevice) {
726 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
727 if (storageManager != null) {
728
729 // Check input parameters for null
730 if (directory == null) {
731 if (mFile != null) {
732 directory = mFile;
733 } else {
734 directory = storageManager.getFileByPath("/");
735 if (directory == null) return; // no files, wait for sync
736 }
737 }
738
739
740 // If that's not a directory -> List its parent
741 if (!directory.isFolder()) {
742 Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
743 directory = storageManager.getFileById(directory.getParentId());
744 }
745
746 mAdapter.swapDirectory(directory, storageManager, onlyOnDevice);
747 if (mFile == null || !mFile.equals(directory)) {
748 mCurrentListView.setSelection(0);
749 }
750 mFile = directory;
751
752 updateLayout();
753
754 }
755 }
756
757 private void updateLayout() {
758 if (!mJustFolders) {
759 int filesCount = 0, foldersCount = 0, imagesCount = 0;
760 int count = mAdapter.getCount();
761 OCFile file;
762 for (int i=0; i < count ; i++) {
763 file = (OCFile) mAdapter.getItem(i);
764 if (file.isFolder()) {
765 foldersCount++;
766 } else {
767 if (!file.isHidden()) {
768 filesCount++;
769
770 if (file.isImage() || file.isVideo()) {
771 imagesCount++;
772 }
773 }
774 }
775 }
776 // set footer text
777 setFooterText(generateFooterText(filesCount, foldersCount));
778
779 // decide grid vs list view
780 OwnCloudVersion version = AccountUtils.getServerVersion(
781 ((FileActivity)mContainerActivity).getAccount());
782 if (version != null && version.supportsRemoteThumbnails() &&
783 DisplayUtils.isGridView(mFile, mContainerActivity.getStorageManager())) {
784 switchToGridView();
785 registerLongClickListener();
786 } else {
787 switchToListView();
788 // switchToGridView();
789 }
790 }
791 }
792
793 private String generateFooterText(int filesCount, int foldersCount) {
794 String output;
795 if (filesCount <= 0) {
796 if (foldersCount <= 0) {
797 output = "";
798
799 } else if (foldersCount == 1) {
800 output = getResources().getString(R.string.file_list__footer__folder);
801
802 } else { // foldersCount > 1
803 output = getResources().getString(R.string.file_list__footer__folders, foldersCount);
804 }
805
806 } else if (filesCount == 1) {
807 if (foldersCount <= 0) {
808 output = getResources().getString(R.string.file_list__footer__file);
809
810 } else if (foldersCount == 1) {
811 output = getResources().getString(R.string.file_list__footer__file_and_folder);
812
813 } else { // foldersCount > 1
814 output = getResources().getString(R.string.file_list__footer__file_and_folders, foldersCount);
815 }
816 } else { // filesCount > 1
817 if (foldersCount <= 0) {
818 output = getResources().getString(R.string.file_list__footer__files, filesCount);
819
820 } else if (foldersCount == 1) {
821 output = getResources().getString(R.string.file_list__footer__files_and_folder, filesCount);
822
823 } else { // foldersCount > 1
824 output = getResources().getString(
825 R.string.file_list__footer__files_and_folders, filesCount, foldersCount
826 );
827
828 }
829 }
830 return output;
831 }
832
833 public void sortByName(boolean descending) {
834 mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
835 }
836
837 public void sortByDate(boolean descending) {
838 mAdapter.setSortOrder(FileStorageUtils.SORT_DATE, descending);
839 }
840
841 public void sortBySize(boolean descending) {
842 mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
843 }
844 }