Browse Source

Merge pull request #12041 from nextcloud/feature/use-m3-confirmation-dialog

Use Material Design 3 For Confirmation Dialog
Andy Scherzinger 1 year ago
parent
commit
d13f28017c

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


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


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


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


+ 18 - 0
app/src/androidTest/java/com/owncloud/android/AbstractIT.java

@@ -7,6 +7,8 @@ import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
@@ -58,6 +60,7 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collection;
+import java.util.Locale;
 import java.util.Objects;
 
 import androidx.annotation.NonNull;
@@ -403,6 +406,21 @@ public abstract class AbstractIT {
         assertTrue(result.getLogMessage(), result.isSuccess());
     }
 
+    protected void enableRTL() {
+        Locale locale = new Locale("ar");
+        Resources resources = InstrumentationRegistry.getInstrumentation().getTargetContext().getResources();
+        Configuration config = resources.getConfiguration();
+        config.setLocale(locale);
+        resources.updateConfiguration(config, null);
+    }
+
+    protected void resetLocale() {
+        Resources resources = InstrumentationRegistry.getInstrumentation().getTargetContext().getResources();
+        Configuration defaultConfig = resources.getConfiguration();
+        defaultConfig.setLocale(Locale.getDefault());
+        resources.updateConfiguration(defaultConfig, null);
+    }
+
     protected void screenshot(View view) {
         screenshot(view, "");
     }

+ 32 - 0
app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java

@@ -138,6 +138,38 @@ public class DialogFragmentIT extends AbstractIT {
         showDialog(dialog);
     }
 
+    @Test
+    @ScreenshotTest
+    public void testConfirmationDialogWithOneAction() {
+        ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_list_empty_text_auto_upload, new String[]{}, R.string.filedetails_sync_file, R.string.common_ok, -1, -1);
+        showDialog(dialog);
+    }
+
+    @Test
+    @ScreenshotTest
+    public void testConfirmationDialogWithTwoAction() {
+        ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_list_empty_text_auto_upload, new String[]{}, R.string.filedetails_sync_file, R.string.common_ok, R.string.common_cancel, -1);
+        showDialog(dialog);
+    }
+
+    @Test
+    @ScreenshotTest
+    public void testConfirmationDialogWithThreeAction() {
+        ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_list_empty_text_auto_upload, new String[]{}, R.string.filedetails_sync_file, R.string.common_ok, R.string.common_cancel, R.string.common_confirm);
+        showDialog(dialog);
+    }
+
+    @Test
+    @ScreenshotTest
+    public void testConfirmationDialogWithThreeActionRTL() {
+        enableRTL();
+
+        ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_list_empty_text_auto_upload, new String[] { }, -1, R.string.common_ok, R.string.common_cancel, R.string.common_confirm);
+        showDialog(dialog);
+
+        resetLocale();
+    }
+
     @Test
     @ScreenshotTest
     public void testRemoveFileDialog() {

+ 1 - 3
app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java

@@ -528,9 +528,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
             // to the ownCloud folder instead of copying
             String[] args = {getString(R.string.app_name)};
             ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(
-                R.string.upload_query_move_foreign_files, args, 0, R.string.common_yes, -1,
-                R.string.common_no
-                                                                                      );
+                R.string.upload_query_move_foreign_files, args, 0, R.string.common_yes,  R.string.common_no, -1);
             dialog.setOnConfirmationListener(this);
             dialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
         }

+ 0 - 173
app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java

