Merge branch 'material_buttons' of https://github.com/owncloud/android into material_fab
authorAndy Scherzinger <info@andy-scherzinger.de>
Fri, 6 Nov 2015 10:54:28 +0000 (11:54 +0100)
committerAndy Scherzinger <info@andy-scherzinger.de>
Fri, 6 Nov 2015 10:54:28 +0000 (11:54 +0100)
1  2 
build.gradle
res/layout/list_fragment.xml
res/values/colors.xml
res/values/styles.xml
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/FolderPickerActivity.java
src/com/owncloud/android/ui/activity/Uploader.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

diff --combined build.gradle
@@@ -20,11 -20,10 +20,11 @@@ repositories 
  
  dependencies {
      compile name: 'touch-image-view'
-     compile 'com.android.support:support-v4:22.2.1'
      compile project(':owncloud-android-library')
+     compile 'com.android.support:support-v4:22.2.1'
      compile 'com.jakewharton:disklrucache:2.0.2'
      compile 'com.android.support:appcompat-v7:22.2.1'
 +    compile 'com.getbase:floatingactionbutton:1.10.1'
  }
  
  android {
@@@ -59,7 -58,7 +59,7 @@@
              abortOnError false
          }
      }
-     
      productFlavors {
      }
  
@@@ -69,3 -68,7 +69,7 @@@
  }
  
  
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  -->
 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 +    xmlns:fab="http://schemas.android.com/apk/res-auto"
 +    android:layout_width="match_parent"
 +    android:layout_height="match_parent">
 +
  <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
 +    xmlns:fab="http://schemas.android.com/apk/res-auto"
      android:layout_width="match_parent"
 -    android:layout_height="match_parent"
 -    android:layout_weight="1" >
 +    android:layout_height="match_parent">
  
      <android.support.v4.widget.SwipeRefreshLayout
          android:id="@+id/swipe_containing_list"
          android:layout_width="match_parent"
 -        android:layout_height="match_parent" 
 -        android:layout_weight="1"
 +        android:layout_height="match_parent"
          android:footerDividersEnabled="false"
          android:visibility="visible" >
          
@@@ -39,6 -35,8 +39,8 @@@
              android:id="@+id/list_root"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
+             android:divider="@color/list_divider_background"
+             android:dividerHeight="1px"
              android:visibility="visible" />
  
      </android.support.v4.widget.SwipeRefreshLayout>
              </ScrollView>
      </android.support.v4.widget.SwipeRefreshLayout>
  
 -</FrameLayout>
 +</FrameLayout>
 +    <com.getbase.floatingactionbutton.FloatingActionsMenu
 +        android:id="@+id/fab_main"
 +        android:layout_width="wrap_content"
 +        android:layout_height="wrap_content"
 +        android:layout_alignParentBottom="true"
 +        android:layout_alignParentRight="true"
 +        android:layout_alignParentEnd="true"
 +        fab:fab_addButtonColorNormal="@color/owncloud_blue_accent"
 +        fab:fab_addButtonColorPressed="@color/owncloud_blue"
 +        fab:fab_addButtonPlusIconColor="@color/white"
 +        fab:fab_labelStyle="@style/menu_labels_style"
 +        android:layout_marginBottom="@dimen/standard_margin"
 +        android:layout_marginRight="@dimen/standard_margin"
 +        android:layout_marginEnd="@dimen/standard_margin"
 +        android:visibility="gone">
 +
 +        <com.getbase.floatingactionbutton.FloatingActionButton
 +            android:id="@+id/fab_upload"
 +            android:layout_width="wrap_content"
 +            android:layout_height="wrap_content"
 +            fab:fab_size="mini"
 +            fab:fab_icon="@drawable/ic_action_upload"
 +            fab:fab_colorNormal="@color/owncloud_blue_accent"
 +            fab:fab_colorPressed="@color/owncloud_blue"
 +            fab:fab_title=""/>
 +
 +        <com.getbase.floatingactionbutton.FloatingActionButton
 +            android:id="@+id/fab_mkdir"
 +            android:layout_width="wrap_content"
 +            android:layout_height="wrap_content"
 +            fab:fab_size="mini"
 +            fab:fab_icon="@drawable/ic_action_create_dir"
 +            fab:fab_colorNormal="@color/owncloud_blue_accent"
 +            fab:fab_colorPressed="@color/owncloud_blue"
 +            fab:fab_title=""/>
 +
 +        <com.getbase.floatingactionbutton.FloatingActionButton
 +            android:id="@+id/fab_upload_from_app"
 +            android:layout_width="wrap_content"
 +            android:layout_height="wrap_content"
 +            fab:fab_size="mini"
 +            fab:fab_icon="@drawable/ic_import"
 +            fab:fab_colorNormal="@color/owncloud_blue_accent"
 +            fab:fab_colorPressed="@color/owncloud_blue"
 +            fab:fab_title=""/>
 +
 +    </com.getbase.floatingactionbutton.FloatingActionsMenu>
