wip
[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.accounts.AccountManager;
27 import android.accounts.AuthenticatorException;
28 import android.accounts.OperationCanceledException;
29 import android.app.Activity;
30 import android.content.ActivityNotFoundException;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.DialogInterface;
34 import android.content.Intent;
35 import android.net.Uri;
36 import android.os.Bundle;
37 import android.support.v4.widget.SwipeRefreshLayout;
38 import android.support.v7.app.AlertDialog;
39 import android.view.ContextMenu;
40 import android.view.Menu;
41 import android.view.MenuInflater;
42 import android.view.MenuItem;
43 import android.view.View;
44 import android.widget.AdapterView;
45 import android.widget.AdapterView.AdapterContextMenuInfo;
46 import android.widget.PopupMenu;
47
48 import com.owncloud.android.MainApp;
49 import com.owncloud.android.R;
50 import com.owncloud.android.lib.common.OwnCloudBasicCredentials;
51 import com.owncloud.android.lib.common.OwnCloudCredentials;
52 import com.owncloud.android.lib.common.accounts.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.ui.activity.FileActivity;
59 import com.owncloud.android.ui.activity.FileDisplayActivity;
60 import com.owncloud.android.ui.activity.FolderPickerActivity;
61 import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
62 import com.owncloud.android.ui.adapter.FileListListAdapter;
63 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
64 import com.owncloud.android.ui.dialog.FileActionsDialogFragment;
65 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
66 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
67 import com.owncloud.android.ui.preview.PreviewImageFragment;
68 import com.owncloud.android.ui.preview.PreviewMediaFragment;
69 import com.owncloud.android.utils.FileStorageUtils;
70 import com.owncloud.android.ui.preview.PreviewTextFragment;
71
72 import java.io.File;
73 import java.io.IOException;
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 implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
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
90 private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
91
92 private FileFragment.ContainerActivity mContainerActivity;
93
94 private OCFile mFile = null;
95 private FileListListAdapter mAdapter;
96 private boolean mJustFolders;
97
98 private OCFile mTargetFile;
99
100
101
102 /**
103 * {@inheritDoc}
104 */
105 @Override
106 public void onAttach(Activity activity) {
107 super.onAttach(activity);
108 Log_OC.e(TAG, "onAttach");
109 try {
110 mContainerActivity = (FileFragment.ContainerActivity) activity;
111
112 } catch (ClassCastException e) {
113 throw new ClassCastException(activity.toString() + " must implement " +
114 FileFragment.ContainerActivity.class.getSimpleName());
115 }
116 try {
117 setOnRefreshListener((OnEnforceableRefreshListener) activity);
118
119 } catch (ClassCastException e) {
120 throw new ClassCastException(activity.toString() + " must implement " +
121 SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
122 }
123 }
124
125
126 @Override
127 public void onDetach() {
128 setOnRefreshListener(null);
129 mContainerActivity = null;
130 super.onDetach();
131 }
132
133 /**
134 * {@inheritDoc}
135 */
136 @Override
137 public void onActivityCreated(Bundle savedInstanceState) {
138 super.onActivityCreated(savedInstanceState);
139 Log_OC.e(TAG, "onActivityCreated() start");
140
141 if (savedInstanceState != null) {
142 mFile = savedInstanceState.getParcelable(KEY_FILE);
143 }
144
145 if (mJustFolders) {
146 setFooterEnabled(false);
147 } else {
148 setFooterEnabled(true);
149 }
150
151 Bundle args = getArguments();
152 mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
153 mAdapter = new FileListListAdapter(
154 mJustFolders,
155 getActivity(),
156 mContainerActivity
157 );
158 setListAdapter(mAdapter);
159
160 registerLongClickListener();
161 }
162
163 private void registerLongClickListener() {
164 getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
165 public boolean onItemLongClick(AdapterView<?> arg0, View v,
166 int index, long arg3) {
167 showFileAction(index);
168 return true;
169 }
170 });
171 }
172
173
174 private void showFileAction(int fileIndex) {
175 Bundle args = getArguments();
176 PopupMenu pm = new PopupMenu(getActivity(),null);
177 Menu menu = pm.getMenu();
178
179 boolean allowContextualActions =
180 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
181
182 if (allowContextualActions) {
183 MenuInflater inflater = getActivity().getMenuInflater();
184
185 inflater.inflate(R.menu.file_actions_menu, menu);
186 OCFile targetFile = (OCFile) mAdapter.getItem(fileIndex);
187
188 if (mContainerActivity.getStorageManager() != null) {
189 FileMenuFilter mf = new FileMenuFilter(
190 targetFile,
191 mContainerActivity.getStorageManager().getAccount(),
192 mContainerActivity,
193 getActivity()
194 );
195 mf.filter(menu);
196 }
197
198 /// TODO break this direct dependency on FileDisplayActivity... if possible
199 MenuItem item = menu.findItem(R.id.action_open_file_with);
200 FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
201 if (frag != null && frag instanceof FileDetailFragment &&
202 frag.getFile().getFileId() == targetFile.getFileId()) {
203 item = menu.findItem(R.id.action_see_details);
204 if (item != null) {
205 item.setVisible(false);
206 item.setEnabled(false);
207 }
208 }
209
210 FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu, fileIndex, targetFile.getFileName());
211 dialog.setTargetFragment(this, 0);
212 dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
213 }
214 }
215
216 /**
217 * Saves the current listed folder.
218 */
219 @Override
220 public void onSaveInstanceState(Bundle outState) {
221 super.onSaveInstanceState(outState);
222 outState.putParcelable(KEY_FILE, mFile);
223 }
224
225 /**
226 * Call this, when the user presses the up button.
227 *
228 * Tries to move up the current folder one level. If the parent folder was removed from the
229 * database, it continues browsing up until finding an existing folders.
230 * <p/>
231 * return Count of folder levels browsed up.
232 */
233 public int onBrowseUp() {
234 OCFile parentDir = null;
235 int moveCount = 0;
236
237 if (mFile != null) {
238 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
239
240 String parentPath = null;
241 if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
242 parentPath = new File(mFile.getRemotePath()).getParent();
243 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
244 parentPath + OCFile.PATH_SEPARATOR;
245 parentDir = storageManager.getFileByPath(parentPath);
246 moveCount++;
247 } else {
248 parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);
249 }
250 while (parentDir == null) {
251 parentPath = new File(parentPath).getParent();
252 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
253 parentPath + OCFile.PATH_SEPARATOR;
254 parentDir = storageManager.getFileByPath(parentPath);
255 moveCount++;
256 } // exit is granted because storageManager.getFileByPath("/") never returns null
257 mFile = parentDir;
258
259 // TODO Enable when "On Device" is recovered ?
260 listDirectory(mFile /*, MainApp.getOnlyOnDevice()*/);
261
262 onRefresh(false);
263
264 // restore index and top position
265 restoreIndexAndTopPosition();
266
267 } // else - should never happen now
268
269 return moveCount;
270 }
271
272 @Override
273 public void onItemClick(AdapterView<?> l, View v, int position, long id) {
274 OCFile file = (OCFile) mAdapter.getItem(position);
275 if (file != null) {
276 if (file.isFolder()) {
277 // update state and view of this fragment
278 // TODO Enable when "On Device" is recovered ?
279 listDirectory(file/*, MainApp.getOnlyOnDevice()*/);
280 // then, notify parent activity to let it update its state and view
281 mContainerActivity.onBrowsedDownTo(file);
282 // save index and top position
283 saveIndexAndTopPosition(position);
284
285 } else { /// Click on a file
286 if (PreviewImageFragment.canBePreviewed(file)) {
287 // preview image - it handles the download, if needed
288 ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
289 } else if (PreviewTextFragment.canBePreviewed(file)){
290 ((FileDisplayActivity)mContainerActivity).startTextPreview(file);
291 } else if (PreviewMediaFragment.canBePreviewed(file)) {
292 // media preview
293 ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true);
294 } else if (file.isDown()) {
295 mContainerActivity.getFileOperationsHelper().openFile(file);
296 }
297 else {
298 // automatic download, preview on finish
299 ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file);
300 }
301
302 }
303
304 } else {
305 Log_OC.d(TAG, "Null object in ListAdapter!!");
306 }
307
308 }
309
310 /**
311 * {@inheritDoc}
312 */
313 @Override
314 public void onCreateContextMenu(
315 ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
316 Bundle args = getArguments();
317 boolean allowContextualActions =
318 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
319 if (allowContextualActions) {
320 MenuInflater inflater = getActivity().getMenuInflater();
321 inflater.inflate(R.menu.file_actions_menu, menu);
322 AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
323 OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
324
325 if (mContainerActivity.getStorageManager() != null) {
326 FileMenuFilter mf = new FileMenuFilter(
327 targetFile,
328 mContainerActivity.getStorageManager().getAccount(),
329 mContainerActivity,
330 getActivity()
331 );
332 mf.filter(menu);
333 }
334
335 /// TODO break this direct dependency on FileDisplayActivity... if possible
336 MenuItem item = menu.findItem(R.id.action_open_file_with);
337 FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
338 if (frag != null && frag instanceof FileDetailFragment &&
339 frag.getFile().getFileId() == targetFile.getFileId()) {
340 item = menu.findItem(R.id.action_see_details);
341 if (item != null) {
342 item.setVisible(false);
343 item.setEnabled(false);
344 }
345 }
346 }
347 }
348
349 /**
350 * {@inheritDoc}
351 */
352 @Override
353 public boolean onFileActionChosen(int menuId, int filePosition) {
354 mTargetFile = (OCFile) mAdapter.getItem(filePosition);
355 switch (menuId) {
356 case R.id.action_share_file: {
357 mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
358 return true;
359 }
360 case R.id.action_open_file_with: {
361 mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
362 return true;
363 }
364 case R.id.action_unshare_file: {
365 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
366 return true;
367 }
368 case R.id.action_rename_file: {
369 RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
370 dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
371 return true;
372 }
373 case R.id.action_remove_file: {
374 RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
375 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
376 return true;
377 }
378 case R.id.action_download_file:
379 case R.id.action_sync_file: {
380 mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
381 return true;
382 }
383 case R.id.action_cancel_download:
384 case R.id.action_cancel_upload: {
385 ((FileDisplayActivity) mContainerActivity).cancelTransference(mTargetFile);
386 return true;
387 }
388 case R.id.action_see_details: {
389 mContainerActivity.showDetails(mTargetFile);
390 return true;
391 }
392 case R.id.action_send_file: {
393 // Obtain the file
394 // if (!mTargetFile.isDown()) { // Download the file
395 // Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
396 // ((FileDisplayActivity) mContainerActivity).startDownloadForSending(mTargetFile);
397 //
398 // } else {
399 // mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
400
401 // String url = "https://test:teddy03@192.168.0.100/owncloud/remote.php/webdav/2/1.ogg";
402 // String url = "https://test:test@demo.owncloud.org/remote.php/webdav/Demo%20Movie%20OGG%20-%20Big%20Buck%20Bunny%20Trailer.ogg";
403
404
405 // try{
406 // Intent i = new Intent(Intent.ACTION_VIEW);
407 // i.setComponent(new ComponentName("org.videolan.vlc.betav7neon", "org.videolan.vlc.betav7neon.gui.video.VideoPlayerActivity"));
408 // i.setData(Uri.parse(url));
409 // startActivity(i);
410 // }
411 // catch (ActivityNotFoundException e){
412 // Uri uri = Uri.parse("http://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon");
413 // Intent intent = new Intent (Intent.ACTION_VIEW, uri);
414 // startActivity(intent);
415 // }
416 //
417
418 // TODO TOBI neuer Menüpunkt: Stream
419
420 try {
421 Context context = MainApp.getAppContext();
422 Account account = mContainerActivity.getStorageManager().getAccount();
423 String url = AccountUtils.constructFullURLForAccount(context, account) + mTargetFile.getRemotePath();
424
425 OwnCloudCredentials credentials = AccountUtils.getCredentialsForAccount(context, account);
426
427 url = url.replace("//", "//" + credentials.getUsername() + ":" + credentials.getAuthToken() + "@");
428
429 Log_OC.d(TAG, "Streaming url: " + url);
430 // VLC
431 Intent i = new Intent(Intent.ACTION_VIEW);
432 i.setComponent(new ComponentName("org.videolan.vlc.betav7neon", "org.videolan.vlc.betav7neon.gui.video.VideoPlayerActivity"));
433 i.setData(Uri.parse(url));
434 startActivity(i);
435
436 // MX
437 // Intent i = new Intent(android.content.Intent.ACTION_VIEW);
438 // i.setData(Uri.parse(url));
439 // startActivity(i);
440 } catch (AccountUtils.AccountNotFoundException e) {
441 e.printStackTrace();
442 }
443 catch (ActivityNotFoundException e) {
444 // VLC
445 Uri uri = Uri.parse("http://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon");
446 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
447 startActivity(intent);
448 } catch (AuthenticatorException e) {
449 e.printStackTrace();
450 } catch (OperationCanceledException e) {
451 e.printStackTrace();
452 } catch (IOException e) {
453 e.printStackTrace();
454 }
455
456
457 // }
458 return true;
459 }
460 case R.id.action_stream_file: {
461 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
462 builder.setMessage("May expose password?")
463 .setPositiveButton("Stream", new DialogInterface.OnClickListener() {
464 public void onClick(DialogInterface dialog, int id) {
465 Account account = ((FileActivity)mContainerActivity).getAccount();
466 Context context = MainApp.getAppContext();
467 String uri = PreviewMediaFragment.generateUrlWithCredentials(account, context, mTargetFile);
468
469 Intent i = new Intent(android.content.Intent.ACTION_VIEW);
470 i.setData(Uri.parse(uri));
471 startActivity(i);
472
473 // Intent i = new Intent(Intent.ACTION_VIEW);
474 // i.setComponent(new ComponentName("org.videolan.vlc", "org.videolan.vlc.gui.video.VideoPlayerActivity"));
475 // i.setData(Uri.parse(uri));
476 // startActivity(i);
477 }
478 })
479 .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
480 public void onClick(DialogInterface dialog, int id) {
481 // User cancelled the dialog
482 }
483 });
484 builder.show();
485
486 return true;
487 }
488 case R.id.action_move: {
489 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
490
491 // Pass mTargetFile that contains info of selected file/folder
492 action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
493 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
494 return true;
495 }
496 case R.id.action_favorite_file: {
497 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, true);
498 return true;
499 }
500 case R.id.action_unfavorite_file: {
501 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, false);
502 return true;
503 }
504 case R.id.action_copy:
505 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
506
507 // Pass mTargetFile that contains info of selected file/folder
508 action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
509 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
510 return true;
511 default:
512 return false;
513 }
514 }
515
516 /**
517 * {@inhericDoc}
518 */
519 @Override
520 public boolean onContextItemSelected (MenuItem item) {
521 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
522 boolean matched = onFileActionChosen(item.getItemId(), ((AdapterContextMenuInfo) item.getMenuInfo()).position);
523 if(!matched) {
524 return super.onContextItemSelected(item);
525 } else {
526 return matched;
527 }
528 }
529
530
531 /**
532 * Use this to query the {@link OCFile} that is currently
533 * being displayed by this fragment
534 *
535 * @return The currently viewed OCFile
536 */
537 public OCFile getCurrentFile() {
538 return mFile;
539 }
540
541 /**
542 * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
543 */
544 public void listDirectory(/*boolean onlyOnDevice*/){
545 listDirectory(null);
546 // TODO Enable when "On Device" is recovered ?
547 // listDirectory(null, onlyOnDevice);
548 }
549
550 public void refreshDirectory(){
551 // TODO Enable when "On Device" is recovered ?
552 listDirectory(getCurrentFile()/*, MainApp.getOnlyOnDevice()*/);
553 }
554
555 /**
556 * Lists the given directory on the view. When the input parameter is null,
557 * it will either refresh the last known directory. list the root
558 * if there never was a directory.
559 *
560 * @param directory File to be listed
561 */
562 public void listDirectory(OCFile directory/*, boolean onlyOnDevice*/) {
563 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
564 if (storageManager != null) {
565
566 // Check input parameters for null
567 if (directory == null) {
568 if (mFile != null) {
569 directory = mFile;
570 } else {
571 directory = storageManager.getFileByPath("/");
572 if (directory == null) return; // no files, wait for sync
573 }
574 }
575
576
577 // If that's not a directory -> List its parent
578 if (!directory.isFolder()) {
579 Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
580 directory = storageManager.getFileById(directory.getParentId());
581 }
582
583 // TODO Enable when "On Device" is recovered ?
584 mAdapter.swapDirectory(directory, storageManager/*, onlyOnDevice*/);
585 if (mFile == null || !mFile.equals(directory)) {
586 mCurrentListView.setSelection(0);
587 }
588 mFile = directory;
589
590 updateLayout();
591
592 }
593 }
594
595 private void updateLayout() {
596 if (!mJustFolders) {
597 int filesCount = 0, foldersCount = 0, imagesCount = 0;
598 int count = mAdapter.getCount();
599 OCFile file;
600 for (int i=0; i < count ; i++) {
601 file = (OCFile) mAdapter.getItem(i);
602 if (file.isFolder()) {
603 foldersCount++;
604 } else {
605 if (!file.isHidden()) {
606 filesCount++;
607
608 if (file.isImage()) {
609 imagesCount++;
610 }
611 }
612 }
613 }
614 // set footer text
615 setFooterText(generateFooterText(filesCount, foldersCount));
616
617 // decide grid vs list view
618 OwnCloudVersion version = com.owncloud.android.authentication.AccountUtils.getServerVersion(
619 ((FileActivity)mContainerActivity).getAccount());
620 if (version != null && version.supportsRemoteThumbnails() &&
621 imagesCount > 0 && imagesCount == filesCount) {
622 switchToGridView();
623 registerLongClickListener();
624 } else {
625 switchToListView();
626 }
627 }
628 }
629
630 private String generateFooterText(int filesCount, int foldersCount) {
631 String output;
632 if (filesCount <= 0) {
633 if (foldersCount <= 0) {
634 output = "";
635
636 } else if (foldersCount == 1) {
637 output = getResources().getString(R.string.file_list__footer__folder);
638
639 } else { // foldersCount > 1
640 output = getResources().getString(R.string.file_list__footer__folders, foldersCount);
641 }
642
643 } else if (filesCount == 1) {
644 if (foldersCount <= 0) {
645 output = getResources().getString(R.string.file_list__footer__file);
646
647 } else if (foldersCount == 1) {
648 output = getResources().getString(R.string.file_list__footer__file_and_folder);
649
650 } else { // foldersCount > 1
651 output = getResources().getString(R.string.file_list__footer__file_and_folders, foldersCount);
652 }
653 } else { // filesCount > 1
654 if (foldersCount <= 0) {
655 output = getResources().getString(R.string.file_list__footer__files, filesCount);
656
657 } else if (foldersCount == 1) {
658 output = getResources().getString(R.string.file_list__footer__files_and_folder, filesCount);
659
660 } else { // foldersCount > 1
661 output = getResources().getString(
662 R.string.file_list__footer__files_and_folders, filesCount, foldersCount
663 );
664
665 }
666 }
667 return output;
668 }
669
670 public void sortByName(boolean descending) {
671 mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
672 }
673
674 public void sortByDate(boolean descending) {
675 mAdapter.setSortOrder(FileStorageUtils.SORT_DATE, descending);
676 }
677
678 public void sortBySize(boolean descending) {
679 mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
680 }
681 }