@@ -1,173 +0,0 @@
-/*
- * ownCloud Android client application
- *
- * Copyright (C) 2012 Bartek Przybylski Copyright (C) 2015 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation.
- *
- * 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
- * <http://www.gnu.org/licenses/>.
- */
-
-package com.owncloud.android.ui.dialog;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.os.Bundle;
-
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.nextcloud.client.di.Injectable;
-import com.owncloud.android.R;
-import com.owncloud.android.utils.theme.ViewThemeUtils;
-
-import javax.inject.Inject;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-
-
-public class ConfirmationDialogFragment extends DialogFragment implements Injectable {
-
-    final static String ARG_MESSAGE_RESOURCE_ID = "resource_id";
-    final static String ARG_MESSAGE_ARGUMENTS = "string_array";
-    final static String ARG_TITLE_ID = "title_id";
-
-    final static String ARG_POSITIVE_BTN_RES = "positive_btn_res";
-    final static String ARG_NEUTRAL_BTN_RES = "neutral_btn_res";
-    final static String ARG_NEGATIVE_BTN_RES = "negative_btn_res";
-
-    public static final String FTAG_CONFIRMATION = "CONFIRMATION_FRAGMENT";
-
-    @Inject ViewThemeUtils viewThemeUtils;
-
-
-    private ConfirmationDialogFragmentListener mListener;
-
-    /**
-     * Public factory method to create new ConfirmationDialogFragment instances.
-     *
-     * @param messageResId     Resource id for a message to show in the dialog.
-     * @param messageArguments Arguments to complete the message, if it's a format string. May be null.
-     * @param titleResId       Resource id for a text to show in the title. 0 for default alert title, -1 for no title.
-     * @param posBtn           Resource id for the text of the positive button. -1 for no positive button.
-     * @param neuBtn           Resource id for the text of the neutral button. -1 for no neutral button.
-     * @param negBtn           Resource id for the text of the negative button. -1 for no negative button.
-     * @return Dialog ready to show.
-     */
-    public static ConfirmationDialogFragment newInstance(int messageResId, String[] messageArguments, int titleResId,
-                                                         int posBtn, int neuBtn, int negBtn) {
-        if (messageResId == -1) {
-            throw new IllegalStateException("Calling confirmation dialog without message resource");
-        }
-
-        ConfirmationDialogFragment frag = new ConfirmationDialogFragment();
-        Bundle args = new Bundle();
-        args.putInt(ARG_MESSAGE_RESOURCE_ID, messageResId);
-        args.putStringArray(ARG_MESSAGE_ARGUMENTS, messageArguments);
-        args.putInt(ARG_TITLE_ID, titleResId);
-        args.putInt(ARG_POSITIVE_BTN_RES, posBtn);
-        args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn);
-        args.putInt(ARG_NEGATIVE_BTN_RES, negBtn);
-        frag.setArguments(args);
-        return frag;
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        AlertDialog alertDialog = (AlertDialog) getDialog();
-
-        if(alertDialog != null) {
-            viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE),
-                                                     alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE),
-                                                     alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL));
-        }
-    }
-
-    public void setOnConfirmationListener(ConfirmationDialogFragmentListener listener) {
-        mListener = listener;
-    }
-
-    @NonNull
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        Bundle arguments = getArguments();
-
-        if (arguments == null) {
-            throw new IllegalArgumentException("Arguments may not be null");
-        }
-
-        Activity activity = getActivity();
-
-        if (activity == null) {
-            throw new IllegalArgumentException("Activity may not be null");
-        }
-
-        Object[] messageArguments = arguments.getStringArray(ARG_MESSAGE_ARGUMENTS);
-        int messageId = arguments.getInt(ARG_MESSAGE_RESOURCE_ID, -1);
-        int titleId = arguments.getInt(ARG_TITLE_ID, -1);
-        int posBtn = arguments.getInt(ARG_POSITIVE_BTN_RES, -1);
-        int neuBtn = arguments.getInt(ARG_NEUTRAL_BTN_RES, -1);
-        int negBtn = arguments.getInt(ARG_NEGATIVE_BTN_RES, -1);
-
-        if (messageArguments == null) {
-            messageArguments = new String[]{};
-        }
-
-        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity)
-            .setIcon(R.drawable.ic_warning)
-            .setIconAttribute(android.R.attr.alertDialogIcon)
-            .setMessage(String.format(getString(messageId), messageArguments));
-
-        if (titleId == 0) {
-            builder.setTitle(android.R.string.dialog_alert_title);
-        } else if (titleId != -1) {
-            builder.setTitle(titleId);
-        }
-
-        if (posBtn != -1) {
-            builder.setPositiveButton(posBtn, (dialog, whichButton) -> {
-                if (mListener != null) {
-                    mListener.onConfirmation(getTag());
-                }
-                dialog.dismiss();
-            });
-        }
-        if (neuBtn != -1) {
-            builder.setNeutralButton(neuBtn, (dialog, whichButton) -> {
-                if (mListener != null) {
-                    mListener.onNeutral(getTag());
-                }
-                dialog.dismiss();
-            });
-        }
-        if (negBtn != -1) {
-            builder.setNegativeButton(negBtn, (dialog, which) -> {
-                if (mListener != null) {
-                    mListener.onCancel(getTag());
-                }
-                dialog.dismiss();
-            });
-        }
-
-        viewThemeUtils.dialog.colorMaterialAlertDialogBackground(activity, builder);
-
-        return builder.create();
-    }
-
-    public interface ConfirmationDialogFragmentListener {
-        void onConfirmation(String callerTag);
-
-        void onNeutral(String callerTag);
-
-        void onCancel(String callerTag);
-    }
-}
-

+ 161 - 0
app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt

