소스 검색

Merge pull request #2432 from nextcloud/BottomSheet

Better understandable FAB actions via bottom sheet implementation
Andy Scherzinger 7 년 전
부모
커밋
84b80bebff

+ 0 - 2
build.gradle

@@ -121,7 +121,6 @@ android {
         }
     }
 
-
     // adapt structure from Eclipse to Gradle/Android Studio expectations;
     // see http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Configuring-the-Structure
 
@@ -205,7 +204,6 @@ dependencies {
     implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
     implementation "com.android.support:cardview-v7:${supportLibraryVersion}"
     implementation "com.android.support:exifinterface:${supportLibraryVersion}"
-    implementation 'com.github.tobiasKaminsky:android-floating-action-button:1.10.2'
     implementation 'com.github.albfernandez:juniversalchardet:v2.0.0'
     implementation 'com.google.code.findbugs:annotations:2.0.1'
     implementation 'commons-io:commons-io:2.5'

+ 1 - 1
scripts/lint/lint-results.txt

@@ -1,2 +1,2 @@
 DO NOT TOUCH; GENERATED BY DRONE
-      <span class="mdl-layout-title">Lint Report: 129 warnings</span>
+      <span class="mdl-layout-title">Lint Report: 127 warnings</span>

+ 0 - 9
src/main/java/com/owncloud/android/db/PreferenceManager.java

@@ -62,7 +62,6 @@ public abstract class PreferenceManager {
     private static final String PREF__AUTO_UPLOAD_INIT = "autoUploadInit";
     private static final String PREF__FOLDER_SORT_ORDER = "folder_sort_order";
     private static final String PREF__FOLDER_LAYOUT = "folder_layout";
-    private static final String KEY_FAB_EVER_CLICKED = "FAB_EVER_CLICKED";
 
     public static void setKeysReInit(Context context) {
         saveBooleanPreference(context, PREF__KEYS_REINIT, true);
@@ -117,14 +116,6 @@ public abstract class PreferenceManager {
         return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("show_hidden_files_pref", false);
     }
 
-    public static long getFABClicked(Context context) {
-        return getDefaultSharedPreferences(context).getLong(KEY_FAB_EVER_CLICKED, 0);
-    }
-
-    public static void setFABClicked(Context context) {
-        getDefaultSharedPreferences(context).edit().putLong(KEY_FAB_EVER_CLICKED, 1).apply();
-    }
-
     /**
      * Gets the selected file extension position the user selected to do the last upload of a url file shared from other
      * app.

+ 1 - 14
src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -1010,7 +1010,6 @@ public class FileDisplayActivity extends HookActivity
 
     @Override
     public void onBackPressed() {
-        boolean isFabOpen = isFabOpen();
         boolean isDrawerOpen = isDrawerOpen();
         boolean isSearchOpen = isSearchOpen();
 
@@ -1026,15 +1025,9 @@ public class FileDisplayActivity extends HookActivity
             searchView.setQuery("", true);
             searchView.onActionViewCollapsed();
             setDrawerIndicatorEnabled(isDrawerIndicatorAvailable());
-        } else if (isDrawerOpen && isFabOpen) {
+        } else if (isDrawerOpen) {
             // 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
 
@@ -1155,12 +1148,6 @@ public class FileDisplayActivity extends HookActivity
         Log_OC.v(TAG, "onPause() end");
     }
 
-    public boolean isFabOpen() {
-        return (getListOfFilesFragment() != null
-                && getListOfFilesFragment().getFabMain() != null
-                && getListOfFilesFragment().getFabMain().isExpanded());
-    }
-
     @Override
     public void onSortingOrderChosen(FileSortOrder selection) {
         getListOfFilesFragment().sortFiles(selection);

+ 4 - 43
src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java

@@ -31,6 +31,7 @@ import android.os.Looper;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.StringRes;
 import android.support.design.widget.BottomNavigationView;
+import android.support.design.widget.FloatingActionButton;
 import android.support.v4.app.Fragment;
 import android.support.v4.view.MenuItemCompat;
 import android.support.v4.widget.SwipeRefreshLayout;
@@ -58,9 +59,6 @@ import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
-import com.getbase.floatingactionbutton.AddFloatingActionButton;
-import com.getbase.floatingactionbutton.FloatingActionButton;
-import com.getbase.floatingactionbutton.FloatingActionsMenu;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
@@ -109,10 +107,7 @@ public class ExtendedListFragment extends Fragment
     protected ImageView mEmptyListIcon;
     protected ProgressBar mEmptyListProgress;
 
-    private FloatingActionsMenu mFabMain;
-    private FloatingActionButton mFabUpload;
-    private FloatingActionButton mFabMkdir;
-    private FloatingActionButton mFabUploadFromApp;
+    private FloatingActionButton mFabMain;
 
     // Save the state of the scroll in browsing
     private ArrayList<Integer> mIndexes;
@@ -156,19 +151,7 @@ public class ExtendedListFragment extends Fragment
         return mRecyclerView;
     }
 
-    public FloatingActionButton getFabUpload() {
-        return mFabUpload;
-    }
-
-    public FloatingActionButton getFabUploadFromApp() {
-        return mFabUploadFromApp;
-    }
-
-    public FloatingActionButton getFabMkdir() {
-        return mFabMkdir;
-    }
-
-    public FloatingActionsMenu getFabMain() {
+    public FloatingActionButton getFabMain() {
         return mFabMain;
     }
 
@@ -215,9 +198,6 @@ public class ExtendedListFragment extends Fragment
         searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
             @Override
             public void onFocusChange(View v, final boolean hasFocus) {
-                if (hasFocus) {
-                    mFabMain.collapse();
-                }
 
                 handler.postDelayed(new Runnable() {
                     @Override
@@ -390,11 +370,7 @@ public class ExtendedListFragment extends Fragment
         onCreateSwipeToRefresh(mRefreshListLayout);
 
         mFabMain = v.findViewById(R.id.fab_main);
-        mFabUpload = v.findViewById(R.id.fab_upload);
-        mFabMkdir = v.findViewById(R.id.fab_mkdir);
-        mFabUploadFromApp = v.findViewById(R.id.fab_upload_from_app);
-
-        applyFABTheming();
+        ThemeUtils.tintFloatingActionButton(mFabMain, R.drawable.ic_plus);
 
         boolean searchSupported = AccountUtils.hasSearchSupport(AccountUtils.
                 getCurrentOwnCloudAccount(MainApp.getAppContext()));
@@ -619,21 +595,6 @@ public class ExtendedListFragment extends Fragment
         }
     }
 
-
-    /**
-     * Set tinting of FAB's from server data
-     */
-    private void applyFABTheming() {
-        AddFloatingActionButton addButton = getFabMain().getAddButton();
-        addButton.setColorNormal(ThemeUtils.primaryColor());
-        addButton.setColorPressed(ThemeUtils.primaryDarkColor());
-        addButton.setPlusColor(ThemeUtils.fontColor());
-
-        ThemeUtils.tintFloatingActionButton(getFabUpload(), R.drawable.ic_action_upload);
-        ThemeUtils.tintFloatingActionButton(getFabMkdir(), R.drawable.ic_action_create_dir);
-        ThemeUtils.tintFloatingActionButton(getFabUploadFromApp(), R.drawable.ic_import);
-    }
-
     /**
      * Set message for empty list view.
      */

+ 42 - 0
src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java

@@ -0,0 +1,42 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2018 Andy Scherzinger
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.fragment;
+
+/**
+ * Actions interface to be implemented by any class that makes use of
+ * {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}.
+ */
+public interface OCFileListBottomSheetActions {
+    /**
+     * creates a folder within the actual folder.
+     */
+    void createFolder();
+
+    /**
+     * offers a file upload with the Android OS file picker to the current folder.
+     */
+    void uploadFromApp();
+
+    /**
+     * offers a file upload with the app file picker to the current folder.
+     */
+    void uploadFiles();
+}

+ 112 - 0
src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java

@@ -0,0 +1,112 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2018 Andy Scherzinger
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.fragment;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.BottomSheetBehavior;
+import android.support.design.widget.BottomSheetDialog;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.owncloud.android.R;
+import com.owncloud.android.utils.ThemeUtils;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import butterknife.Unbinder;
+
+/**
+ * FAB menu {@link android.app.Dialog} styled as a bottom sheet for main actions.
+ */
+public class OCFileListBottomSheetDialog extends BottomSheetDialog {
+    @BindView(R.id.menu_icon_upload_files)
+    public ImageView iconUploadFiles;
+    @BindView(R.id.menu_icon_upload_from_app)
+    public ImageView iconUploadFromApp;
+    @BindView(R.id.menu_icon_mkdir)
+    public ImageView iconMakeDir;
+    @BindView(R.id.add_to_cloud)
+    public TextView headline;
+
+    private Unbinder unbinder;
+
+    private OCFileListBottomSheetActions actions;
+
+
+    public OCFileListBottomSheetDialog(@NonNull Context context, OCFileListBottomSheetActions actions) {
+        super(context);
+        this.actions = actions;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final View view = getLayoutInflater().inflate(R.layout.file_list_actions_bottom_sheet_fragment, null);
+        setContentView(view);
+
+        if (getWindow() != null) {
+            getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        unbinder = ButterKnife.bind(this, view);
+
+        int primaryColor = ThemeUtils.primaryColor();
+        ThemeUtils.tintDrawable(iconUploadFiles.getDrawable(), primaryColor);
+        ThemeUtils.tintDrawable(iconUploadFromApp.getDrawable(), primaryColor);
+        ThemeUtils.tintDrawable(iconMakeDir.getDrawable(), primaryColor);
+
+        headline.setText(getContext().getResources().getString(R.string.add_to_cloud,
+                ThemeUtils.getDefaultDisplayNameForRootFolder()));
+
+        setOnShowListener(d ->
+                BottomSheetBehavior.from((View) view.getParent()).setPeekHeight(view.getMeasuredHeight())
+        );
+    }
+
+    @OnClick(R.id.menu_mkdir)
+    public void createFolder() {
+        actions.createFolder();
+        dismiss();
+    }
+
+    @OnClick(R.id.menu_upload_from_app)
+    public void uploadFromApp() {
+        actions.uploadFromApp();
+        dismiss();
+    }
+
+    @OnClick(R.id.menu_upload_files)
+    public void uploadFiles() {
+        actions.uploadFiles();
+        dismiss();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        unbinder.unbind();
+    }
+}

+ 29 - 139
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -55,7 +55,6 @@ import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.PopupMenu;
 import android.widget.RelativeLayout;
-import android.widget.TextView;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -122,7 +121,8 @@ import java.util.Set;
  * A Fragment that lists all files and folders in a given path.
  * TODO refactor to get rid of direct dependency on FileDisplayActivity
  */
-public class OCFileListFragment extends ExtendedListFragment implements OCFileListFragmentInterface {
+public class OCFileListFragment extends ExtendedListFragment implements
+        OCFileListFragmentInterface, OCFileListBottomSheetActions {
 
     private static final String TAG = OCFileListFragment.class.getSimpleName();
 
@@ -163,7 +163,6 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
     private int mProgressBarColor;
 
     private boolean mHideFab = true;
-    private boolean miniFabClicked = false;
     private ActionMode mActiveActionMode;
     private OCFileListFragment.MultiChoiceModeListener mMultiChoiceModeListener;
 
@@ -327,19 +326,7 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
             setFabEnabled(false);
         } else {
             setFabEnabled(true);
-            registerFabListeners();
-
-            // detect if a mini FAB has ever been clicked
-            if (PreferenceManager.getFABClicked(getActivity()) > 0) {
-                miniFabClicked = true;
-            }
-
-            // add labels to the min FABs when none of them has ever been clicked on
-            if (!miniFabClicked) {
-                setFabLabels();
-            } else {
-                removeFabLabels();
-            }
+            registerFabListener();
         }
 
         searchEvent = Parcels.unwrap(getArguments().getParcelable(OCFileListFragment.SEARCH_EVENT));
@@ -381,138 +368,41 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
     }
 
     /**
-     * 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(getActivity());
-        registerFabMkDirListeners(getActivity());
-        registerFabUploadFromAppListeners(getActivity());
-    }
-
-    /**
-     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
-     * on the Upload mini FAB for the linked action and {@link Snackbar} showing the underlying action.
-     *
-     * @param activity the activity on which's content the {@link Snackbar} will be shown.
+     * register listener on FAB.
      */
-    private void registerFabUploadListeners(final Activity activity) {
-        getFabUpload().setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                UploadFilesActivity.startUploadActivityForResult(getActivity(), ((FileActivity) getActivity())
-                        .getAccount(), FileDisplayActivity.REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM);
-                getFabMain().collapse();
-                recordMiniFabClick();
-            }
-        });
-
-        getFabUpload().setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                DisplayUtils.showSnackMessage(activity, R.string.actionbar_upload);
-                return true;
-            }
+    private void registerFabListener() {
+        getFabMain().setOnClickListener(v -> {
+            new OCFileListBottomSheetDialog(getContext(), this).show();
         });
     }
 
-    /**
-     * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
-     * on the 'Create Dir' mini FAB for the linked action and {@link Snackbar} showing the underlying action.
-     *
-     * @param activity the activity on which's content the {@link Snackbar} will be shown.
-     */
-    private void registerFabMkDirListeners(final Activity activity) {
-        getFabMkdir().setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                CreateFolderDialogFragment dialog =
-                        CreateFolderDialogFragment.newInstance(mFile);
-                dialog.show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
-                getFabMain().collapse();
-                recordMiniFabClick();
-            }
-        });
-
-        getFabMkdir().setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                DisplayUtils.showSnackMessage(activity, R.string.actionbar_mkdir);
-                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 Snackbar} showing the underlying action.
-     *
-     * @param activity the activity on which's content the {@link Snackbar} will be shown.
-     */
-    private void registerFabUploadFromAppListeners(final Activity activity) {
-        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)),
-                        FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
-                );
-                getFabMain().collapse();
-                recordMiniFabClick();
-            }
-        });
-
-        getFabUploadFromApp().setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                DisplayUtils.showSnackMessage(activity, R.string.actionbar_upload_from_apps);
-                return true;
-            }
-        });
+    @Override
+    public void createFolder() {
+        CreateFolderDialogFragment.newInstance(mFile)
+                .show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
     }
 
