Merge remote-tracking branch 'remotes/upstream/multiSelect' into beta
authortobiasKaminsky <tobias@kaminsky.me>
Thu, 29 Oct 2015 17:53:05 +0000 (18:53 +0100)
committertobiasKaminsky <tobias@kaminsky.me>
Thu, 29 Oct 2015 17:53:05 +0000 (18:53 +0100)
33 files changed:
1  2 
res/values-cs-rCZ/strings.xml
res/values-de/strings.xml
res/values-el/strings.xml
res/values-eo/strings.xml
res/values-es/strings.xml
res/values-fi-rFI/strings.xml
res/values-fr/strings.xml
res/values-hu-rHU/strings.xml
res/values-id/strings.xml
res/values-it/strings.xml
res/values-ko/strings.xml
res/values-lt-rLT/strings.xml
res/values-nb-rNO/strings.xml
res/values-nl/strings.xml
res/values-oc/strings.xml
res/values-pt-rBR/strings.xml
res/values-ru/strings.xml
res/values-sr/strings.xml
res/values-th-rTH/strings.xml
res/values-tr/strings.xml
res/values-uk/strings.xml
res/values-zh-rCN/strings.xml
res/values/setup.xml
res/values/strings.xml
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/FileOperationsHelper.java
src/com/owncloud/android/ui/activity/FileActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/FolderPickerActivity.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
src/com/owncloud/android/ui/fragment/ExtendedListFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -201,10 -200,10 +201,10 @@@ Ci-dessous la liste des fichiers locaux
    <string name="auth_can_not_auth_against_server">Impossible de s\'authentifier sur ce serveur</string>
    <string name="auth_account_does_not_exist">Le compte n\'existe pas encore sur ce périphérique</string>
    <string name="favorite">Ajouter aux favoris</string>
 -  <string name="unfavorite">Supprimer des favoris</string>
 +  <string name="unfavorite">Retirer des favoris</string>
    <string name="common_rename">Renommer</string>
    <string name="common_remove">Supprimer</string>
-   <string name="confirmation_remove_alert">Voulez-vous vraiment supprimer %1$s ?</string>
+   <string name="confirmation_remove_file_alert">Voulez-vous vraiment supprimer %1$s ?</string>
    <string name="confirmation_remove_folder_alert">Voulez-vous vraiment supprimer %1$s et son contenu ?</string>
    <string name="confirmation_remove_local">Local seulement</string>
    <string name="confirmation_remove_folder_local">Local seulement</string>
Simple merge
Simple merge
Simple merge
Simple merge
    <string name="auth_connecting_auth_server">Jungiamasi prie autentikacijos serverio...</string>
    <string name="auth_unsupported_auth_method">Serveris nepalaiko šio autentikacijos metodo</string>
    <string name="auth_unsupported_multiaccount">%1$s nepalaiko kelių paskyrų iš karto</string>
 +  <string name="auth_fail_get_user_name">Serveris negražina tinkamo vartotojo ID, susisiekite su administratoriumi</string>
    <string name="auth_can_not_auth_against_server">Jungiamasi prie autentikacijos serverio...</string>
 +  <string name="auth_account_does_not_exist">Paskyra neegzistuoja įrenginyje</string>
    <string name="favorite">Mėgiamas</string>
 +  <string name="unfavorite">Nebemėgti</string>
    <string name="common_rename">Pervadinti</string>
    <string name="common_remove">Pašalinti</string>
-   <string name="confirmation_remove_alert">Ar tikrai norite pašalinti %1$s?</string>
+   <string name="confirmation_remove_file_alert">Ar tikrai norite pašalinti %1$s?</string>
    <string name="confirmation_remove_folder_alert">Ar tikrai norite pašalinti %1$s ir ten esantį turinį?</string>
    <string name="confirmation_remove_local">Tik vietiniai</string>
    <string name="confirmation_remove_folder_local">Tik vietiniai</string>
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
    <string name="auth_can_not_auth_against_server">Аутентифікація на цьому сервері неможлива</string>
    <string name="auth_account_does_not_exist">Користвача в пристрої не існуе</string>
    <string name="favorite">Улюблений</string>
 +  <string name="unfavorite">Прибрати з вибраного</string>
    <string name="common_rename">Перейменувати</string>
    <string name="common_remove">Видалити</string>
-   <string name="confirmation_remove_alert">Ви дійсно бажаєте видалити %1$s?</string>
+   <string name="confirmation_remove_file_alert">Ви дійсно бажаєте видалити %1$s?</string>
    <string name="confirmation_remove_folder_alert">Ви дійсно бажаєте видалити %1$s та весь вміст?</string>
    <string name="confirmation_remove_local">Лише локально</string>
    <string name="confirmation_remove_folder_local">Лише локально</string>