- </RelativeLayout>
++</RelativeLayout>
diff --combined res/values/colors.xml
      <color name="owncloud_blue_accent">#35537A</color>
      <color name="owncloud_blue_bright">#00ddff</color>
  
 -    <color name="list_item_lastmod_and_filesize_text">#989898</color>
 +    <color name="list_item_lastmod_and_filesize_text">@color/secondaryTextColor</color>
      <color name="black">#000000</color>
      <color name="white">#FFFFFF</color>
 -    <color name="textColor">#303030</color>
 +    <color name="fab_white">#fafafa</color>
 +    <color name="white_pressed">#f1f1f1</color>
 +    <color name="half_black">#808080</color>
 +    <color name="black_semi_transparent">#B2000000</color>
 +    <color name="textColor">@color/black</color>
      <color name="drawerMenuTextColor">#000000</color>
-     <color name="list_divider_background">#f8f8f8</color>
+     <color name="list_divider_background">#eee</color>
      <color name="filelist_icon_backgorund">#DDDDDD</color>
      <color name="dark_background_text_color">#EEEEEE</color>
      <color name="login_text_color">#757575</color>
@@@ -40,9 -36,6 +40,9 @@@
      <color name="primary_button_color">@color/owncloud_blue_accent</color>
      <color name="secondary_button_color">#D6D7D7</color>
      <color name="transparent">#00000000</color>
 +    <color name="secondaryTextColor">#a0a0a0</color>
 +    <color name="listItemHighlighted">#f8f8f8</color>
 +    <color name="highlightTextColor">#55739a</color>
  
      <!-- Colors -->
      <color name="color_accent">@color/owncloud_blue_accent</color>
diff --combined res/values/styles.xml
@@@ -51,9 -51,7 +51,9 @@@
                <item name="android:textColorPrimary">@color/primary</item>
        </style>
  
 -      <style name="ownCloud.Dialog" parent="Theme.AppCompat.Light.Dialog" />
 +      <style name="ownCloud.Dialog" parent="Theme.AppCompat.Light.Dialog">
 +              <item name="colorAccent">@color/color_accent</item>
 +      </style>
  
        <style name="ProgressDialogTheme" parent="ownCloud.Dialog">
                <item name="colorAccent">@color/color_accent</item>
  
        <style name="Theme.ownCloud.Fullscreen" parent="style/Theme.AppCompat">
          <item name="android:windowFullscreen">true</item>
 +              <item name="colorAccent">@color/color_accent</item>
      </style>
        
        
                <item name="buttonBarStyle">@style/Theme.ownCloud.Dialog.ButtonBar</item>
        </style>
  
 +      <style name="menu_labels_style">
 +              <item name="android:background">@drawable/fab_label_background</item>
 +              <item name="android:textColor">@color/fab_white</item>
 +      </style>
 +
        <!-- Button Bar hack due to Lollipop bug:
                https://code.google.com/p/android/issues/detail?id=78302
        fix see:
                
        <color name="setup_text_hint">#777777</color>
        <color name="setup_text_typed">#000000</color>
+     <style name="Theme.ownCloud.NoActionBar">
+         <item name="windowActionBar">false</item>
+         <item name="windowNoTitle">true</item>
+     </style>
+     <style name="Theme.ownCloud.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+     <style name="Theme.ownCloud.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
  </resources>
@@@ -79,13 -79,14 +79,14 @@@ import com.owncloud.android.lib.common.
  import com.owncloud.android.lib.common.utils.Log_OC;
  import com.owncloud.android.operations.CopyFileOperation;
  import com.owncloud.android.operations.CreateFolderOperation;
- import com.owncloud.android.operations.CreateShareOperation;
+ import com.owncloud.android.operations.CreateShareViaLinkOperation;
+ import com.owncloud.android.operations.CreateShareWithShareeOperation;
  import com.owncloud.android.operations.MoveFileOperation;
  import com.owncloud.android.operations.RefreshFolderOperation;
  import com.owncloud.android.operations.RemoveFileOperation;
  import com.owncloud.android.operations.RenameFileOperation;
  import com.owncloud.android.operations.SynchronizeFileOperation;
