Explorar o código

Merge pull request #12064 from nextcloud/feature/use-m3-SendFilesDialog-BottomSheet

Use Material Design 3 For Send Files Bottom Sheet
Andy Scherzinger hai 1 ano
pai
achega
9e17bcb779

BIN=BIN
app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialogDifferentTypes_Screenshot.png


BIN=BIN
app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialog_Screenshot.png


+ 4 - 0
app/src/main/java/com/nextcloud/client/di/ComponentsModule.java

@@ -95,6 +95,7 @@ import com.owncloud.android.ui.dialog.MultipleAccountsDialog;
 import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment;
 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 import com.owncloud.android.ui.dialog.RenamePublicShareDialogFragment;
+import com.owncloud.android.ui.dialog.SendFilesDialog;
 import com.owncloud.android.ui.dialog.SendShareDialog;
 import com.owncloud.android.ui.dialog.SetupEncryptionDialogFragment;
 import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
@@ -460,6 +461,9 @@ abstract class ComponentsModule {
     @ContributesAndroidInjector
     abstract FileActionsBottomSheet fileActionsBottomSheet();
 
+    @ContributesAndroidInjector
+    abstract SendFilesDialog sendFilesDialog();
+
     @ContributesAndroidInjector
     abstract DocumentScanActivity documentScanActivity();
 

+ 0 - 135
app/src/main/java/com/owncloud/android/ui/dialog/SendFilesDialog.java

@@ -1,135 +0,0 @@
-package com.owncloud.android.ui.dialog;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Toast;
-
-import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
-import com.nextcloud.client.utils.IntentUtil;
-import com.owncloud.android.R;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.ui.adapter.SendButtonAdapter;
-import com.owncloud.android.ui.components.SendButtonData;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-/*
- * Nextcloud Android client application
- *
- * @author Tobias Kaminsky
- * Copyright (C) 2020 Tobias Kaminsky
- * Copyright (C) 2020 Nextcloud GmbH.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero 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 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/>.
- */
-public class SendFilesDialog extends BottomSheetDialogFragment {
-
-    private static final String KEY_OCFILES = "KEY_OCFILES";
-
-    private OCFile[] files;
-
-    public static SendFilesDialog newInstance(Set<OCFile> files) {
-
-        SendFilesDialog dialogFragment = new SendFilesDialog();
-
-        Bundle args = new Bundle();
-        args.putParcelableArray(KEY_OCFILES, files.toArray(new OCFile[0]));
-        dialogFragment.setArguments(args);
-
-        return dialogFragment;
-    }
-
-    @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        // keep the state of the fragment on configuration changes
-        setRetainInstance(true);
-
-        files = (OCFile[]) requireArguments().getParcelableArray(KEY_OCFILES);
-    }
-
-    @Nullable
-    @Override
-    public View onCreateView(@NonNull LayoutInflater inflater,
-                             @Nullable ViewGroup container,
-                             @Nullable Bundle savedInstanceState) {
-
-        View view = inflater.inflate(R.layout.send_files_fragment, container, false);
-
-        // populate send apps
-        Intent sendIntent = IntentUtil.createSendIntent(requireContext(), files);
-        List<ResolveInfo> matches = requireActivity().getPackageManager().queryIntentActivities(sendIntent, 0);
-        if (matches.isEmpty()) {
-            Toast.makeText(getContext(), R.string.no_send_app, Toast.LENGTH_SHORT).show();
-            dismiss();
-            return null;
-        }
-
-        List<SendButtonData> sendButtonDataList = setupSendButtonData(matches);
-
-        SendButtonAdapter.ClickListener clickListener = setupSendButtonClickListener(sendIntent);
-
-        RecyclerView sendButtonsView = view.findViewById(R.id.send_button_recycler_view);
-        sendButtonsView.setLayoutManager(new GridLayoutManager(getActivity(), 4));
-        sendButtonsView.setAdapter(new SendButtonAdapter(sendButtonDataList, clickListener));
-
-        return view;
-    }
-
-    @NonNull
-    private SendButtonAdapter.ClickListener setupSendButtonClickListener(Intent sendIntent) {
-        return sendButtonDataData -> {
-            String packageName = sendButtonDataData.getPackageName();
-            String activityName = sendButtonDataData.getActivityName();
-
-            sendIntent.setComponent(new ComponentName(packageName, activityName));
-            requireActivity().startActivity(Intent.createChooser(sendIntent, getString(R.string.send)));
-
-            dismiss();
-        };
-    }
-
-    @NonNull
-    private List<SendButtonData> setupSendButtonData(List<ResolveInfo> matches) {
-        Drawable icon;
-        SendButtonData sendButtonData;
-        CharSequence label;
-
-        List<SendButtonData> sendButtonDataList = new ArrayList<>(matches.size());
-        for (ResolveInfo match : matches) {
-            icon = match.loadIcon(requireActivity().getPackageManager());
-            label = match.loadLabel(requireActivity().getPackageManager());
-            sendButtonData = new SendButtonData(icon, label,
-                                                match.activityInfo.packageName,
-                                                match.activityInfo.name);
-
-            sendButtonDataList.add(sendButtonData);
-        }
-        return sendButtonDataList;
-    }
-}

+ 138 - 0
app/src/main/java/com/owncloud/android/ui/dialog/SendFilesDialog.kt

