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