mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
PowerLevel : clean after Benoit's review
This commit is contained in:
parent
bf5ad2cf18
commit
60b91d4d50
@ -43,20 +43,19 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @return the power level
|
||||
*/
|
||||
fun getUserRole(userId: String): Role {
|
||||
return getUserPowerLevelValue(userId).let {
|
||||
Role.fromValue(it, powerLevelsContent.eventsDefault)
|
||||
}
|
||||
val value = getUserPowerLevelValue(userId)
|
||||
return Role.fromValue(value, powerLevelsContent.eventsDefault)
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if an user can send an event of a certain type
|
||||
*
|
||||
* @param userId the id of the user to check for.
|
||||
* @param isState true if the event is a state event (ie. state key is not null)
|
||||
* @param eventType the event type to check for
|
||||
* @param userId the user id
|
||||
* @return true if the user can send this type of event
|
||||
*/
|
||||
fun isAllowedToSend(isState: Boolean, eventType: String?, userId: String): Boolean {
|
||||
fun isUserAllowedToSend(userId: String, isState: Boolean, eventType: String?): Boolean {
|
||||
return if (userId.isNotEmpty()) {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
val minimumPowerLevel = powerLevelsContent.events[eventType]
|
||||
@ -69,22 +68,42 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
} else false
|
||||
}
|
||||
|
||||
fun canInvite(userId: String): Boolean {
|
||||
/**
|
||||
* Check if the user have the necessary power level to invite
|
||||
* @param userId the id of the user to check for.
|
||||
* @return true if able to invite
|
||||
*/
|
||||
fun isUserAbleToInvite(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.invite
|
||||
}
|
||||
|
||||
fun canBan(userId: String): Boolean {
|
||||
/**
|
||||
* Check if the user have the necessary power level to ban
|
||||
* @param userId the id of the user to check for.
|
||||
* @return true if able to ban
|
||||
*/
|
||||
fun isUserAbleToBan(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.ban
|
||||
}
|
||||
|
||||
fun canKick(userId: String): Boolean {
|
||||
/**
|
||||
* Check if the user have the necessary power level to kick
|
||||
* @param userId the id of the user to check for.
|
||||
* @return true if able to kick
|
||||
*/
|
||||
fun isUserAbleToKick(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.kick
|
||||
}
|
||||
|
||||
fun canRedact(userId: String): Boolean {
|
||||
/**
|
||||
* Check if the user have the necessary power level to redact
|
||||
* @param userId the id of the user to check for.
|
||||
* @return true if able to redact
|
||||
*/
|
||||
fun isUserAbleToRedact(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.redact
|
||||
}
|
||||
|
@ -34,10 +34,11 @@ sealed class Role(open val value: Int, @StringRes val res: Int) : Comparable<Rol
|
||||
|
||||
fun fromValue(value: Int, default: Int): Role {
|
||||
return when (value) {
|
||||
default, Default.value -> Default
|
||||
Moderator.value -> Moderator
|
||||
Admin.value -> Admin
|
||||
else -> Custom(value)
|
||||
default,
|
||||
Default.value -> Default
|
||||
Moderator.value -> Moderator
|
||||
Admin.value -> Admin
|
||||
else -> Custom(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ internal interface RoomAPI {
|
||||
* @param userIdAndReason the banned user object (userId and reason for ban)
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/ban")
|
||||
fun ban(@Path("roomId") roomId: String?, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
fun ban(@Path("roomId") roomId: String, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
|
||||
/**
|
||||
* unban a user from the given room.
|
||||
@ -260,7 +260,7 @@ internal interface RoomAPI {
|
||||
* @param userIdAndReason the unbanned user object (userId and reason for unban)
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/unban")
|
||||
fun unban(@Path("roomId") roomId: String?, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
fun unban(@Path("roomId") roomId: String, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
|
||||
/**
|
||||
* Kick a user from the given room.
|
||||
@ -269,7 +269,7 @@ internal interface RoomAPI {
|
||||
* @param userIdAndReason the kicked user object (userId and reason for kicking)
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/kick")
|
||||
fun kick(@Path("roomId") roomId: String?, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
fun kick(@Path("roomId") roomId: String, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
|
||||
/**
|
||||
* Strips all information out of an event which isn't critical to the integrity of the server-side representation of the room.
|
||||
|
@ -198,6 +198,6 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||
stateKey = QueryStringValue.NoCondition
|
||||
)
|
||||
val powerLevelsContent = powerLevelsEvent?.content?.toModel<PowerLevelsContent>() ?: return false
|
||||
return PowerLevelsHelper(powerLevelsContent).isAllowedToSend(true, null, userId)
|
||||
return PowerLevelsHelper(powerLevelsContent).isUserAllowedToSend(userId, true, null)
|
||||
}
|
||||
}
|
||||
|
@ -95,8 +95,11 @@
|
||||
<string name="power_level_custom">Custom (%1$d)</string>
|
||||
<string name="power_level_custom_no_value">Custom</string>
|
||||
|
||||
<!-- parameter will be a comma separated list of values of notice_power_level_diff -->
|
||||
<string name="notice_power_level_changed_by_you">You changed the power level of %1$s.</string>
|
||||
<!-- parameter will be a comma separated list of values of notice_power_level_diff -->
|
||||
<string name="notice_power_level_changed">%1$s changed the power level of %2$s.</string>
|
||||
<!-- First parameter will be a userId or display name, the two last ones will be value of power_level_* -->
|
||||
<string name="notice_power_level_diff">%1$s from %2$s to %3$s</string>
|
||||
|
||||
<string name="notice_crypto_unable_to_decrypt">** Unable to decrypt: %s **</string>
|
||||
|
@ -18,11 +18,15 @@ package im.vector.riotx.core.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.text.method.LinkMovementMethod
|
||||
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.*
|
||||
@ -61,10 +65,11 @@ class NotificationAreaView @JvmOverloads constructor(
|
||||
cleanUp()
|
||||
state = newState
|
||||
when (newState) {
|
||||
is State.Default -> renderDefault()
|
||||
is State.Hidden -> renderHidden()
|
||||
is State.NoPermissionToPost -> renderNoPermissionToPost()
|
||||
is State.Tombstone -> renderTombstone(newState)
|
||||
is State.Default -> renderDefault()
|
||||
is State.Hidden -> renderHidden()
|
||||
is State.NoPermissionToPost -> renderNoPermissionToPost()
|
||||
is State.Tombstone -> renderTombstone(newState)
|
||||
is State.ResourceLimitExceededError -> renderResourceLimitExceededError(newState)
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +98,26 @@ class NotificationAreaView @JvmOverloads constructor(
|
||||
roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||
}
|
||||
|
||||
private fun renderResourceLimitExceededError(state: State.ResourceLimitExceededError) {
|
||||
visibility = View.VISIBLE
|
||||
val resourceLimitErrorFormatter = ResourceLimitErrorFormatter(context)
|
||||
val formatterMode: ResourceLimitErrorFormatter.Mode
|
||||
val backgroundColor: Int
|
||||
if (state.isSoft) {
|
||||
backgroundColor = R.color.soft_resource_limit_exceeded
|
||||
formatterMode = ResourceLimitErrorFormatter.Mode.Soft
|
||||
} else {
|
||||
backgroundColor = R.color.hard_resource_limit_exceeded
|
||||
formatterMode = ResourceLimitErrorFormatter.Mode.Hard
|
||||
}
|
||||
val message = resourceLimitErrorFormatter.format(state.matrixError, formatterMode, clickable = true)
|
||||
roomNotificationMessage.setTextColor(Color.WHITE)
|
||||
roomNotificationMessage.text = message
|
||||
roomNotificationMessage.movementMethod = LinkMovementMethod.getInstance()
|
||||
roomNotificationMessage.setLinkTextColor(Color.WHITE)
|
||||
setBackgroundColor(ContextCompat.getColor(context, backgroundColor))
|
||||
}
|
||||
|
||||
private fun renderTombstone(state: State.Tombstone) {
|
||||
visibility = View.VISIBLE
|
||||
roomNotificationIcon.setImageResource(R.drawable.error)
|
||||
@ -129,13 +154,16 @@ class NotificationAreaView @JvmOverloads constructor(
|
||||
object Default : State()
|
||||
|
||||
// User can't post messages to room because his power level doesn't allow it.
|
||||
object NoPermissionToPost: State()
|
||||
object NoPermissionToPost : State()
|
||||
|
||||
// View will be Gone
|
||||
object Hidden : State()
|
||||
|
||||
// The room is dead
|
||||
data class Tombstone(val tombstoneEvent: Event) : State()
|
||||
|
||||
// Resource limit exceeded error will be displayed (only hard for the moment)
|
||||
data class ResourceLimitExceededError(val isSoft: Boolean, val matrixError: MatrixError) : State()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,8 +72,8 @@ import im.vector.riotx.features.crypto.verification.SupportedVerificationMethods
|
||||
import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator
|
||||
import im.vector.riotx.features.home.room.detail.sticker.StickerPickerActionHandler
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
||||
import im.vector.riotx.features.powerlevel.PowerLevelsObservableFactory
|
||||
import im.vector.riotx.features.home.room.typing.TypingHelper
|
||||
import im.vector.riotx.features.powerlevel.PowerLevelsObservableFactory
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
@ -176,11 +176,12 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||
private fun observePowerLevel() {
|
||||
PowerLevelsObservableFactory(room).createObservable()
|
||||
.subscribe {
|
||||
val canSendMessage = PowerLevelsHelper(it).isAllowedToSend(false, EventType.MESSAGE, session.myUserId)
|
||||
val canSendMessage = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
setState {
|
||||
copy(canSendMessage = canSendMessage)
|
||||
}
|
||||
}.disposeOnClear()
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeActiveRoomWidgets() {
|
||||
|
@ -109,9 +109,9 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
|
||||
PowerLevelsObservableFactory(room).createObservable()
|
||||
.subscribe {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
val canReact = powerLevelsHelper.isAllowedToSend(false, EventType.REACTION, session.myUserId)
|
||||
val canRedact = powerLevelsHelper.canRedact(session.myUserId)
|
||||
val canSendMessage = powerLevelsHelper.isAllowedToSend(false, EventType.MESSAGE, session.myUserId)
|
||||
val canReact = powerLevelsHelper.isUserAllowedToSend(session.myUserId, false, EventType.REACTION)
|
||||
val canRedact = powerLevelsHelper.isUserAbleToRedact(session.myUserId)
|
||||
val canSendMessage = powerLevelsHelper.isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
val permissions = ActionPermissions(canSendMessage = canSendMessage, canRedact = canRedact, canReact = canReact)
|
||||
setState {
|
||||
copy(actionPermissions = permissions)
|
||||
|
@ -22,7 +22,7 @@ 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 BanOrUnbanUser(val reason: String?) : RoomMemberProfileAction()
|
||||
data class KickUser(val reason: String?) : RoomMemberProfileAction()
|
||||
object InviteUser : RoomMemberProfileAction()
|
||||
object VerifyUser : RoomMemberProfileAction()
|
||||
|
@ -325,7 +325,7 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||
reasonHintRes = R.string.room_participants_ban_reason,
|
||||
titleRes = titleRes
|
||||
) { reason ->
|
||||
viewModel.handle(RoomMemberProfileAction.BanUser(reason))
|
||||
viewModel.handle(RoomMemberProfileAction.BanOrUnbanUser(reason))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ 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.BanOrUnbanUser -> handleBanOrUnbanAction(action)
|
||||
is RoomMemberProfileAction.KickUser -> handleKickAction(action)
|
||||
RoomMemberProfileAction.InviteUser -> handleInviteAction()
|
||||
}
|
||||
@ -223,7 +223,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBanAction(action: RoomMemberProfileAction.BanUser) = withState { state ->
|
||||
private fun handleBanOrUnbanAction(action: RoomMemberProfileAction.BanOrUnbanUser) = withState { state ->
|
||||
if (room == null) {
|
||||
return@withState
|
||||
}
|
||||
@ -286,10 +286,10 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
||||
powerLevelsContentLive.subscribe {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
val permissions = ActionPermissions(
|
||||
canKick = powerLevelsHelper.canKick(session.myUserId),
|
||||
canBan = powerLevelsHelper.canBan(session.myUserId),
|
||||
canInvite = powerLevelsHelper.canInvite(session.myUserId),
|
||||
canEditPowerLevel = powerLevelsHelper.isAllowedToSend(true, EventType.STATE_ROOM_POWER_LEVELS, session.myUserId)
|
||||
canKick = powerLevelsHelper.isUserAbleToKick(session.myUserId),
|
||||
canBan = powerLevelsHelper.isUserAbleToBan(session.myUserId),
|
||||
canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId),
|
||||
canEditPowerLevel = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_POWER_LEVELS)
|
||||
)
|
||||
setState { copy(powerLevelsContent = it, actionPermissions = permissions) }
|
||||
}.disposeOnClear()
|
||||
|
@ -73,7 +73,7 @@ object EditPowerLevelDialogs {
|
||||
}
|
||||
|
||||
fun showValidation(activity: Activity, onValidate: () -> Unit) {
|
||||
// ask to the user to confirmation thu upgrade.
|
||||
// Ask to the user the confirmation to upgrade.
|
||||
AlertDialog.Builder(activity)
|
||||
.setMessage(R.string.room_participants_power_level_prompt)
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
@ -84,6 +84,7 @@ object EditPowerLevelDialogs {
|
||||
}
|
||||
|
||||
fun showDemoteWarning(activity: Activity, onValidate: () -> Unit) {
|
||||
// Ask to the user the confirmation to downgrade his own role.
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.room_participants_power_level_demote_warning_title)
|
||||
.setMessage(R.string.room_participants_power_level_demote_warning_prompt)
|
||||
|
@ -124,7 +124,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
|
||||
PowerLevelsObservableFactory(room).createObservable()
|
||||
.subscribe {
|
||||
val permissions = ActionPermissions(
|
||||
canInvite = PowerLevelsHelper(it).canInvite(session.myUserId)
|
||||
canInvite = PowerLevelsHelper(it).isUserAbleToInvite(session.myUserId)
|
||||
)
|
||||
setState {
|
||||
copy(actionsPermissions = permissions)
|
||||
|
@ -154,7 +154,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
|
||||
val canSend = if (powerLevelsContent == null) {
|
||||
false
|
||||
} else {
|
||||
PowerLevelsHelper(powerLevelsContent).isAllowedToSend(isState, eventType, session.myUserId)
|
||||
PowerLevelsHelper(powerLevelsContent).isUserAllowedToSend(session.myUserId, isState, eventType)
|
||||
}
|
||||
if (canSend) {
|
||||
Timber.d("## canSendEvent() returns true")
|
||||
|
@ -112,7 +112,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.unwrap()
|
||||
.map {
|
||||
PowerLevelsHelper(it).isAllowedToSend(true, null, session.myUserId)
|
||||
PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, null)
|
||||
}.subscribe {
|
||||
setState { copy(canManageWidgets = it) }
|
||||
}.disposeOnClear()
|
||||
|
Loading…
Reference in New Issue
Block a user