From a8ae4ddde8e361941c558dca6f5543d19797d135 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 8 Jun 2020 16:33:56 +0200 Subject: [PATCH] Power level: use confirmation dialog --- .../core/dialogs/ConfirmationDialogBuilder.kt | 61 ++++++++++++ .../core/ui/views/NotificationAreaView.kt | 7 -- .../home/room/detail/RoomDetailFragment.kt | 32 ++---- .../RoomMemberProfileFragment.kt | 97 +++++++++++++------ ...ml => dialog_confirmation_with_reason.xml} | 17 ++-- vector/src/main/res/values/strings.xml | 30 +++--- 6 files changed, 164 insertions(+), 80 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/core/dialogs/ConfirmationDialogBuilder.kt rename vector/src/main/res/layout/{dialog_delete_event.xml => dialog_confirmation_with_reason.xml} (74%) diff --git a/vector/src/main/java/im/vector/riotx/core/dialogs/ConfirmationDialogBuilder.kt b/vector/src/main/java/im/vector/riotx/core/dialogs/ConfirmationDialogBuilder.kt new file mode 100644 index 0000000000..aa95b29c4d --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/core/dialogs/ConfirmationDialogBuilder.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * 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. + */ + +package im.vector.riotx.core.dialogs + +import android.app.Activity +import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isVisible +import im.vector.riotx.R +import kotlinx.android.synthetic.main.dialog_confirmation_with_reason.view.* + +object ConfirmationDialogBuilder { + + fun show(activity: Activity, + askForReason: Boolean, + @StringRes titleRes: Int, + @StringRes confirmationRes: Int, + @StringRes positiveRes: Int, + @StringRes reasonHintRes: Int, + confirmation: (String?) -> Unit) { + val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null) + layout.dialogConfirmationText.setText(confirmationRes) + + layout.dialogReasonCheck.isVisible = askForReason + layout.dialogReasonTextInputLayout.isVisible = askForReason + + layout.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked -> + layout.dialogReasonTextInputLayout.isEnabled = isChecked + } + if (askForReason && reasonHintRes != 0) { + layout.dialogReasonInput.setHint(reasonHintRes) + } + + AlertDialog.Builder(activity) + .setTitle(titleRes) + .setView(layout) + .setPositiveButton(positiveRes) { _, _ -> + val reason = layout.dialogReasonInput.text.toString() + .takeIf { askForReason } + ?.takeIf { layout.dialogReasonCheck.isChecked } + ?.takeIf { it.isNotBlank() } + confirmation(reason) + } + .setNegativeButton(R.string.cancel, null) + .show() + } +} diff --git a/vector/src/main/java/im/vector/riotx/core/ui/views/NotificationAreaView.kt b/vector/src/main/java/im/vector/riotx/core/ui/views/NotificationAreaView.kt index 4bf5c818e5..f44f689f4c 100644 --- a/vector/src/main/java/im/vector/riotx/core/ui/views/NotificationAreaView.kt +++ b/vector/src/main/java/im/vector/riotx/core/ui/views/NotificationAreaView.kt @@ -18,18 +18,11 @@ package im.vector.riotx.core.ui.views import android.content.Context import android.graphics.Color -import android.text.SpannableString -import android.text.TextPaint -import android.text.method.LinkMovementMethod -import android.text.style.ClickableSpan import android.util.AttributeSet import android.view.View import android.widget.RelativeLayout -import androidx.core.content.ContextCompat -import im.vector.matrix.android.api.failure.MatrixError import im.vector.matrix.android.api.session.events.model.Event import im.vector.riotx.R -import im.vector.riotx.core.error.ResourceLimitErrorFormatter import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.features.themes.ThemeUtils import kotlinx.android.synthetic.main.view_notification_area.view.* diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index ca86a3fbe4..97f8469357 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -56,10 +56,8 @@ import com.airbnb.mvrx.Success import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState -import com.google.android.material.checkbox.MaterialCheckBox import com.google.android.material.snackbar.Snackbar import com.google.android.material.textfield.TextInputEditText -import com.google.android.material.textfield.TextInputLayout import com.jakewharton.rxbinding3.widget.textChanges import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.permalinks.PermalinkFactory @@ -88,6 +86,7 @@ import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt import im.vector.riotx.R +import im.vector.riotx.core.dialogs.ConfirmationDialogBuilder import im.vector.riotx.core.dialogs.withColoredButton import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer import im.vector.riotx.core.extensions.cleanup @@ -862,28 +861,17 @@ class RoomDetailFragment @Inject constructor( } private fun promptConfirmationToRedactEvent(action: EventSharedAction.Redact) { - val layout = requireActivity().layoutInflater.inflate(R.layout.dialog_delete_event, null) - val reasonCheckBox = layout.findViewById(R.id.deleteEventReasonCheck) - val reasonTextInputLayout = layout.findViewById(R.id.deleteEventReasonTextInputLayout) - val reasonInput = layout.findViewById(R.id.deleteEventReasonInput) - - reasonCheckBox.isVisible = action.askForReason - reasonTextInputLayout.isVisible = action.askForReason - - reasonCheckBox.setOnCheckedChangeListener { _, isChecked -> reasonTextInputLayout.isEnabled = isChecked } - - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.delete_event_dialog_title) - .setView(layout) - .setPositiveButton(R.string.remove) { _, _ -> - val reason = reasonInput.text.toString() - .takeIf { action.askForReason } - ?.takeIf { reasonCheckBox.isChecked } - ?.takeIf { it.isNotBlank() } + ConfirmationDialogBuilder + .show( + activity = requireActivity(), + askForReason = action.askForReason, + confirmationRes = R.string.delete_event_dialog_content, + positiveRes = R.string.remove, + reasonHintRes = R.string.delete_event_dialog_reason_hint, + titleRes = R.string.delete_event_dialog_title + ) { reason -> roomDetailViewModel.handle(RoomDetailAction.RedactAction(action.eventId, reason)) } - .setNegativeButton(R.string.cancel, null) - .show() } private fun displayRoomDetailActionFailure(result: RoomDetailViewEvents.ActionFailure) { diff --git a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt index 6c5ae1d325..e4034b389a 100644 --- a/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -21,7 +21,6 @@ import android.os.Bundle import android.os.Parcelable import android.view.MenuItem import android.view.View -import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import com.airbnb.mvrx.Fail @@ -35,6 +34,7 @@ import im.vector.matrix.android.api.util.MatrixItem import im.vector.riotx.R import im.vector.riotx.core.animations.AppBarStateChangeListener import im.vector.riotx.core.animations.MatrixItemAppBarStateChangeListener +import im.vector.riotx.core.dialogs.ConfirmationDialogBuilder import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith import im.vector.riotx.core.extensions.exhaustive @@ -221,8 +221,31 @@ class RoomMemberProfileFragment @Inject constructor( // RoomMemberProfileController.Callback - override fun onIgnoreClicked() { - viewModel.handle(RoomMemberProfileAction.IgnoreUser) + override fun onIgnoreClicked() = withState(viewModel) { state -> + val isIgnored = state.isIgnored() ?: false + val titleRes: Int + val positiveButtonRes: Int + val confirmationRes: Int + if (isIgnored) { + confirmationRes = R.string.room_participants_action_unignore_prompt_msg + titleRes = R.string.room_participants_action_unignore_title + positiveButtonRes = R.string.room_participants_action_unignore + } else { + confirmationRes = R.string.room_participants_action_ignore_prompt_msg + titleRes = R.string.room_participants_action_ignore_title + positiveButtonRes = R.string.room_participants_action_ignore + } + ConfirmationDialogBuilder + .show( + activity = requireActivity(), + askForReason = false, + confirmationRes = confirmationRes, + positiveRes = positiveButtonRes, + reasonHintRes = 0, + titleRes = titleRes + ) { + viewModel.handle(RoomMemberProfileAction.IgnoreUser) + } } override fun onTapVerify() { @@ -260,47 +283,57 @@ class RoomMemberProfileFragment @Inject constructor( } override fun onKickClicked() { - val layout = layoutInflater.inflate(R.layout.dialog_base_edit_text, null) - val input = layout.findViewById(R.id.editText) - input.setHint(R.string.reason_hint) - AlertDialog.Builder(requireActivity()) - .setTitle(resources.getQuantityString(R.plurals.room_participants_kick_prompt_msg, 1)) - .setView(layout) - .setPositiveButton(R.string.room_participants_action_kick) { _, _ -> - viewModel.handle(RoomMemberProfileAction.KickUser(input.text.toString())) + ConfirmationDialogBuilder + .show( + activity = requireActivity(), + askForReason = true, + confirmationRes = R.string.room_participants_kick_prompt_msg, + positiveRes = R.string.room_participants_action_kick, + reasonHintRes = R.string.room_participants_kick_reason, + titleRes = R.string.room_participants_kick_title + ) { reason -> + viewModel.handle(RoomMemberProfileAction.KickUser(reason)) } - .setNegativeButton(R.string.cancel, null) - .show() } override fun onBanClicked(isUserBanned: Boolean) { - val layout = layoutInflater.inflate(R.layout.dialog_base_edit_text, null) - val input = layout.findViewById(R.id.editText) - input.setHint(R.string.reason_hint) - val (titleRes, positiveButtonRes) = if (isUserBanned) { - input.isVisible = false - Pair(R.string.room_participants_unban_prompt_msg, R.string.room_participants_action_unban) + val titleRes: Int + val positiveButtonRes: Int + val confirmationRes: Int + if (isUserBanned) { + confirmationRes = R.string.room_participants_unban_prompt_msg + titleRes = R.string.room_participants_unban_title + positiveButtonRes = R.string.room_participants_action_unban } else { - Pair(R.string.room_participants_ban_prompt_msg, R.string.room_participants_action_ban) + confirmationRes = R.string.room_participants_ban_prompt_msg + titleRes = R.string.room_participants_ban_title + positiveButtonRes = R.string.room_participants_action_ban } - AlertDialog.Builder(requireActivity()) - .setTitle(titleRes) - .setView(layout) - .setPositiveButton(positiveButtonRes) { _, _ -> - viewModel.handle(RoomMemberProfileAction.BanUser(input.text.toString())) + ConfirmationDialogBuilder + .show( + activity = requireActivity(), + askForReason = !isUserBanned, + confirmationRes = confirmationRes, + positiveRes = positiveButtonRes, + reasonHintRes = R.string.room_participants_ban_reason, + titleRes = titleRes + ) { reason -> + viewModel.handle(RoomMemberProfileAction.BanUser(reason)) } - .setNegativeButton(R.string.cancel, null) - .show() } override fun onCancelInviteClicked() { - AlertDialog.Builder(requireActivity()) - .setTitle(resources.getString(R.string.room_participants_action_cancel_invite_prompt_msg)) - .setPositiveButton(R.string.room_participants_action_cancel_invite) { _, _ -> + ConfirmationDialogBuilder + .show( + activity = requireActivity(), + askForReason = false, + confirmationRes = R.string.room_participants_action_cancel_invite_prompt_msg, + positiveRes = R.string.room_participants_action_cancel_invite, + reasonHintRes = 0, + titleRes = R.string.room_participants_action_cancel_invite_title + ) { viewModel.handle(RoomMemberProfileAction.KickUser(null)) } - .setNegativeButton(R.string.cancel, null) - .show() } override fun onInviteClicked() { diff --git a/vector/src/main/res/layout/dialog_delete_event.xml b/vector/src/main/res/layout/dialog_confirmation_with_reason.xml similarity index 74% rename from vector/src/main/res/layout/dialog_delete_event.xml rename to vector/src/main/res/layout/dialog_confirmation_with_reason.xml index 08b0131f6a..859eda2010 100644 --- a/vector/src/main/res/layout/dialog_delete_event.xml +++ b/vector/src/main/res/layout/dialog_confirmation_with_reason.xml @@ -1,6 +1,7 @@ + app:layout_constraintTop_toBottomOf="@+id/dialogConfirmationText" /> + app:layout_constraintTop_toBottomOf="@+id/dialogReasonCheck"> diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d9cc8cf9f4..3a061a5550 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -474,22 +474,30 @@ Reset to normal user Make moderator Make admin - Hide all messages from this user - Show all messages from this user - Show all messages from this user?\n\nNote that this action will restart the app and it may take some time. User ID, Name or email Mention Show Session List You will not be able to undo this change as you are promoting the user to have the same power level as yourself.\nAre you sure? - Are you sure you want to cancel the invite for this user? - - Are you sure that you want to kick this user from this chat? - Are you sure that you want to kick these users from this chat? - - Are you sure that you want to ban this user from this chat? - Are you sure that you want to unban this user from this chat? + Ignore user + Ignoring this user will remove their messages from rooms you share.\n\nYou can reverse this action at any time in the general settings. + Ignore + + Unignore user + Unignoring this user will show all messages from them again. + Unignore + + Cancel invite + Are you sure you want to cancel the invite for this user? + Kick user + Reason to kick + kicking user will remove them from this room.\n\nTo prevent them from joining again, you should ban them instead. + Ban user + Reason to ban + Unban user + Banning user will kick them from this room and prevent them from joining again. + Unbanning user will allow them to join the room again. Reason @@ -2433,6 +2441,6 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming Alternatively, you can enter any other identity server URL Enter the URL of an identity server Submit - Edit power level + Set role