- import com.owncloud.android.operations.UnshareLinkOperation;
+ import com.owncloud.android.operations.UnshareOperation;
  import com.owncloud.android.services.observer.FileObserverService;
  import com.owncloud.android.syncadapter.FileSyncAdapter;
  import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
@@@ -116,8 -117,6 +117,6 @@@ public class FileDisplayActivity extend
          implements FileFragment.ContainerActivity,
          OnSslUntrustedCertListener, OnEnforceableRefreshListener {
  
      private SyncBroadcastReceiver mSyncBroadcastReceiver;
      private UploadFinishReceiver mUploadFinishReceiver;
      private DownloadFinishReceiver mDownloadFinishReceiver;
      private boolean mSyncInProgress = false;
  
      private static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
 -    private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
 +    public static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
      private static String DIALOG_UPLOAD_SOURCE = "DIALOG_UPLOAD_SOURCE";
      private static String DIALOG_CERT_NOT_SAVED = "DIALOG_CERT_NOT_SAVED";
  
      }
  
      @Override
+     protected void onStop() {
+         Log_OC.v(TAG, "onStop() start");
+         super.onStop();
+         Log_OC.v(TAG, "onStop() end");
+     }
+     @Override
      protected void onDestroy() {
          Log_OC.v(TAG, "onDestroy() start");
          super.onDestroy();
      @Override
      public boolean onPrepareOptionsMenu(Menu menu) {
          boolean drawerOpen = mDrawerLayout.isDrawerOpen(GravityCompat.START);
 -        menu.findItem(R.id.action_upload).setVisible(!drawerOpen);
 -        menu.findItem(R.id.action_create_dir).setVisible(!drawerOpen);
          menu.findItem(R.id.action_sort).setVisible(!drawerOpen);
          menu.findItem(R.id.action_sync_account).setVisible(!drawerOpen);
          
      public boolean onCreateOptionsMenu(Menu menu) {
          MenuInflater inflater = getMenuInflater();
          inflater.inflate(R.menu.main_menu, menu);
 +        menu.findItem(R.id.action_create_dir).setVisible(false);
          return true;
      }
      
      public boolean onOptionsItemSelected(MenuItem item) {
          boolean retval = true;
          switch (item.getItemId()) {
 -            case R.id.action_create_dir: {
 -                CreateFolderDialogFragment dialog =
 -                        CreateFolderDialogFragment.newInstance(getCurrentDir());
 -                dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
 -                break;
 -            }
 -
              case R.id.action_sync_account: {
                  startSynchronization();
                  break;
              }
 -            case R.id.action_upload: {
 -                UploadSourceDialogFragment dialog =
 -                        UploadSourceDialogFragment.newInstance(getAccount());
 -                dialog.show(getSupportFragmentManager(), DIALOG_UPLOAD_SOURCE);
 -                break;
 -            }
              case android.R.id.home: {
                  FileFragment second = getSecondFragment();
                  OCFile currentDir = getCurrentDir();
          return retval;
      }
  
 +    public void createFolder() {
 +        CreateFolderDialogFragment dialog =
 +                CreateFolderDialogFragment.newInstance(getCurrentDir());
 +        dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
 +    }
 +
 +    public void uploadLocalFilesSelected() {
 +        Intent action = new Intent(this, UploadFilesActivity.class);
 +        action.putExtra(
 +                UploadFilesActivity.EXTRA_ACCOUNT,
 +                getAccount()
 +        );
 +        startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
 +    }
 +
 +    public void uploadFromOtherAppsSelected() {
 +        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);
 +        }
 +        startActivityForResult(
 +                Intent.createChooser(action, getString(R.string.upload_chooser_title)),
 +                ACTION_SELECT_CONTENT_FROM_APPS
 +        );
 +    }
 +
      private void startSynchronization() {
          Log_OC.d(TAG, "Got to start sync");
          if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
                              requestMoveOperation(fData, fResultCode);
                          }
                      },
-                     DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+                     DELAY_TO_REQUEST_OPERATIONS_LATER
              );
  
          } else if (requestCode == ACTION_COPY_FILES && resultCode == RESULT_OK) {
                              requestCopyOperation(fData, fResultCode);
                          }
                      },