Simple merge
Simple merge
      <string name="file_list__footer__files">%1$d files</string>
      <string name="file_list__footer__files_and_folder">%1$d files, 1 folder</string>
      <string name="file_list__footer__files_and_folders">%1$d files, %2$d folders</string>
 +    <string name="action_switch_grid_view">Switch to grid view</string>
 +    <string name="action_switch_list_view">Switch to list view</string>
 +    <string name="common_category">Common</string>
 +    <string name="pref_cache_size">Cache size</string>
 +    <string name="prefs_instant_behaviour_dialogTitle">Upload file to server and ...</string>
 +    <string name="prefs_instant_behaviour_title">Behaviour</string>
 +    <string name="upload_copy_files">Copy file</string>
 +    <string name="upload_move_files">Move file</string>
 +
 +    <string name="pref_behaviour_entries_do_nothing">do nothing</string>
 +    <string name="pref_behaviour_entries_copy">copy file to OC folder</string>
 +    <string name="pref_behaviour_entries_move">move file to OC folder</string>
 +    <string name="pref_behaviour_entries_delete">delete origin file</string>
+     <string name="confirmation_remove_files_alert">Do you really want to remove selected items?</string>
+     <string name="confirmation_remove_folders_alert">Do you really want to remove a folder and its content?</string>
+     <string name="confirmation_remove_files">selected items</string>
  
  </resources>
@@@ -27,7 -27,7 +27,6 @@@ import android.webkit.MimeTypeMap
  import com.owncloud.android.lib.common.utils.Log_OC;
  
  import java.io.File;
- import java.util.Enumeration;
 -import java.io.Serializable;
  
  import third_parties.daveKoeller.AlphanumComparator;
  public class OCFile implements Parcelable, Comparable<OCFile> {
@@@ -51,14 -43,8 +51,16 @@@ import com.owncloud.android.ui.dialog.S
  
  import org.apache.http.protocol.HTTP;
  
 +import java.util.List;
 +
 +import java.io.ByteArrayOutputStream;
 +import java.io.File;
 +import java.io.FileNotFoundException;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +
+ import java.util.ArrayList;
  /**
   *
   */
@@@ -246,28 -207,14 +248,32 @@@ public class FileOperationsHelper 
          }
      }
  
 +    public void sendCachedImage(OCFile file) {
 +        if (file != null) {
 +            Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
 +            // set MimeType
 +            sendIntent.setType(file.getMimetype());
 +//            sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + "/#" + file.getRemoteId() + "#" + file.getFileName()));
 +            sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + file.getRemotePath()));
 +            sendIntent.putExtra(Intent.ACTION_SEND, true);      // Send Action
 +
 +            // Show dialog, without the own app
 +            String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
 +            DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
 +            chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
 +        } else {
 +            Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
 +        }
 +    }
 +
+     public void syncFiles(ArrayList<OCFile> files) {
+         for (OCFile file: files) {
+             syncFile(file);
+         }
+     }
  
      public void syncFile(OCFile file) {
-         if (!file.isFolder()){
+         if (!file.isFolder()) {
              Intent intent = new Intent(mFileActivity, OperationsService.class);
              intent.setAction(OperationsService.ACTION_SYNC_FILE);
              intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
@@@ -194,16 -200,14 +200,15 @@@ public class FileListListAdapter extend
              switch (viewType){\r
                  case LIST_ITEM:\r
                      TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);\r
 +                    TextView fileSizeSeparatorV = (TextView) view.findViewById(R.id.file_separator);\r
                      TextView lastModV = (TextView) view.findViewById(R.id.last_mod);\r
-                     ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);\r
\r
  \r
                      lastModV.setVisibility(View.VISIBLE);\r
                      lastModV.setText(showRelativeTimestamp(file));\r
  \r
-                     checkBoxV.setVisibility(View.GONE);\r
  \r
 -\r
 +                    fileSizeSeparatorV.setVisibility(View.VISIBLE);\r
                      fileSizeV.setVisibility(View.VISIBLE);\r
                      fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
  \r
          mGridMode = gridMode;\r
      }\r
  \r
 +    public boolean isGridMode() {\r
 +        return mGridMode;\r
 +    }\r
++\r
+     public void setNewSelection(int position, boolean checked) {\r
+         mSelection.put(position, checked);\r
+         notifyDataSetChanged();\r
+     }\r
\r
+     public void removeSelection(int position) {\r
+         mSelection.remove(position);\r
+         notifyDataSetChanged();\r
+     }\r
\r
+     public void removeSelection(){\r
+          mSelection.clear();\r
+         notifyDataSetChanged();\r
+     }\r
\r
+     public ArrayList<Integer> getCheckedItemPositions() {\r
+         ArrayList<Integer> ids = new ArrayList<Integer>();\r
\r
+         for (Map.Entry<Integer, Boolean> entry : mSelection.entrySet()){\r
+             if (entry.getValue()){\r
+                 ids.add(entry.getKey());\r
+             }\r
+         }\r
+         return ids;\r
+     }\r
\r
+     public ArrayList<OCFile> getCheckedItems() {\r
+         ArrayList<OCFile> files = new ArrayList<OCFile>();\r
\r
+         for (Map.Entry<Integer, Boolean> entry : mSelection.entrySet()){\r
+             if (entry.getValue()){\r
+                 files.add((OCFile) getItem(entry.getKey()));\r
+             }\r
+         }\r
+         return files;\r
+     }\r
  }\r
