diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png index e451319a42a4..bb93a174e2db 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png index caa860dc2b97..f61b09696988 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png index ff264659676c..ef0b1d7912b4 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png index caa860dc2b97..f61b09696988 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png differ diff --git a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java index 68bd9cc9d452..98fe9c75e576 100644 --- a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -7,6 +7,8 @@ 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.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 boolean isPowerSavingExclusionAvailable() { 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, ""); } diff --git a/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java b/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java index a440e88a8bce..3853215b7754 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java +++ b/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java @@ -138,6 +138,38 @@ public void testLoadingDialog() { 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() { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java index 8a8572e3002f..bff39ae57e0e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -528,9 +528,7 @@ public void onCheckAvailableSpaceFinish(boolean hasEnoughSpaceAvailable, String. // 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); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java deleted file mode 100644 index 7c0c19001daf..000000000000 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java +++ /dev/null @@ -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 - * . - */ - -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); - } -} - diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt new file mode 100644 index 000000000000..48b37961e613 --- /dev/null +++ b/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 + * . + */ +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() + } + + 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?, + 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 + } + } +}