-                     DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+                     DELAY_TO_REQUEST_OPERATIONS_LATER
              );
  
          } else {
  
      @Override
      public void onBackPressed() {
 -        if (!isDrawerOpen()){
 +        boolean isFabOpen = isFabOpen();
 +        boolean isDrawerOpen = isDrawerOpen();
 +
 +        /*
 +         * BackPressed priority/hierarchy:
 +         *    1. close drawer if opened
 +         *    2. close FAB if open (only if drawer isn't open)
 +         *    3. navigate up (only if drawer and FAB aren't open)
 +         */
 +        if(isDrawerOpen && isFabOpen) {
 +            // close drawer first
 +            super.onBackPressed();
 +        } else if(isDrawerOpen && !isFabOpen) {
 +            // close drawer
 +            super.onBackPressed();
 +        } else if (!isDrawerOpen && isFabOpen) {
 +            // close fab
 +            getListOfFilesFragment().getFabMain().collapse();
 +        } else {
 +            // all closed
              OCFileListFragment listOfFiles = getListOfFilesFragment();
              if (mDualPane || getSecondFragment() == null) {
                  OCFile currentDir = getCurrentDir();
                  setFile(listOfFiles.getCurrentFile());
              }
              cleanSecondFragment();
 -        } else {
 -            super.onBackPressed();
          }
      }
  
          Log_OC.v(TAG, "onPause() end");
      }
  
 +    public boolean isFabOpen() {
 +        if(getListOfFilesFragment() != null && getListOfFilesFragment().getFabMain() != null && getListOfFilesFragment().getFabMain().isExpanded()) {
 +            return true;
 +        } else {
 +            return false;
 +        }
 +    }
 +
  
      private class SyncBroadcastReceiver extends BroadcastReceiver {
  
                              }
  
                          }
                      }
                      removeStickyBroadcast(intent);
                      Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
          } else if (operation instanceof CreateFolderOperation) {
              onCreateFolderOperationFinish((CreateFolderOperation) operation, result);
  
-         } else if (operation instanceof CreateShareOperation) {
-             onCreateShareOperationFinish((CreateShareOperation) operation, result);
+         } else if (operation instanceof CreateShareViaLinkOperation ||
+                     operation instanceof CreateShareWithShareeOperation ) {
  
-         } else if (operation instanceof UnshareLinkOperation) {
-             onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
+             refreshShowDetails();
+             refreshListOfFilesFragment();
+         } else if (operation instanceof UnshareOperation) {
+             onUnshareLinkOperationFinish((UnshareOperation) operation, result);
  
          } else if (operation instanceof MoveFileOperation) {
              onMoveFileOperationFinish((MoveFileOperation) operation, result);
          }
  
      }
-     private void onCreateShareOperationFinish(CreateShareOperation operation,
-                                               RemoteOperationResult result) {
-         if (result.isSuccess()) {
-             refreshShowDetails();
-             refreshListOfFilesFragment();
-         }
-     }
  