@@@ -24,12 -24,9 +24,12 @@@ package com.owncloud.android.ui.fragmen
  
  import android.app.Activity;
  import android.content.Intent;
 +import android.content.SharedPreferences;
 +import android.os.Build;
  import android.os.Bundle;
 +import android.preference.PreferenceManager;
  import android.support.v4.widget.SwipeRefreshLayout;
- import android.view.ContextMenu;
+ import android.view.ActionMode;
  import android.view.Menu;
  import android.view.MenuInflater;
  import android.view.MenuItem;
@@@ -52,17 -47,14 +53,18 @@@ import com.owncloud.android.ui.activity
  import com.owncloud.android.ui.activity.FileDisplayActivity;
  import com.owncloud.android.ui.activity.FolderPickerActivity;
  import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
 +import com.owncloud.android.ui.activity.UploadFilesActivity;
  import com.owncloud.android.ui.adapter.FileListListAdapter;
  import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 +import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
  import com.owncloud.android.ui.dialog.FileActionsDialogFragment;
  import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+ import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
  import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 +import com.owncloud.android.ui.dialog.UploadSourceDialogFragment;
  import com.owncloud.android.ui.preview.PreviewImageFragment;
  import com.owncloud.android.ui.preview.PreviewMediaFragment;
 +import com.owncloud.android.utils.DisplayUtils;
  import com.owncloud.android.utils.FileStorageUtils;
  import com.owncloud.android.ui.preview.PreviewTextFragment;
  
