Power level: use confirmation dialog

This commit is contained in:
ganfra 2020-06-08 16:33:56 +02:00
parent d2dba1826d
commit a8ae4ddde8
6 changed files with 164 additions and 80 deletions

View File

@ -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()
}
}

View File

@ -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.*

View File

@ -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<MaterialCheckBox>(R.id.deleteEventReasonCheck)
val reasonTextInputLayout = layout.findViewById<TextInputLayout>(R.id.deleteEventReasonTextInputLayout)
val reasonInput = layout.findViewById<TextInputEditText>(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) {

View File

@ -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<TextView>(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<TextView>(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() {

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -12,36 +13,36 @@
android:paddingBottom="12dp">
<TextView
android:id="@+id/deleteEventConfirmationText"
android:id="@+id/dialogConfirmationText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/delete_event_dialog_content"
tools:text="@string/delete_event_dialog_content"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/deleteEventReasonCheck"
android:id="@+id/dialogReasonCheck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="true"
android:text="@string/delete_event_dialog_reason_checkbox"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/deleteEventConfirmationText" />
app:layout_constraintTop_toBottomOf="@+id/dialogConfirmationText" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/deleteEventReasonTextInputLayout"
android:id="@+id/dialogReasonTextInputLayout"
style="@style/VectorTextInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/delete_event_dialog_reason_hint"
tools:hint="@string/delete_event_dialog_reason_hint"
app:counterEnabled="true"
app:counterMaxLength="240"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/deleteEventReasonCheck">
app:layout_constraintTop_toBottomOf="@+id/dialogReasonCheck">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/deleteEventReasonInput"
android:id="@+id/dialogReasonInput"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@ -474,22 +474,30 @@
<string name="room_participants_action_set_default_power_level">Reset to normal user</string>
<string name="room_participants_action_set_moderator">Make moderator</string>
<string name="room_participants_action_set_admin">Make admin</string>
<string name="room_participants_action_ignore">Hide all messages from this user</string>
<string name="room_participants_action_unignore">Show all messages from this user</string>
<string name="room_participants_action_unignore_prompt">Show all messages from this user?\n\nNote that this action will restart the app and it may take some time.</string>
<string name="room_participants_invite_search_another_user">User ID, Name or email</string>
<string name="room_participants_action_mention">Mention</string>
<string name="room_participants_action_devices_list">Show Session List</string>
<string name="room_participants_power_level_prompt">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?</string>
<string name="room_participants_action_cancel_invite_prompt_msg">Are you sure you want to cancel the invite for this user?</string>
<plurals name="room_participants_kick_prompt_msg">
<item quantity="one">Are you sure that you want to kick this user from this chat?</item>
<item quantity="other">Are you sure that you want to kick these users from this chat?</item>
</plurals>
<string name="room_participants_ban_prompt_msg">Are you sure that you want to ban this user from this chat?</string>
<string name="room_participants_unban_prompt_msg">Are you sure that you want to unban this user from this chat?</string>
<string name="room_participants_action_ignore_title">Ignore user</string>
<string name="room_participants_action_ignore_prompt_msg">Ignoring this user will remove their messages from rooms you share.\n\nYou can reverse this action at any time in the general settings.</string>
<string name="room_participants_action_ignore">Ignore</string>
<string name="room_participants_action_unignore_title">Unignore user</string>
<string name="room_participants_action_unignore_prompt_msg">Unignoring this user will show all messages from them again.</string>
<string name="room_participants_action_unignore">Unignore</string>
<string name="room_participants_action_cancel_invite_title">Cancel invite</string>
<string name="room_participants_action_cancel_invite_prompt_msg">Are you sure you want to cancel the invite for this user?</string>
<string name="room_participants_kick_title">Kick user</string>
<string name="room_participants_kick_reason">Reason to kick</string>
<string name="room_participants_kick_prompt_msg">kicking user will remove them from this room.\n\nTo prevent them from joining again, you should ban them instead.</string>
<string name="room_participants_ban_title">Ban user</string>
<string name="room_participants_ban_reason">Reason to ban</string>
<string name="room_participants_unban_title">Unban user</string>
<string name="room_participants_ban_prompt_msg">Banning user will kick them from this room and prevent them from joining again.</string>
<string name="room_participants_unban_prompt_msg">Unbanning user will allow them to join the room again.</string>
<string name="reason_hint">Reason</string>
@ -2433,6 +2441,6 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
<string name="identity_server_set_alternative_notice">Alternatively, you can enter any other identity server URL</string>
<string name="identity_server_set_alternative_notice_no_default">Enter the URL of an identity server</string>
<string name="identity_server_set_alternative_submit">Submit</string>
<string name="power_level_edit_title">Edit power level</string>
<string name="power_level_edit_title">Set role</string>
</resources>