-     private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+     private void onUnshareLinkOperationFinish(UnshareOperation operation,
                                                RemoteOperationResult result) {
          if (result.isSuccess()) {
              refreshShowDetails();
       */
      private void onRemoveFileOperationFinish(RemoveFileOperation operation,
                                               RemoteOperationResult result) {
-         dismissLoadingDialog();
          Toast msg = Toast.makeText(this,
                  ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
                  Toast.LENGTH_LONG);
      private void onMoveFileOperationFinish(MoveFileOperation operation,
                                             RemoteOperationResult result) {
          if (result.isSuccess()) {
-             dismissLoadingDialog();
              refreshListOfFilesFragment();
          } else {
-             dismissLoadingDialog();
              try {
                  Toast msg = Toast.makeText(FileDisplayActivity.this,
                          ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
       */
      private void onCopyFileOperationFinish(CopyFileOperation operation, RemoteOperationResult result) {
          if (result.isSuccess()) {
-             dismissLoadingDialog();
              refreshListOfFilesFragment();
          } else {
-             dismissLoadingDialog();
              try {
                  Toast msg = Toast.makeText(FileDisplayActivity.this,
                          ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
       */
      private void onRenameFileOperationFinish(RenameFileOperation operation,
                                               RemoteOperationResult result) {
-         dismissLoadingDialog();
          OCFile renamedFile = operation.getFile();
          if (result.isSuccess()) {
              FileFragment details = getSecondFragment();
      private void onCreateFolderOperationFinish(CreateFolderOperation operation,
                                                 RemoteOperationResult result) {
          if (result.isSuccess()) {
-             dismissLoadingDialog();
              refreshListOfFilesFragment();
          } else {
-             dismissLoadingDialog();
              try {
                  Toast msg = Toast.makeText(FileDisplayActivity.this,
                          ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
          return null;
      }
  
-     public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) {
-         long currentSyncTime = System.currentTimeMillis();
-         mSyncInProgress = true;
-         // perform folder synchronization
-         RemoteOperation synchFolderOp = new RefreshFolderOperation( folder,
-                 currentSyncTime,
-                 false,
-                 getFileOperationsHelper().isSharedSupported(),
-                 ignoreETag,
-                 getStorageManager(),
-                 getAccount(),
-                 getApplicationContext()
+     /**
+      * Starts an operation to refresh the requested folder.
+      *
+      * The operation is run in a new background thread created on the fly.
+      *
+      * The refresh updates is a "light sync": properties of regular files in folder are updated (including
+      * associated shares), but not their contents. Only the contents of files marked to be kept-in-sync are
+      * synchronized too.
+      *
+      * @param folder        Folder to refresh.
+      * @param ignoreETag    If 'true', the data from the server will be fetched and sync'ed even if the eTag
+      *                      didn't change.
+      */
+     public void startSyncFolderOperation(final OCFile folder, final boolean ignoreETag) {
+         // the execution is slightly delayed to allow the activity get the window focus if it's being started
+         // or if the method is called from a dialog that is being dismissed
+         getHandler().postDelayed(
+                 new Runnable() {
+                     @Override
+                     public void run() {
+                         if (hasWindowFocus()) {
+                             long currentSyncTime = System.currentTimeMillis();
+                             mSyncInProgress = true;
+                             // perform folder synchronization
+                             RemoteOperation synchFolderOp = new RefreshFolderOperation(folder,
+                                     currentSyncTime,
+                                     false,
+                                     getFileOperationsHelper().isSharedSupported(),
+                                     ignoreETag,
+                                     getStorageManager(),
+                                     getAccount(),
+                                     getApplicationContext()
+                             );
+                             synchFolderOp.execute(
+                                     getAccount(),
+                                     MainApp.getAppContext(),
+                                     FileDisplayActivity.this,
+                                     null,
+                                     null
+                             );
+                             mProgressBar.setIndeterminate(true);
+                             setBackgroundText();
+                         }   // else: NOTHING ; lets' not refresh when the user rotates the device but there is
+                         // another window floating over
+                     }
+                 },
+                 DELAY_TO_REQUEST_OPERATIONS_LATER
          );
-         synchFolderOp.execute(getAccount(), MainApp.getAppContext(), this, null, null);
-         mProgressBar.setIndeterminate(true);
  
-         setBackgroundText();
      }
  
      /**
@@@ -38,7 -38,6 +38,6 @@@ import android.view.MenuInflater
  import android.view.MenuItem;
  import android.view.View;
  import android.view.View.OnClickListener;
- import android.view.Window;
  import android.widget.Button;
  import android.widget.ProgressBar;
  import android.widget.Toast;
@@@ -155,7 -154,6 +154,7 @@@ public class FolderPickerActivity exten
          Bundle args = new Bundle();
          args.putBoolean(OCFileListFragment.ARG_JUST_FOLDERS, true);
          args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
 +        args.putBoolean(OCFileListFragment.ARG_HIDE_FAB, true);
          listOfFiles.setArguments(args);
          FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
          transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
      public boolean onCreateOptionsMenu(Menu menu) {
          MenuInflater inflater = getMenuInflater();
          inflater.inflate(R.menu.main_menu, menu);
 -        menu.findItem(R.id.action_upload).setVisible(false);
          menu.findItem(R.id.action_sort).setVisible(false);
          return true;
      }
          actionBar.setDisplayHomeAsUpEnabled(!atRoot);
          actionBar.setHomeButtonEnabled(!atRoot);
          actionBar.setTitle(
-             atRoot 
-                 ? getString(R.string.default_display_name_for_root_folder) 
-                 : currentDir.getFileName()
+                 atRoot
+                         ? getString(R.string.default_display_name_for_root_folder)
+                         : currentDir.getFileName()
          );
      }
  
          super.onRemoteOperationFinish(operation, result);
          
          if (operation instanceof CreateFolderOperation) {
-             onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+             onCreateFolderOperationFinish((CreateFolderOperation) operation, result);
              
          }
      }
              ) {
          
          if (result.isSuccess()) {
-             dismissLoadingDialog();
              refreshListOfFilesFragment();
          } else {
-             dismissLoadingDialog();
              try {
                  Toast msg = Toast.makeText(FolderPickerActivity.this, 
                          ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
      
  
      /**
-      * Shows the information of the {@link OCFile} received as a 
+      * Shows the information of the {@link OCFile} received as a
       * parameter in the second fragment.
-      * 
+      *
       * @param file          {@link OCFile} whose details will be shown
       */
      @Override
@@@ -607,10 -607,8 +607,8 @@@ public class Uploader extends FileActiv
      private void onCreateFolderOperationFinish(CreateFolderOperation operation,
                                                 RemoteOperationResult result) {
          if (result.isSuccess()) {
-             dismissLoadingDialog();
              populateDirectoryList();
          } else {
-             dismissLoadingDialog();
              try {
                  Toast msg = Toast.makeText(this, 
                          ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
      public boolean onCreateOptionsMenu(Menu menu) {
          MenuInflater inflater = getMenuInflater();
          inflater.inflate(R.menu.main_menu, menu);
 -        menu.findItem(R.id.action_upload).setVisible(false);
          menu.findItem(R.id.action_sort).setVisible(false);
          menu.findItem(R.id.action_sync_account).setVisible(false);
          return true;
@@@ -24,10 -24,7 +24,10 @@@ 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.Menu;
@@@ -37,8 -34,6 +37,8 @@@ import android.view.View
  import android.widget.AdapterView;
  import android.widget.AdapterView.AdapterContextMenuInfo;
  import android.widget.PopupMenu;
 +import android.widget.TextView;
 +import android.widget.Toast;
  
  import com.owncloud.android.R;
  import com.owncloud.android.authentication.AccountUtils;
@@@ -51,18 -46,15 +51,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.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.FileStorageUtils;
  import com.owncloud.android.ui.preview.PreviewTextFragment;
+ import com.owncloud.android.utils.FileStorageUtils;
  
  import java.io.File;
  
@@@ -71,7 -63,8 +71,8 @@@
   *
   * TODO refactor to get rid of direct dependency on FileDisplayActivity
   */
- public class OCFileListFragment extends ExtendedListFragment implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
+ public class OCFileListFragment extends ExtendedListFragment
+         implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
      
      private static final String TAG = OCFileListFragment.class.getSimpleName();
  
  
      public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
      public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
 +    public final static String ARG_HIDE_FAB = MY_PACKAGE + ".HIDE_FAB";
  
      private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
 +    private static final String KEY_FAB_EVER_CLICKED = "FAB_EVER_CLICKED";
 +
 +    private static String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER";
  
      private FileFragment.ContainerActivity mContainerActivity;
  
@@@ -94,8 -83,8 +95,8 @@@
      private boolean mJustFolders;
      
      private OCFile mTargetFile;
 -    
 -   
 +
 +    private boolean miniFabClicked = false;
      
      /**
       * {@inheritDoc}
          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,
          });
      }
  
 -
      private void showFileAction(int fileIndex) {
          Bundle args = getArguments();
          PopupMenu pm = new PopupMenu(getActivity(),null);
                  }
              }
  
-             FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu, fileIndex, targetFile.getFileName());
+             FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu,
+                     fileIndex, targetFile.getFileName());
              dialog.setTargetFragment(this, 0);
              dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
          }
  
      /**
       * Call this, when the user presses the up button.
 -     *
 -     * Tries to move up the current folder one level. If the parent folder was removed from the
 -     * database, it continues browsing up until finding an existing folders.
 -     * <p/>
 -     * return       Count of folder levels browsed up.
 +     * <p>
 +     *     Tries to move up the current folder one level. If the parent folder was removed from the
 +     *     database, it continues browsing up until finding an existing folders.
 +     * </p>
 +     * @return Count of folder levels browsed up.
       */
      public int onBrowseUp() {
          OCFile parentDir = null;
                  mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
                  return true;
              }
+             case R.id.action_share_with_users: {
+                 mContainerActivity.getFileOperationsHelper().showShareFile(mTargetFile);
+                 return true;
+             }
              case R.id.action_open_file_with: {
                  mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
                  return true;
      @Override
      public boolean onContextItemSelected (MenuItem item) {
          AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-         boolean matched = onFileActionChosen(item.getItemId(), ((AdapterContextMenuInfo) item.getMenuInfo()).position);
+         boolean matched = onFileActionChosen(item.getItemId(),
+                 ((AdapterContextMenuInfo) item.getMenuInfo()).position);
          if(!matched) {
              return super.onContextItemSelected(item);
          } else {