@@@ -158,174 -143,59 +161,215 @@@ public class OCFileListFragment extend
          setListAdapter(mAdapter);
  
          registerLongClickListener();
 +
 +        boolean hideFab = (args != null) && args.getBoolean(ARG_HIDE_FAB, false);
 +        if (hideFab) {
 +            setFabEnabled(false);
 +        } else {
 +            setFabEnabled(true);
 +            registerFabListeners();
 +
 +            // detect if a mini FAB has ever been clicked
 +            final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
 +            if(prefs.getLong(KEY_FAB_EVER_CLICKED, 0) > 0) {
 +                miniFabClicked = true;
 +            }
 +
 +            // add labels to the min FABs when none of them has ever been clicked on
 +            if(!miniFabClicked) {
 +                setFabLabels();
 +            } else {
 +                removeFabLabels();
 +            }
 +        }
    }
  
 +    /**
 +     * adds labels to all mini FABs.
 +     */
 +    private void setFabLabels() {
 +        getFabUpload().setTitle(getResources().getString(R.string.actionbar_upload));
 +        getFabMkdir().setTitle(getResources().getString(R.string.actionbar_mkdir));
 +        getFabUploadFromApp().setTitle(getResources().getString(R.string.actionbar_upload_from_apps));
 +    }
 +
 +    /**
 +     * registers all listeners on all mini FABs.
 +     */
 +    private void registerFabListeners() {
 +        registerFabUploadListeners();
 +        registerFabMkDirListeners();
 +        registerFabUploadFromAppListeners();
 +    }
 +
 +    /**
 +     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
 +     * on the Upload mini FAB for the linked action and {@link Toast} showing the underlying action.
 +     */
 +    private void registerFabUploadListeners() {
 +        getFabUpload().setOnClickListener(new View.OnClickListener() {
 +            @Override
 +            public void onClick(View v) {
 +                Intent action = new Intent(getActivity(), UploadFilesActivity.class);
 +                action.putExtra(
 +                        UploadFilesActivity.EXTRA_ACCOUNT,
 +                        ((FileActivity) getActivity()).getAccount()
 +                );
 +                getActivity().startActivityForResult(action, UploadSourceDialogFragment.ACTION_SELECT_MULTIPLE_FILES);
 +                getFabMain().collapse();
 +                recordMiniFabClick();
 +            }
 +        });
 +
 +        getFabUpload().setOnLongClickListener(new View.OnLongClickListener() {
 +            @Override
 +            public boolean onLongClick(View v) {
 +                Toast.makeText(getActivity(), R.string.actionbar_upload, Toast.LENGTH_SHORT).show();
 +                return true;
 +            }
 +        });
 +    }
 +
 +    /**
 +     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
 +     * on the 'Create Dir' mini FAB for the linked action and {@link Toast} showing the underlying action.
 +     */
 +    private void registerFabMkDirListeners() {
 +        getFabMkdir().setOnClickListener(new View.OnClickListener() {
 +            @Override
 +            public void onClick(View v) {
 +                CreateFolderDialogFragment dialog =
 +                        CreateFolderDialogFragment.newInstance(mFile);
 +                dialog.show(getActivity().getSupportFragmentManager(), FileDisplayActivity.DIALOG_CREATE_FOLDER);
 +                getFabMain().collapse();
 +                recordMiniFabClick();
 +            }
 +        });
 +
 +        getFabMkdir().setOnLongClickListener(new View.OnLongClickListener() {
 +            @Override
 +            public boolean onLongClick(View v) {
 +                Toast.makeText(getActivity(), R.string.actionbar_mkdir, Toast.LENGTH_SHORT).show();
 +                return true;
 +            }
 +        });
 +    }
 +
 +    /**
 +     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
 +     * on the Upload from App mini FAB for the linked action and {@link Toast} showing the underlying action.
 +     */
 +    private void registerFabUploadFromAppListeners() {
 +        getFabUploadFromApp().setOnClickListener(new View.OnClickListener() {
 +            @Override
 +            public void onClick(View v) {
 +                Intent action = new Intent(Intent.ACTION_GET_CONTENT);
 +                action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
 +
 +                //Intent.EXTRA_ALLOW_MULTIPLE is only supported on api level 18+, Jelly Bean
 +                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
 +                    action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 +                }
 +
 +                getActivity().startActivityForResult(
 +                        Intent.createChooser(action, getString(R.string.upload_chooser_title)),
 +                        UploadSourceDialogFragment.ACTION_SELECT_CONTENT_FROM_APPS
 +                );
 +                getFabMain().collapse();
 +                recordMiniFabClick();
 +            }
 +        });
 +
 +        getFabUploadFromApp().setOnLongClickListener(new View.OnLongClickListener() {
 +            @Override
 +            public boolean onLongClick(View v) {
 +                Toast.makeText(getActivity(),
 +                        R.string.actionbar_upload_from_apps,
 +                        Toast.LENGTH_SHORT).show();
 +                return true;
 +            }
 +        });
 +    }
 +
 +    /**
 +     * records a click on a mini FAB and thus:
 +     * <ol>
 +     *     <li>persists the click fact</li>
 +     *     <li>removes the mini FAB labels</li>
 +     * </ol>
 +     */
 +    private void recordMiniFabClick() {
 +        // only record if it hasn't been done already at some other time
 +        if(!miniFabClicked) {
 +            final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
 +            sp.edit().putLong(KEY_FAB_EVER_CLICKED, 1).commit();
 +            miniFabClicked = true;
 +        }
 +    }
 +
 +    /**
 +     * removes the labels on all known min FABs.
 +     */
 +    private void removeFabLabels() {
 +        getFabUpload().setTitle(null);
 +        getFabMkdir().setTitle(null);
 +        getFabUploadFromApp().setTitle(null);
 +        ((TextView) getFabUpload().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
 +        ((TextView) getFabMkdir().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
 +        ((TextView) getFabUploadFromApp().getTag(com.getbase.floatingactionbutton.R.id.fab_label)).setVisibility(View.GONE);
 +    }
 +
      private void registerLongClickListener() {
-         getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
-             public boolean onItemLongClick(AdapterView<?> arg0, View v,
-                                            int index, long arg3) {
-                 showFileAction(index);
+         getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
+             private Menu menu;
+             @Override
+             public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+                 final int checkedCount = getListView().getCheckedItemCount();
+                 // TODO Tobi extract to values
+                 mode.setTitle(checkedCount + " selected");
+                 if (checked) {
+                     mAdapter.setNewSelection(position, checked);
+                 } else {
+                     mAdapter.removeSelection(position);
+                 }
+                 // TODO maybe change: only recreate menu if count changes
+                 menu.clear();
+                 if (checkedCount == 1) {
+                     createContextMenu(menu);
+                 } else {
+                     // download, move, copy, delete
+                     getActivity().getMenuInflater().inflate(R.menu.multiple_file_actions_menu, menu);
+                 }
+             }
+             @Override
+             public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+                 this.menu = menu;
                  return true;
              }
+             @Override
+             public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+                 return false;
+             }
+             @Override
+             public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+                 return onFileActionChosen(item.getItemId());
+             }
+             @Override
+             public void onDestroyActionMode(ActionMode mode) {
+                 mAdapter.removeSelection();
+             }
          });
      }
  
 -    // TODO Tobi needed?
++
      private void showFileAction(int fileIndex) {
          Bundle args = getArguments();
          PopupMenu pm = new PopupMenu(getActivity(),null);