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