@@ -0,0 +1,161 @@
+/*
+ * ownCloud Android client application
+ *
+ * Copyright (C) 2012 Bartek Przybylski Copyright (C) 2015 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation.
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.dialog
+
+//noinspection SuspiciousImport
+import android.R
+import android.app.Dialog
+import android.content.DialogInterface
+import android.os.Bundle
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.di.Injectable
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import javax.inject.Inject
+
+open class ConfirmationDialogFragment : DialogFragment(), Injectable {
+
+    @JvmField
+    @Inject
+    var viewThemeUtils: ViewThemeUtils? = null
+
+    private var mListener: ConfirmationDialogFragmentListener? = null
+
+    override fun onStart() {
+        super.onStart()
+
+        val alertDialog = dialog as AlertDialog?
+
+        if (alertDialog != null) {
+            val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton?
+            if (positiveButton != null) {
+                viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton)
+            }
+
+            val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton?
+            if (negativeButton != null) {
+                viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton)
+            }
+
+            val neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) as MaterialButton?
+            if (neutralButton != null) {
+                viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(neutralButton)
+            }
+        }
+    }
+
+    fun setOnConfirmationListener(listener: ConfirmationDialogFragmentListener?) {
+        mListener = listener
+    }
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        var messageArguments = requireArguments().getStringArray(ARG_MESSAGE_ARGUMENTS)
+        val titleId = requireArguments().getInt(ARG_TITLE_ID, -1)
+        val messageId = requireArguments().getInt(ARG_MESSAGE_RESOURCE_ID, -1)
+        val positiveButtonTextId = requireArguments().getInt(ARG_POSITIVE_BTN_RES, -1)
+        val negativeButtonTextId = requireArguments().getInt(ARG_NEGATIVE_BTN_RES, -1)
+        val neutralButtonTextId = requireArguments().getInt(ARG_NEUTRAL_BTN_RES, -1)
+
+        if (messageArguments == null) {
+            messageArguments = arrayOf<String?>()
+        }
+
+        val builder = MaterialAlertDialogBuilder(requireActivity())
+            .setIcon(com.owncloud.android.R.drawable.ic_warning)
+            .setIconAttribute(R.attr.alertDialogIcon)
+            .setMessage(String.format(getString(messageId), messageArguments))
+
+        if (titleId == 0) {
+            builder.setTitle(R.string.dialog_alert_title)
+        } else if (titleId != -1) {
+            builder.setTitle(titleId)
+        }
+        if (positiveButtonTextId != -1) {
+            builder.setPositiveButton(positiveButtonTextId) { dialog: DialogInterface, _: Int ->
+                mListener?.onConfirmation(tag)
+                dialog.dismiss()
+            }
+        }
+        if (negativeButtonTextId != -1) {
+            builder.setNegativeButton(negativeButtonTextId) { dialog: DialogInterface, _: Int ->
+                mListener?.onCancel(tag)
+                dialog.dismiss()
+            }
+        }
+        if (neutralButtonTextId != -1) {
+            builder.setNeutralButton(neutralButtonTextId) { dialog: DialogInterface, _: Int ->
+                mListener?.onNeutral(tag)
+                dialog.dismiss()
+            }
+        }
+
+        viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder)
+
+        return builder.create()
+    }
+
+    interface ConfirmationDialogFragmentListener {
+        fun onConfirmation(callerTag: String?)
+        fun onNeutral(callerTag: String?)
+        fun onCancel(callerTag: String?)
+    }
+
+    companion object {
+        const val ARG_MESSAGE_RESOURCE_ID = "resource_id"
+        const val ARG_MESSAGE_ARGUMENTS = "string_array"
+        const val ARG_TITLE_ID = "title_id"
+        const val ARG_POSITIVE_BTN_RES = "positive_btn_res"
+        const val ARG_NEUTRAL_BTN_RES = "neutral_btn_res"
+        const val ARG_NEGATIVE_BTN_RES = "negative_btn_res"
+        const val FTAG_CONFIRMATION = "CONFIRMATION_FRAGMENT"
+
+        /**
+         * Public factory method to create new ConfirmationDialogFragment instances.
+         *
+         * @param messageResId         Resource id for a message to show in the dialog.
+         * @param messageArguments     Arguments to complete the message, if it's a format string. May be null.
+         * @param titleResId           Resource id for a text to show in the title. 0 for default alert title, -1 for no
+         * title.
+         * @param positiveButtonTextId Resource id for the text of the positive button. -1 for no positive button.
+         * @param neutralButtonTextId  Resource id for the text of the neutral button. -1 for no neutral button.
+         * @param negativeButtonTextId Resource id for the text of the negative button. -1 for no negative button.
+         * @return Dialog ready to show.
+         */
+        @JvmStatic
+        fun newInstance(
+            messageResId: Int,
+            messageArguments: Array<String?>?,
+            titleResId: Int,
+            positiveButtonTextId: Int,
+            negativeButtonTextId: Int,
+            neutralButtonTextId: Int
+        ): ConfirmationDialogFragment {
+            check(messageResId != -1) { "Calling confirmation dialog without message resource" }
+            val frag = ConfirmationDialogFragment()
+            val args = Bundle()
+            args.putInt(ARG_MESSAGE_RESOURCE_ID, messageResId)
+            args.putStringArray(ARG_MESSAGE_ARGUMENTS, messageArguments)
+            args.putInt(ARG_TITLE_ID, titleResId)
+            args.putInt(ARG_POSITIVE_BTN_RES, positiveButtonTextId)
+            args.putInt(ARG_NEGATIVE_BTN_RES, negativeButtonTextId)
+            args.putInt(ARG_NEUTRAL_BTN_RES, neutralButtonTextId)
+            frag.arguments = args
+            return frag
+        }
+    }
+}