92177f4a28ea4d5ad0cb9f0ec9add952a72cc5c9
[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, fileIndex, targetFile.getFileName());
419 dialog.setTargetFragment(this, 0);
420 dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
421 }
422 }
423
424 /**
425 * Saves the current listed folder.
426 */
427 @Override
428 public void onSaveInstanceState(Bundle outState) {
429 super.onSaveInstanceState(outState);
430 outState.putParcelable(KEY_FILE, mFile);
431 }
432
433 /**
434 * Call this, when the user presses the up button.
435 * <p>
436 * Tries to move up the current folder one level. If the parent folder was removed from the
437 * database, it continues browsing up until finding an existing folders.
438 * </p>
439 * @return Count of folder levels browsed up.
440 */
441 public int onBrowseUp() {
442 OCFile parentDir = null;
443 int moveCount = 0;
444
445 if (mFile != null) {
446 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
447
448 String parentPath = null;
449 if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
450 parentPath = new File(mFile.getRemotePath()).getParent();
451 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
452 parentPath + OCFile.PATH_SEPARATOR;
453 parentDir = storageManager.getFileByPath(parentPath);
454 moveCount++;
455 } else {
456 parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);
457 }
458 while (parentDir == null) {
459 parentPath = new File(parentPath).getParent();
460 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
461 parentPath + OCFile.PATH_SEPARATOR;
462 parentDir = storageManager.getFileByPath(parentPath);
463 moveCount++;
464 } // exit is granted because storageManager.getFileByPath("/") never returns null
465 mFile = parentDir;
466
467 listDirectory(mFile, MainApp.getOnlyOnDevice());
468
469 onRefresh(false);
470
471 // restore index and top position
472 restoreIndexAndTopPosition();
473
474 } // else - should never happen now
475
476 return moveCount;
477 }
478
479 @Override
480 public void onItemClick(AdapterView<?> l, View v, int position, long id) {
481 OCFile file = (OCFile) mAdapter.getItem(position);
482 if (file != null) {
483 if (file.isFolder()) {
484 // update state and view of this fragment
485 listDirectory(file, MainApp.getOnlyOnDevice());
486 // then, notify parent activity to let it update its state and view
487 mContainerActivity.onBrowsedDownTo(file);
488 // save index and top position
489 saveIndexAndTopPosition(position);
490
491 } else { /// Click on a file
492 if (PreviewImageFragment.canBePreviewed(file)) {
493 // preview image - it handles the download, if needed
494 ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
495 } else if (PreviewTextFragment.canBePreviewed(file)){
496 ((FileDisplayActivity)mContainerActivity).startTextPreview(file);
497 } else if (PreviewMediaFragment.canBePreviewed(file)) {
498 // media preview
499 ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true);
500 } else if (file.isDown()) {
501 mContainerActivity.getFileOperationsHelper().openFile(file);
502 } else {
503 // automatic download, preview on finish
504 ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file);
505 }
506 }
507 } else {
508 Log_OC.d(TAG, "Null object in ListAdapter!!");
509 }
510 }
511
512 /**
513 * {@inheritDoc}
514 */
515 // TODO Tobi needed?
516 public void createContextMenu(Menu menu) {
517 Bundle args = getArguments();
518 boolean allowContextualActions =
519 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
520 if (allowContextualActions) {
521 MenuInflater inflater = getActivity().getMenuInflater();
522 inflater.inflate(R.menu.file_actions_menu, menu);
523 OCFile targetFile = null;
524 if (mAdapter.getCheckedItems().size() == 1){
525 targetFile = mAdapter.getCheckedItems().get(0);
526 }
527
528 if (mContainerActivity.getStorageManager() != null) {
529 FileMenuFilter mf = new FileMenuFilter(
530 targetFile,
531 mContainerActivity.getStorageManager().getAccount(),
532 mContainerActivity,
533 getActivity()
534 );
535 mf.filter(menu);
536 }
537
538 /// TODO break this direct dependency on FileDisplayActivity... if possible
539 MenuItem item = menu.findItem(R.id.action_open_file_with);
540 FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
541 if (frag != null && frag instanceof FileDetailFragment &&
542 frag.getFile().getFileId() == targetFile.getFileId()) {
543 item = menu.findItem(R.id.action_see_details);
544 if (item != null) {
545 item.setVisible(false);
546 item.setEnabled(false);
547 }
548 }
549
550 // String.format(mContext.getString(R.string.subject_token),
551 // getClient().getCredentials().getUsername(), file.getFileName()));
552 }
553 }
554
555 public boolean onFileActionChosen(int menuId) {
556 if (mAdapter.getCheckedItems().size() == 1){
557 OCFile mTargetFile = mAdapter.getCheckedItems().get(0);
558
559 switch (menuId) {
560 case R.id.action_share_file: {
561 mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
562 return true;
563 }
564 case R.id.action_open_file_with: {
565 mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
566 return true;
567 }
568 case R.id.action_unshare_file: {
569 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
570 return true;
571 }
572 case R.id.action_rename_file: {
573 RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
574 dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
575 return true;
576 }
577 case R.id.action_remove_file: {
578 RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
579 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
580 return true;
581 }
582 case R.id.action_download_file:
583 case R.id.action_sync_file: {
584 mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
585 return true;
586 }
587 case R.id.action_cancel_sync: {
588 ((FileDisplayActivity) mContainerActivity).cancelTransference(mTargetFile);
589 return true;
590 }
591 case R.id.action_see_details: {
592 mContainerActivity.showDetails(mTargetFile);
593 return true;
594 }
595 case R.id.action_send_file: {
596 // Obtain the file
597 if (!mTargetFile.isDown()) { // Download the file
598 Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
599 ((FileDisplayActivity) mContainerActivity).startDownloadForSending(mTargetFile);
600 return true;
601 } else {
602 mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
603 }
604 }
605 case R.id.action_stream_file: {
606 Account account = ((FileActivity)mContainerActivity).getAccount();
607 Context context = MainApp.getAppContext();
608 String uri = PreviewMediaFragment.generateUrlWithCredentials(account, context, mTargetFile);
609 MediaService.streamWithExternalApp(uri, getActivity()).show();
610 return true;
611 }
612 case R.id.action_move: {
613 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
614 ArrayList files = new ArrayList();
615 files.add(mTargetFile);
616 action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, files);
617 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
618 return true;
619 }
620 case R.id.action_favorite_file: {
621 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, true);
622 return true;
623 }
624 case R.id.action_unfavorite_file: {
625 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, false);
626 return true;
627 }
628 case R.id.action_copy:
629 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
630
631 // Pass mTargetFile that contains info of selected file/folder
632 action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
633 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
634 return true;
635 default:
636 return false;
637 }
638 } else {
639 ArrayList<OCFile> mTargetFiles = mAdapter.getCheckedItems();
640
641 switch (menuId) {
642 case R.id.action_remove_file: {
643 RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(mTargetFiles);
644 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
645 return true;
646 }
647 case R.id.action_download_file:
648 case R.id.action_sync_file: {
649 mContainerActivity.getFileOperationsHelper().syncFiles(mTargetFiles);
650 return true;
651 }
652 case R.id.action_move: {
653 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
654 action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, mTargetFiles);
655 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
656 return true;
657 }
658 case R.id.action_favorite_file: {
659 mContainerActivity.getFileOperationsHelper().toggleFavorites(mTargetFiles, true);
660 return true;
661 }
662 case R.id.action_unfavorite_file: {
663 mContainerActivity.getFileOperationsHelper().toggleFavorites(mTargetFiles, false);
664 return true;
665 }
666 case R.id.action_copy:
667 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
668 action.putParcelableArrayListExtra(FolderPickerActivity.EXTRA_FILES, mTargetFiles);
669 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
670 return true;
671 default:
672 return false;
673 }
674 }
675
676 }
677
678 /**
679 * {@inhericDoc}
680 */
681 @Override
682 public boolean onContextItemSelected (MenuItem item) {
683 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
684 boolean matched = onFileActionChosen(item.getItemId());
685 if(!matched) {
686 return super.onContextItemSelected(item);
687 } else {
688 return matched;
689 }
690 }
691
692
693 /**
694 * Use this to query the {@link OCFile} that is currently
695 * being displayed by this fragment
696 *
697 * @return The currently viewed OCFile
698 */
699 public OCFile getCurrentFile() {
700 return mFile;
701 }
702
703 /**
704 * Calls {@link OCFileListFragment#listDirectory(OCFile, boolean)} with a null parameter
705 */
706 public void listDirectory(boolean onlyOnDevice){
707 listDirectory(null, onlyOnDevice);
708 }
709
710 public void refreshDirectory(){
711 listDirectory(getCurrentFile(), MainApp.getOnlyOnDevice());
712 }
713
714 /**
715 * Lists the given directory on the view. When the input parameter is null,
716 * it will either refresh the last known directory. list the root
717 * if there never was a directory.
718 *
719 * @param directory File to be listed
720 */
721 public void listDirectory(OCFile directory, boolean onlyOnDevice) {
722 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
723 if (storageManager != null) {
724
725 // Check input parameters for null
726 if (directory == null) {
727 if (mFile != null) {
728 directory = mFile;
729 } else {
730 directory = storageManager.getFileByPath("/");
731 if (directory == null) return; // no files, wait for sync
732 }
733 }
734
735
736 // If that's not a directory -> List its parent
737 if (!directory.isFolder()) {
738 Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
739 directory = storageManager.getFileById(directory.getParentId());
740 }
741
742 mAdapter.swapDirectory(directory, storageManager, onlyOnDevice);
743 if (mFile == null || !mFile.equals(directory)) {
744 mCurrentListView.setSelection(0);
745 }
746 mFile = directory;
747
748 updateLayout();
749
750 }
751 }
752
753 private void updateLayout() {
754 if (!mJustFolders) {
755 int filesCount = 0, foldersCount = 0, imagesCount = 0;
756 int count = mAdapter.getCount();
757 OCFile file;
758 for (int i=0; i < count ; i++) {
759 file = (OCFile) mAdapter.getItem(i);
760 if (file.isFolder()) {
761 foldersCount++;
762 } else {
763 if (!file.isHidden()) {
764 filesCount++;
765
766 if (file.isImage() || file.isVideo()) {
767 imagesCount++;
768 }
769 }
770 }
771 }
772 // set footer text
773 setFooterText(generateFooterText(filesCount, foldersCount));
774
775 // decide grid vs list view
776 OwnCloudVersion version = AccountUtils.getServerVersion(
777 ((FileActivity)mContainerActivity).getAccount());
778 if (version != null && version.supportsRemoteThumbnails() &&
779 DisplayUtils.isGridView(mFile, mContainerActivity.getStorageManager())) {
780 switchToGridView();
781 registerLongClickListener();
782 } else {
783 switchToListView();
784 // switchToGridView();
785 }
786 }
787 }
788
789 private String generateFooterText(int filesCount, int foldersCount) {
790 String output;
791 if (filesCount <= 0) {
792 if (foldersCount <= 0) {
793 output = "";
794
795 } else if (foldersCount == 1) {
796 output = getResources().getString(R.string.file_list__footer__folder);
797
798 } else { // foldersCount > 1
799 output = getResources().getString(R.string.file_list__footer__folders, foldersCount);
800 }
801
802 } else if (filesCount == 1) {
803 if (foldersCount <= 0) {
804 output = getResources().getString(R.string.file_list__footer__file);
805
806 } else if (foldersCount == 1) {
807 output = getResources().getString(R.string.file_list__footer__file_and_folder);
808
809 } else { // foldersCount > 1
810 output = getResources().getString(R.string.file_list__footer__file_and_folders, foldersCount);
811 }
812 } else { // filesCount > 1
813 if (foldersCount <= 0) {
814 output = getResources().getString(R.string.file_list__footer__files, filesCount);
815
816 } else if (foldersCount == 1) {
817 output = getResources().getString(R.string.file_list__footer__files_and_folder, filesCount);
818
819 } else { // foldersCount > 1
820 output = getResources().getString(
821 R.string.file_list__footer__files_and_folders, filesCount, foldersCount
822 );
823
824 }
825 }
826 return output;
827 }
828
829 public void sortByName(boolean descending) {
830 mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
831 }
832
833 public void sortByDate(boolean descending) {
834 mAdapter.setSortOrder(FileStorageUtils.SORT_DATE, descending);
835 }
836
837 public void sortBySize(boolean descending) {
838 mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
839 }
840 }