Room member: continue to branch admin/moderator actions
This commit is contained in:
parent
ad8ed37ff6
commit
a1fd35aa67
|
@ -22,6 +22,9 @@ import im.vector.riotx.core.platform.VectorViewModelAction
|
|||
sealed class RoomMemberProfileAction : VectorViewModelAction {
|
||||
object RetryFetchingInfo : RoomMemberProfileAction()
|
||||
object IgnoreUser : RoomMemberProfileAction()
|
||||
data class BanUser(val reason: String?) : RoomMemberProfileAction()
|
||||
data class KickUser(val reason: String?) : RoomMemberProfileAction()
|
||||
object InviteUser : RoomMemberProfileAction()
|
||||
object VerifyUser : RoomMemberProfileAction()
|
||||
object ShareRoomMemberProfile : RoomMemberProfileAction()
|
||||
data class SetPowerLevel(val previousValue: Int, val newValue: Int, val askForValidation: Boolean) : RoomMemberProfileAction()
|
||||
|
|
|
@ -19,8 +19,9 @@ package im.vector.riotx.features.roommemberprofile
|
|||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.powerlevels.Role
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import im.vector.matrix.android.api.session.room.powerlevels.Role
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.profiles.buildProfileAction
|
||||
import im.vector.riotx.core.epoxy.profiles.buildProfileSection
|
||||
|
@ -47,6 +48,10 @@ class RoomMemberProfileController @Inject constructor(
|
|||
fun onJumpToReadReceiptClicked()
|
||||
fun onMentionClicked()
|
||||
fun onSetPowerLevel(userRole: Role)
|
||||
fun onKickClicked()
|
||||
fun onBanClicked(isUserBanned: Boolean)
|
||||
fun onCancelInviteClicked()
|
||||
fun onInviteClicked()
|
||||
}
|
||||
|
||||
override fun buildModels(data: RoomMemberProfileViewState?) {
|
||||
|
@ -87,11 +92,11 @@ class RoomMemberProfileController @Inject constructor(
|
|||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
val userPowerLevel = powerLevelsHelper.getUserRole(state.userId)
|
||||
val myPowerLevel = powerLevelsHelper.getUserRole(session.myUserId)
|
||||
if ((!state.isMine && myPowerLevel <= userPowerLevel)
|
||||
|| myPowerLevel != Role.Admin) {
|
||||
if (myPowerLevel < Role.Moderator || (!state.isMine && myPowerLevel <= userPowerLevel)) {
|
||||
return
|
||||
}
|
||||
buildProfileSection("Admin Actions")
|
||||
val membership = state.asyncMembership() ?: return
|
||||
buildProfileSection(stringProvider.getString(R.string.room_profile_section_admin))
|
||||
buildProfileAction(
|
||||
id = "set_power_level",
|
||||
editable = false,
|
||||
|
@ -99,11 +104,46 @@ class RoomMemberProfileController @Inject constructor(
|
|||
dividerColor = dividerColor,
|
||||
action = { callback?.onSetPowerLevel(userPowerLevel) }
|
||||
)
|
||||
|
||||
if (membership == Membership.JOIN) {
|
||||
buildProfileAction(
|
||||
id = "kick",
|
||||
editable = false,
|
||||
destructive = true,
|
||||
title = stringProvider.getString(R.string.room_participants_action_kick),
|
||||
dividerColor = dividerColor,
|
||||
action = { callback?.onKickClicked() }
|
||||
)
|
||||
} else if (membership == Membership.INVITE) {
|
||||
buildProfileAction(
|
||||
id = "cancel_invite",
|
||||
title = stringProvider.getString(R.string.room_participants_action_cancel_invite),
|
||||
dividerColor = dividerColor,
|
||||
destructive = true,
|
||||
editable = false,
|
||||
action = { callback?.onCancelInviteClicked() }
|
||||
)
|
||||
}
|
||||
val banActionTitle = if (membership == Membership.BAN) {
|
||||
stringProvider.getString(R.string.room_participants_action_unban)
|
||||
} else {
|
||||
stringProvider.getString(R.string.room_participants_action_ban)
|
||||
}
|
||||
buildProfileAction(
|
||||
id = "ban",
|
||||
editable = false,
|
||||
destructive = true,
|
||||
title = banActionTitle,
|
||||
dividerColor = dividerColor,
|
||||
action = { callback?.onBanClicked(membership == Membership.BAN) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildMoreSection(state: RoomMemberProfileViewState) {
|
||||
// More
|
||||
if (!state.isMine) {
|
||||
val membership = state.asyncMembership() ?: return
|
||||
|
||||
buildProfileSection(stringProvider.getString(R.string.room_profile_section_more))
|
||||
buildProfileAction(
|
||||
id = "read_receipt",
|
||||
|
@ -123,6 +163,17 @@ class RoomMemberProfileController @Inject constructor(
|
|||
divider = ignoreActionTitle != null,
|
||||
action = { callback?.onMentionClicked() }
|
||||
)
|
||||
if (membership == Membership.LEAVE || membership == Membership.KNOCK) {
|
||||
buildProfileAction(
|
||||
id = "invite",
|
||||
title = stringProvider.getString(R.string.room_participants_action_invite),
|
||||
dividerColor = dividerColor,
|
||||
destructive = false,
|
||||
editable = false,
|
||||
divider = ignoreActionTitle != null,
|
||||
action = { callback?.onInviteClicked() }
|
||||
)
|
||||
}
|
||||
if (ignoreActionTitle != null) {
|
||||
buildProfileAction(
|
||||
id = "ignore",
|
||||
|
|
|
@ -21,6 +21,7 @@ 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
|
||||
|
@ -98,11 +99,14 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
when (it) {
|
||||
is RoomMemberProfileViewEvents.Loading -> showLoading(it.message)
|
||||
is RoomMemberProfileViewEvents.Failure -> showFailure(it.throwable)
|
||||
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit
|
||||
is RoomMemberProfileViewEvents.StartVerification -> handleStartVerification(it)
|
||||
is RoomMemberProfileViewEvents.ShareRoomMemberProfile -> handleShareRoomMemberProfile(it.permalink)
|
||||
is RoomMemberProfileViewEvents.OnSetPowerLevelSuccess -> Unit
|
||||
is RoomMemberProfileViewEvents.ShowPowerLevelValidation -> handleShowPowerLevelAdminWarning(it)
|
||||
is RoomMemberProfileViewEvents.OnKickActionSuccess -> Unit
|
||||
is RoomMemberProfileViewEvents.OnSetPowerLevelSuccess -> Unit
|
||||
is RoomMemberProfileViewEvents.OnBanActionSuccess -> Unit
|
||||
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit
|
||||
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
|
@ -254,4 +258,52 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
viewModel.handle(RoomMemberProfileAction.SetPowerLevel(userRole.value, newPowerLevel, true))
|
||||
}
|
||||
}
|
||||
|
||||
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()))
|
||||
}
|
||||
.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)
|
||||
} else {
|
||||
Pair(R.string.room_participants_ban_prompt_msg, R.string.room_participants_action_ban)
|
||||
}
|
||||
AlertDialog.Builder(requireActivity())
|
||||
.setTitle(titleRes)
|
||||
.setView(layout)
|
||||
.setPositiveButton(positiveButtonRes) { _, _ ->
|
||||
viewModel.handle(RoomMemberProfileAction.BanUser(input.text.toString()))
|
||||
}
|
||||
.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) { _, _ ->
|
||||
viewModel.handle(RoomMemberProfileAction.KickUser(null))
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onInviteClicked() {
|
||||
viewModel.handle(RoomMemberProfileAction.InviteUser)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents {
|
|||
|
||||
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
|
||||
object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents()
|
||||
object OnInviteActionSuccess : RoomMemberProfileViewEvents()
|
||||
object OnKickActionSuccess : RoomMemberProfileViewEvents()
|
||||
object OnBanActionSuccess : RoomMemberProfileViewEvents()
|
||||
data class ShowPowerLevelValidation(val currentValue: Int, val newValue: Int) : RoomMemberProfileViewEvents()
|
||||
|
||||
data class StartVerification(
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
package im.vector.riotx.features.roommemberprofile
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
|
@ -35,6 +37,7 @@ import im.vector.matrix.android.api.session.events.model.toModel
|
|||
import im.vector.matrix.android.api.session.profile.ProfileService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.members.roomMemberQueryParams
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
|
||||
|
@ -142,6 +145,9 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
is RoomMemberProfileAction.VerifyUser -> prepareVerification()
|
||||
is RoomMemberProfileAction.ShareRoomMemberProfile -> handleShareRoomMemberProfile()
|
||||
is RoomMemberProfileAction.SetPowerLevel -> handleSetPowerLevel(action)
|
||||
is RoomMemberProfileAction.BanUser -> handleBanAction(action)
|
||||
is RoomMemberProfileAction.KickUser -> handleKickAction(action)
|
||||
RoomMemberProfileAction.InviteUser -> handleInviteAction()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,15 +188,79 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleInviteAction() {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
||||
awaitCallback<Unit> {
|
||||
room.invite(initialState.userId, callback = it)
|
||||
}
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.OnInviteActionSuccess)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleKickAction(action: RoomMemberProfileAction.KickUser) {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
||||
awaitCallback<Unit> {
|
||||
room.kick(initialState.userId, action.reason, it)
|
||||
}
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.OnKickActionSuccess)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBanAction(action: RoomMemberProfileAction.BanUser) = withState { state ->
|
||||
if (room == null) {
|
||||
return@withState
|
||||
}
|
||||
val membership = state.asyncMembership() ?: return@withState
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
||||
awaitCallback<Unit> {
|
||||
if (membership == Membership.BAN) {
|
||||
room.unban(initialState.userId, action.reason, it)
|
||||
} else {
|
||||
room.ban(initialState.userId, action.reason, it)
|
||||
}
|
||||
}
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.OnBanActionSuccess)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomMemberSummary(room: Room) {
|
||||
val queryParams = roomMemberQueryParams {
|
||||
this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE)
|
||||
}
|
||||
room.rx().liveRoomMembers(queryParams)
|
||||
.map { it.firstOrNull()?.toMatrixItem().toOptional() }
|
||||
.map { it.firstOrNull().toOptional() }
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(userMatrixItem = it)
|
||||
when (it) {
|
||||
is Loading -> copy(userMatrixItem = Loading(), asyncMembership = Loading())
|
||||
is Success -> copy(
|
||||
userMatrixItem = Success(it().toMatrixItem()),
|
||||
asyncMembership = Success(it().membership)
|
||||
)
|
||||
is Fail -> copy(userMatrixItem = Fail(it.error), asyncMembership = Fail(it.error))
|
||||
is Uninitialized -> this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@ import com.airbnb.mvrx.Async
|
|||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import java.lang.reflect.Member
|
||||
|
||||
data class RoomMemberProfileViewState(
|
||||
val userId: String,
|
||||
|
@ -36,7 +38,8 @@ data class RoomMemberProfileViewState(
|
|||
val userMatrixItem: Async<MatrixItem> = Uninitialized,
|
||||
val userMXCrossSigningInfo: MXCrossSigningInfo? = null,
|
||||
val allDevicesAreTrusted: Boolean = false,
|
||||
val allDevicesAreCrossSignedTrusted: Boolean = false
|
||||
val allDevicesAreCrossSignedTrusted: Boolean = false,
|
||||
val asyncMembership: Async<Membership> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomMemberProfileArgs) : this(roomId = args.roomId, userId = args.userId)
|
||||
|
|
|
@ -134,7 +134,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
|
|||
val inflater = requireActivity().layoutInflater
|
||||
val layout = inflater.inflate(R.layout.dialog_base_edit_text, null)
|
||||
|
||||
val input = layout.findViewById<EditText>(R.id.edit_text)
|
||||
val input = layout.findViewById<EditText>(R.id.editText)
|
||||
input.setText(deviceInfo.displayName)
|
||||
|
||||
AlertDialog.Builder(requireActivity())
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
android:paddingRight="?dialogPreferredPadding">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:id="@+id/editText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text">
|
||||
|
|
|
@ -465,6 +465,7 @@
|
|||
<string name="room_participants_header_devices">SESSIONS</string>
|
||||
|
||||
<string name="room_participants_action_invite">Invite</string>
|
||||
<string name="room_participants_action_cancel_invite">Cancel invite</string>
|
||||
<string name="room_participants_action_leave">Leave this room</string>
|
||||
<string name="room_participants_action_remove">Remove from this room</string>
|
||||
<string name="room_participants_action_ban">Ban</string>
|
||||
|
@ -481,11 +482,15 @@
|
|||
<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="reason_hint">Reason</string>
|
||||
|
||||
<!--
|
||||
|
@ -2068,6 +2073,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
|
|||
<string name="room_profile_section_security">Security</string>
|
||||
<string name="room_profile_section_security_learn_more">Learn more</string>
|
||||
<string name="room_profile_section_more">More</string>
|
||||
<string name="room_profile_section_admin">Admin Actions</string>
|
||||
<string name="room_profile_section_more_settings">Room settings</string>
|
||||
<string name="room_profile_section_more_notifications">Notifications</string>
|
||||
<plurals name="room_profile_section_more_member_list">
|
||||
|
|
Loading…
Reference in New Issue