@@ -0,0 +1,138 @@
+package com.owncloud.android.ui.dialog
+
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.ResolveInfo
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.recyclerview.widget.GridLayoutManager
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import com.nextcloud.android.common.ui.theme.utils.ColorRole
+import com.nextcloud.client.di.Injectable
+import com.nextcloud.client.utils.IntentUtil.createSendIntent
+import com.owncloud.android.R
+import com.owncloud.android.databinding.SendFilesFragmentBinding
+import com.owncloud.android.datamodel.OCFile
+import com.owncloud.android.ui.adapter.SendButtonAdapter
+import com.owncloud.android.ui.components.SendButtonData
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import javax.inject.Inject
+
+/*
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2020 Tobias Kaminsky
+ * Copyright (C) 2020 Nextcloud GmbH.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 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/>.
+ */
+class SendFilesDialog : BottomSheetDialogFragment(R.layout.send_files_fragment), Injectable {
+
+    private var files: Array<OCFile>? = null
+    private lateinit var binding: SendFilesFragmentBinding
+
+    @JvmField
+    @Inject
+    var viewThemeUtils: ViewThemeUtils? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        // keep the state of the fragment on configuration changes
+        retainInstance = true
+
+        files = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+            requireArguments().getParcelableArray(KEY_OCFILES, OCFile::class.java)
+        } else {
+            @Suppress("DEPRECATION")
+            requireArguments().getParcelableArray(KEY_OCFILES) as Array<OCFile>?
+        }
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        binding = SendFilesFragmentBinding.inflate(inflater, container, false)
+
+        setupSendButtonRecyclerView()
+        viewThemeUtils?.platform?.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE)
+
+        return binding.root
+    }
+
+    private fun setupSendButtonRecyclerView() {
+        val sendIntent = createSendIntent(requireContext(), files!!)
+        val matches = requireActivity().packageManager.queryIntentActivities(sendIntent, 0)
+
+        if (matches.isEmpty()) {
+            Toast.makeText(context, R.string.no_send_app, Toast.LENGTH_SHORT).show()
+            dismiss()
+            return
+        }
+
+        val sendButtonDataList = setupSendButtonData(matches)
+        val clickListener = setupSendButtonClickListener(sendIntent)
+
+        @Suppress("MagicNumber")
+        binding.sendButtonRecyclerView.layoutManager = GridLayoutManager(requireActivity(), 4)
+        binding.sendButtonRecyclerView.adapter = SendButtonAdapter(sendButtonDataList, clickListener)
+    }
+
+    private fun setupSendButtonClickListener(sendIntent: Intent): SendButtonAdapter.ClickListener {
+        return SendButtonAdapter.ClickListener { sendButtonDataData: SendButtonData ->
+            val packageName = sendButtonDataData.packageName
+            val activityName = sendButtonDataData.activityName
+            sendIntent.component = ComponentName(packageName, activityName)
+            requireActivity().startActivity(Intent.createChooser(sendIntent, getString(R.string.send)))
+            dismiss()
+        }
+    }
+
+    private fun setupSendButtonData(matches: List<ResolveInfo>): List<SendButtonData> {
+        var icon: Drawable
+        var sendButtonData: SendButtonData
+        var label: CharSequence
+        val sendButtonDataList: MutableList<SendButtonData> = ArrayList(matches.size)
+        for (match in matches) {
+            icon = match.loadIcon(requireActivity().packageManager)
+            label = match.loadLabel(requireActivity().packageManager)
+            sendButtonData = SendButtonData(
+                icon, label,
+                match.activityInfo.packageName,
+                match.activityInfo.name
+            )
+            sendButtonDataList.add(sendButtonData)
+        }
+        return sendButtonDataList
+    }
+
+    companion object {
+        private const val KEY_OCFILES = "KEY_OCFILES"
+
+        fun newInstance(files: Set<OCFile>): SendFilesDialog {
+            val dialogFragment = SendFilesDialog()
+            val args = Bundle()
+            args.putParcelableArray(KEY_OCFILES, files.toTypedArray())
+            dialogFragment.arguments = args
+            return dialogFragment
+        }
+    }
+}

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

@@ -810,7 +810,7 @@ public class FileOperationsHelper {
         FragmentTransaction ft = fm.beginTransaction();
         ft.addToBackStack(null);
 
-        SendFilesDialog sendFilesDialog = SendFilesDialog.newInstance(files);
+        SendFilesDialog sendFilesDialog = SendFilesDialog.Companion.newInstance(files);
         sendFilesDialog.show(ft, "TAG_SEND_SHARE_DIALOG");
     }
 

+ 26 - 7
app/src/main/res/layout/send_files_fragment.xml

@@ -18,19 +18,38 @@
  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/>.
 -->
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<FrameLayout
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/standard_bottom_sheet"
+    style="@style/Widget.Material3.BottomSheet"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="wrap_content"
+    android:layout_gravity="bottom"
+    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
 
-    <RelativeLayout
+    <LinearLayout
+        android:id="@+id/bottom_sheet"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <com.google.android.material.bottomsheet.BottomSheetDragHandleView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/send_button_recycler_view"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            tools:listitem="@layout/send_button" />
-    </RelativeLayout>
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
+            tools:listitem="@layout/send_button"/>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/standard_padding"/>
+
+    </LinearLayout>
+
+</FrameLayout>