-    /**
-     * 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) {
-            PreferenceManager.setFABClicked(getActivity());
-            miniFabClicked = true;
+    @Override
+    public void uploadFromApp() {
+        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)),
+                FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
+        );
     }
 
-    /**
-     * 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);
+    @Override
+    public void uploadFiles() {
+        UploadFilesActivity.startUploadActivityForResult(
+                getActivity(),
+                ((FileActivity) getActivity()).getAccount(),
+                FileDisplayActivity.REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM
+        );
     }
 
     @Override

+ 5 - 5
src/main/java/com/owncloud/android/utils/ThemeUtils.java

@@ -31,6 +31,7 @@ import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.annotation.ColorInt;
 import android.support.annotation.DrawableRes;
+import android.support.design.widget.FloatingActionButton;
 import android.support.design.widget.Snackbar;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.content.ContextCompat;
@@ -47,7 +48,6 @@ import android.widget.ImageButton;
 import android.widget.ProgressBar;
 import android.widget.SeekBar;
 
-import com.getbase.floatingactionbutton.FloatingActionButton;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
@@ -368,10 +368,10 @@ public class ThemeUtils {
         return String.format("#%06X", 0xFFFFFF & color);
     }
 
-    public static void tintFloatingActionButton(FloatingActionButton button, int drawable) {
-        button.setColorNormal(ThemeUtils.primaryColor());
-        button.setColorPressed(ThemeUtils.primaryDarkColor());
-        button.setIconDrawable(ThemeUtils.tintDrawable(drawable, ThemeUtils.fontColor()));
+    public static void tintFloatingActionButton(FloatingActionButton button, @DrawableRes int drawable) {
+        button.setBackgroundTintList(ColorStateList.valueOf(ThemeUtils.primaryColor()));
+        button.setRippleColor(ThemeUtils.primaryDarkColor());
+        button.setImageDrawable(ThemeUtils.tintDrawable(drawable, ThemeUtils.fontColor()));
     }
 
     private static OCCapability getCapability() {

+ 24 - 0
src/main/res/drawable/ic_plus.xml

@@ -0,0 +1,24 @@
+<!--
+    @author Google LLC
+    Copyright (C) 2018 Google LLC
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path android:fillColor="#000" android:pathData="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z" />
+</vector>

+ 4 - 3
src/main/res/layout/account_action.xml

@@ -19,12 +19,13 @@
   You should have received a copy of the GNU Affero General Public
   License along with this program. If not, see <http://www.gnu.org/licenses/>.
 -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="fill_parent"
     android:layout_height="@dimen/account_action_layout_height"
     android:orientation="horizontal"
-    android:weightSum="1">
+    android:weightSum="1"
+    tools:ignore="UseCompoundDrawables">
 
     <ImageView
         android:id="@+id/user_icon"

+ 7 - 5
src/main/res/layout/file_details_fragment.xml

@@ -18,10 +18,11 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:id="@+id/fdScrollView"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:fillViewport="true">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/fdScrollView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -202,7 +203,8 @@
             <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="horizontal">
+                android:orientation="horizontal"
+                tools:ignore="UseCompoundDrawables">
 
                 <ImageView
                     android:contentDescription="@string/shared_icon"

+ 6 - 4
src/main/res/layout/file_details_share_user_item.xml

@@ -16,10 +16,12 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:weightSum="1">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:weightSum="1"
+    tools:ignore="UseCompoundDrawables">
 
         <ImageView
             android:id="@+id/userIcon"

+ 136 - 0
src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml

@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Nextcloud Android client application
+
+  Copyright (C) 2018 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/add_to_cloud"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="@dimen/standard_padding"
+        android:text="@string/add_to_cloud"
+        android:textSize="@dimen/bottom_sheet_text_size" />
+
+    <LinearLayout
+        android:id="@+id/menu_upload_files"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingBottom="@dimen/standard_half_padding"
+        android:paddingLeft="@dimen/standard_padding"
+        android:paddingRight="@dimen/standard_padding"
+        android:paddingTop="@dimen/standard_half_padding"
+        tools:ignore="UseCompoundDrawables">
+
+        <ImageView
+            android:id="@+id/menu_icon_upload_files"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@null"
+            android:src="@drawable/ic_action_upload"
+            android:tint="@color/primary" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="@dimen/standard_margin"
+            android:layout_marginStart="@dimen/standard_margin"
+            android:text="@string/upload_files"
+            android:textColor="@color/black"
+            android:textSize="@dimen/bottom_sheet_text_size" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/menu_upload_from_app"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingBottom="@dimen/standard_half_padding"
+        android:paddingLeft="@dimen/standard_padding"
+        android:paddingRight="@dimen/standard_padding"
+        android:paddingTop="@dimen/standard_half_padding"
+        tools:ignore="UseCompoundDrawables">
+
+        <ImageView
+            android:id="@+id/menu_icon_upload_from_app"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@null"
+            android:src="@drawable/ic_import"
+            android:tint="@color/primary" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="@dimen/standard_margin"
+            android:layout_marginStart="@dimen/standard_margin"
+            android:text="@string/upload_content_from_other_apps"
+            android:textColor="@color/black"
+            android:textSize="@dimen/bottom_sheet_text_size" />
+
+    </LinearLayout>
+
+    <View
+        android:id="@+id/divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_marginBottom="@dimen/standard_half_margin"
+        android:layout_marginLeft="@dimen/standard_margin"
+        android:layout_marginRight="@dimen/standard_margin"
+        android:layout_marginTop="@dimen/standard_half_margin"
+        android:background="@color/list_divider_background" />
+
+    <LinearLayout
+        android:id="@+id/menu_mkdir"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingBottom="@dimen/standard_padding"
+        android:paddingLeft="@dimen/standard_padding"
+        android:paddingRight="@dimen/standard_padding"
+        android:paddingTop="@dimen/standard_half_padding"
+        tools:ignore="UseCompoundDrawables">
+
+        <ImageView
+            android:id="@+id/menu_icon_mkdir"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@null"
+            android:src="@drawable/ic_action_create_dir"
+            android:tint="@color/primary" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="@dimen/standard_margin"
+            android:layout_marginStart="@dimen/standard_margin"
+            android:text="@string/create_new_folder"
+            android:textColor="@color/black"
+            android:textSize="@dimen/bottom_sheet_text_size" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 2 - 35
src/main/res/layout/list_fragment.xml

@@ -46,7 +46,7 @@
 
     </android.support.design.widget.CoordinatorLayout>
 
-    <com.getbase.floatingactionbutton.FloatingActionsMenu
+    <android.support.design.widget.FloatingActionButton
         android:id="@+id/fab_main"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -56,40 +56,7 @@
         android:layout_marginBottom="@dimen/standard_margin"
         android:layout_marginEnd="@dimen/standard_margin"
         android:layout_marginRight="@dimen/standard_margin"
-        android:visibility="gone"
-        app:fab_labelStyle="@style/menu_labels_style">
-
-        <com.getbase.floatingactionbutton.FloatingActionButton
-            android:id="@+id/fab_upload"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:fab_colorNormal="@color/primary_button_background_color"
-            app:fab_colorPressed="@color/primary"
-            app:fab_icon="@drawable/ic_action_upload"
-            app:fab_size="mini"
-            app:fab_title=""/>
-
-        <com.getbase.floatingactionbutton.FloatingActionButton
-            android:id="@+id/fab_upload_from_app"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:fab_colorNormal="@color/primary_button_background_color"
-            app:fab_colorPressed="@color/primary"
-            app:fab_icon="@drawable/ic_import"
-            app:fab_size="mini"
-            app:fab_title=""/>
-
-        <com.getbase.floatingactionbutton.FloatingActionButton
-            android:id="@+id/fab_mkdir"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:fab_colorNormal="@color/primary_button_background_color"
-            app:fab_colorPressed="@color/primary"
-            app:fab_icon="@drawable/ic_action_create_dir"
-            app:fab_size="mini"
-            app:fab_title=""/>
-
-    </com.getbase.floatingactionbutton.FloatingActionsMenu>
+        android:visibility="gone" />
 
     <android.support.design.widget.BottomNavigationView
         android:id="@+id/bottom_navigation_view"

+ 3 - 1
src/main/res/layout/preview_image_error_fragment.xml

@@ -19,6 +19,7 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/top"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -27,7 +28,8 @@
     android:gravity="center_vertical|center_horizontal"
     android:orientation="vertical"
     android:paddingBottom="@dimen/standard_double_margin"
-    android:animateLayoutChanges="true">
+    android:animateLayoutChanges="true"
+    tools:ignore="UseCompoundDrawables">
 
     <ImageView
         android:id="@+id/preview_error_image"

+ 3 - 1
src/main/res/layout/send_button.xml

@@ -20,10 +20,12 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical"
-    android:paddingTop="@dimen/standard_padding">
+    android:paddingTop="@dimen/standard_padding"
+    tools:ignore="UseCompoundDrawables">
 
     <ImageView
         android:id="@+id/send_button_icon"

+ 7 - 5
src/main/res/layout/send_share_fragment.xml

@@ -19,10 +19,10 @@
  You should have received a copy of the GNU Affero General Public License
  along with this program. If not, see <http://www.gnu.org/licenses/>.
 -->
-
 <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                                                 android:layout_width="match_parent"
-                                                 android:layout_height="match_parent">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
     <RelativeLayout
         android:layout_width="match_parent"
@@ -44,7 +44,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="vertical">
+            android:orientation="vertical"
+            tools:ignore="UseCompoundDrawables">
 
             <ImageView
                 android:id="@+id/share_people_icon"
@@ -76,7 +77,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="vertical">
+            android:orientation="vertical"
+            tools:ignore="UseCompoundDrawables">
 
             <ImageView
                 android:id="@+id/share_link_icon"

+ 1 - 0
src/main/res/values/dims.xml

@@ -144,5 +144,6 @@
     <dimen name="synced_folders_progress_bar_layout_height">72dp</dimen>
     <dimen name="synced_folders_recycler_view_layout_margin">-3dp</dimen>
     <dimen name="toolbar_user_information_layout_margin">12dp</dimen>
+    <dimen name="bottom_sheet_text_size">16sp</dimen>
     <integer name="media_grid_width">4</integer>
 </resources>

+ 4 - 0
src/main/res/values/strings.xml

@@ -779,4 +779,8 @@
     <string name="hidden_character" translatable="false">*</string>
     <string name="hint_name">Name</string>
     <string name="hint_password">Password</string>
+    <string name="add_to_cloud">Add to %1$s</string>
+    <string name="upload_files">Upload files</string>
+    <string name="upload_content_from_other_apps">Upload content from other apps</string>
+    <string name="create_new_folder">Create new folder</string>
 </resources>