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