mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Merge pull request #2627 from vector-im/feature/bma/edit_power_level
Edit power level
This commit is contained in:
commit
5431584b3c
24 changed files with 874 additions and 44 deletions
|
@ -3,6 +3,7 @@ Changes in Element 1.0.14 (2020-XX-XX)
|
|||
|
||||
Features ✨:
|
||||
- Enable url previews for notices (#2562)
|
||||
- Edit room permissions (#2471)
|
||||
|
||||
Improvements 🙌:
|
||||
- Add System theme option and set as default (#904, #2387)
|
||||
|
|
|
@ -37,6 +37,6 @@ class SenderNotificationPermissionCondition(
|
|||
|
||||
fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean {
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevels)
|
||||
return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevelsHelper.notificationLevel(key)
|
||||
return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevels.notificationLevel(key)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,28 +25,85 @@ import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
|||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class PowerLevelsContent(
|
||||
/**
|
||||
* The level required to ban a user. Defaults to 50 if unspecified.
|
||||
*/
|
||||
@Json(name = "ban") val ban: Int = Role.Moderator.value,
|
||||
/**
|
||||
* The level required to kick a user. Defaults to 50 if unspecified.
|
||||
*/
|
||||
@Json(name = "kick") val kick: Int = Role.Moderator.value,
|
||||
/**
|
||||
* The level required to invite a user. Defaults to 50 if unspecified.
|
||||
*/
|
||||
@Json(name = "invite") val invite: Int = Role.Moderator.value,
|
||||
/**
|
||||
* The level required to redact an event. Defaults to 50 if unspecified.
|
||||
*/
|
||||
@Json(name = "redact") val redact: Int = Role.Moderator.value,
|
||||
/**
|
||||
* The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.
|
||||
*/
|
||||
@Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
|
||||
@Json(name = "events") val events: MutableMap<String, Int> = HashMap(),
|
||||
/**
|
||||
* The level required to send specific event types. This is a mapping from event type to power level required.
|
||||
*/
|
||||
@Json(name = "events") val events: Map<String, Int> = emptyMap(),
|
||||
/**
|
||||
* The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified.
|
||||
*/
|
||||
@Json(name = "users_default") val usersDefault: Int = Role.Default.value,
|
||||
@Json(name = "users") val users: MutableMap<String, Int> = HashMap(),
|
||||
/**
|
||||
* The power levels for specific users. This is a mapping from user_id to power level for that user.
|
||||
*/
|
||||
@Json(name = "users") val users: Map<String, Int> = emptyMap(),
|
||||
/**
|
||||
* The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.
|
||||
*/
|
||||
@Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
|
||||
@Json(name = "notifications") val notifications: Map<String, Any> = HashMap()
|
||||
/**
|
||||
* The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.
|
||||
*/
|
||||
@Json(name = "notifications") val notifications: Map<String, Any> = emptyMap()
|
||||
) {
|
||||
/**
|
||||
* Alter this content with a new power level for the specified user
|
||||
* Return a copy of this content with a new power level for the specified user
|
||||
*
|
||||
* @param userId the userId to alter the power level of
|
||||
* @param powerLevel the new power level, or null to set the default value.
|
||||
*/
|
||||
fun setUserPowerLevel(userId: String, powerLevel: Int?) {
|
||||
if (powerLevel == null || powerLevel == usersDefault) {
|
||||
users.remove(userId)
|
||||
} else {
|
||||
users[userId] = powerLevel
|
||||
fun setUserPowerLevel(userId: String, powerLevel: Int?): PowerLevelsContent {
|
||||
return copy(
|
||||
users = users.toMutableMap().apply {
|
||||
if (powerLevel == null || powerLevel == usersDefault) {
|
||||
remove(userId)
|
||||
} else {
|
||||
put(userId, powerLevel)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification level for a dedicated key.
|
||||
*
|
||||
* @param key the notification key
|
||||
* @return the level, default to Moderator if the key is not found
|
||||
*/
|
||||
fun notificationLevel(key: String): Int {
|
||||
return when (val value = notifications[key]) {
|
||||
// the first implementation was a string value
|
||||
is String -> value.toInt()
|
||||
is Double -> value.toInt()
|
||||
is Int -> value
|
||||
else -> Role.Moderator.value
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Key to use for content.notifications and get the level required to trigger an @room notification. Defaults to 50 if unspecified.
|
||||
*/
|
||||
const val NOTIFICATIONS_ROOM_KEY = "room"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,19 +108,4 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
|||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.redact
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification level for a dedicated key.
|
||||
*
|
||||
* @param key the notification key
|
||||
* @return the level
|
||||
*/
|
||||
fun notificationLevel(key: String): Int {
|
||||
return when (val value = powerLevelsContent.notifications[key]) {
|
||||
// the first implementation was a string value
|
||||
is String -> value.toInt()
|
||||
is Int -> value
|
||||
else -> Role.Moderator.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,13 +35,11 @@ import org.matrix.android.sdk.api.util.JsonDict
|
|||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.session.content.FileUploader
|
||||
import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask
|
||||
|
||||
internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||
private val stateEventDataSource: StateEventDataSource,
|
||||
private val sendStateTask: SendStateTask,
|
||||
private val fileUploader: FileUploader,
|
||||
private val addRoomAliasTask: AddRoomAliasTask
|
||||
private val fileUploader: FileUploader
|
||||
) : StateService {
|
||||
|
||||
@AssistedInject.Factory
|
||||
|
@ -74,11 +72,19 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
|||
roomId = roomId,
|
||||
stateKey = stateKey,
|
||||
eventType = eventType,
|
||||
body = body
|
||||
body = body.toSafeJson(eventType)
|
||||
)
|
||||
sendStateTask.execute(params)
|
||||
}
|
||||
|
||||
private fun JsonDict.toSafeJson(eventType: String): JsonDict {
|
||||
// Safe treatment for PowerLevelContent
|
||||
return when (eventType) {
|
||||
EventType.STATE_ROOM_POWER_LEVELS -> toSafePowerLevelsContentDict()
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateTopic(topic: String) {
|
||||
sendStateEvent(
|
||||
eventType = EventType.STATE_ROOM_TOPIC,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.session.room.state
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class SerializablePowerLevelsContent(
|
||||
@Json(name = "ban") val ban: Int = Role.Moderator.value,
|
||||
@Json(name = "kick") val kick: Int = Role.Moderator.value,
|
||||
@Json(name = "invite") val invite: Int = Role.Moderator.value,
|
||||
@Json(name = "redact") val redact: Int = Role.Moderator.value,
|
||||
@Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
|
||||
@Json(name = "events") val events: Map<String, Int> = emptyMap(),
|
||||
@Json(name = "users_default") val usersDefault: Int = Role.Default.value,
|
||||
@Json(name = "users") val users: Map<String, Int> = emptyMap(),
|
||||
@Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
|
||||
// `Int` is the diff here (instead of `Any`)
|
||||
@Json(name = "notifications") val notifications: Map<String, Int> = emptyMap()
|
||||
)
|
||||
|
||||
internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
|
||||
return toModel<PowerLevelsContent>()
|
||||
?.let { content ->
|
||||
SerializablePowerLevelsContent(
|
||||
ban = content.ban,
|
||||
kick = content.kick,
|
||||
invite = content.invite,
|
||||
redact = content.redact,
|
||||
eventsDefault = content.eventsDefault,
|
||||
events = content.events,
|
||||
usersDefault = content.usersDefault,
|
||||
users = content.users,
|
||||
stateDefault = content.stateDefault,
|
||||
notifications = content.notifications.mapValues { content.notificationLevel(it.key) }
|
||||
)
|
||||
}
|
||||
?.toContent()
|
||||
?: emptyMap()
|
||||
}
|
|
@ -247,6 +247,7 @@ class UiAllScreensSanityTest {
|
|||
|
||||
// Room settings
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 3)
|
||||
navigateToRoomParameters()
|
||||
pressBack()
|
||||
|
||||
// Notifications
|
||||
|
@ -285,6 +286,31 @@ class UiAllScreensSanityTest {
|
|||
pressBack()
|
||||
}
|
||||
|
||||
private fun navigateToRoomParameters() {
|
||||
// Room addresses
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 4)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_alias_published_alias_title)))
|
||||
pressBack()
|
||||
|
||||
// Room permissions
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 6)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_permissions_title)))
|
||||
clickOn(R.string.room_permissions_change_room_avatar)
|
||||
clickDialogNegativeButton()
|
||||
// Toggle
|
||||
clickOn(R.string.show_advanced)
|
||||
clickOn(R.string.hide_advanced)
|
||||
pressBack()
|
||||
|
||||
// Room history readability
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 8)
|
||||
pressBack()
|
||||
|
||||
// Room access
|
||||
clickListItem(R.id.roomSettingsRecyclerView, 10)
|
||||
pressBack()
|
||||
}
|
||||
|
||||
private fun navigateToInvite() {
|
||||
assertDisplayed(R.id.inviteUsersButton)
|
||||
clickOn(R.id.inviteUsersButton)
|
||||
|
|
|
@ -84,6 +84,7 @@ import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
|
|||
import im.vector.app.features.roomprofile.members.RoomMemberListFragment
|
||||
import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
|
||||
import im.vector.app.features.roomprofile.alias.RoomAliasFragment
|
||||
import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
|
||||
import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
|
||||
import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment
|
||||
import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment
|
||||
|
@ -364,6 +365,11 @@ interface FragmentModule {
|
|||
@FragmentKey(RoomAliasFragment::class)
|
||||
fun bindRoomAliasFragment(fragment: RoomAliasFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomPermissionsFragment::class)
|
||||
fun bindRoomPermissionsFragment(fragment: RoomPermissionsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomMemberProfileFragment::class)
|
||||
|
|
|
@ -887,13 +887,15 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private fun handleSetUserPowerLevel(setUserPowerLevel: ParsedCommand.SetUserPowerLevel) {
|
||||
val currentPowerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
val newPowerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.content
|
||||
?.toModel<PowerLevelsContent>() ?: return
|
||||
?.toModel<PowerLevelsContent>()
|
||||
?.setUserPowerLevel(setUserPowerLevel.userId, setUserPowerLevel.powerLevel)
|
||||
?.toContent()
|
||||
?: return
|
||||
|
||||
launchSlashCommandFlowSuspendable {
|
||||
currentPowerLevelsContent.setUserPowerLevel(setUserPowerLevel.userId, setUserPowerLevel.powerLevel)
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent())
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -324,7 +324,7 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onEditPowerLevel(currentRole: Role) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), currentRole) { newPowerLevel ->
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), R.string.power_level_edit_title, currentRole) { newPowerLevel ->
|
||||
viewModel.handle(RoomMemberProfileAction.SetPowerLevel(currentRole.value, newPowerLevel, true))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,11 +162,13 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
|||
} else if (action.askForValidation && state.isMine) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning(action.previousValue, action.newValue))
|
||||
} else {
|
||||
currentPowerLevelsContent.setUserPowerLevel(state.userId, action.newValue)
|
||||
val newPowerLevelsContent = currentPowerLevelsContent
|
||||
.setUserPowerLevel(state.userId, action.newValue)
|
||||
.toContent()
|
||||
viewModelScope.launch {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
||||
try {
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, currentPowerLevelsContent.toContent())
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent)
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.OnSetPowerLevelSuccess)
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.roommemberprofile.powerlevel
|
|||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.view.KeyEvent
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
|
@ -29,7 +30,10 @@ import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
|||
|
||||
object EditPowerLevelDialogs {
|
||||
|
||||
fun showChoice(activity: Activity, currentRole: Role, listener: (Int) -> Unit) {
|
||||
fun showChoice(activity: Activity,
|
||||
@StringRes titleRes: Int,
|
||||
currentRole: Role,
|
||||
listener: (Int) -> Unit) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_edit_power_level, null)
|
||||
val views = DialogEditPowerLevelBinding.bind(dialogLayout)
|
||||
views.powerLevelRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||
|
@ -45,7 +49,7 @@ object EditPowerLevelDialogs {
|
|||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.power_level_edit_title)
|
||||
.setTitle(titleRes)
|
||||
.setView(dialogLayout)
|
||||
.setPositiveButton(R.string.edit) { _, _ ->
|
||||
val newValue = when (views.powerLevelRadioGroup.checkedRadioButtonId) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.app.R
|
|||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.addFragment
|
||||
import im.vector.app.core.extensions.addFragmentToBackstack
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivitySimpleBinding
|
||||
|
@ -38,6 +39,7 @@ import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
|
|||
import im.vector.app.features.roomprofile.members.RoomMemberListFragment
|
||||
import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
|
||||
import im.vector.app.features.roomprofile.alias.RoomAliasFragment
|
||||
import im.vector.app.features.roomprofile.permissions.RoomPermissionsFragment
|
||||
import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -102,12 +104,13 @@ class RoomProfileActivity :
|
|||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
when (sharedAction) {
|
||||
is RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers()
|
||||
is RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings()
|
||||
is RoomProfileSharedAction.OpenRoomAliasesSettings -> openRoomAlias()
|
||||
is RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads()
|
||||
is RoomProfileSharedAction.OpenBannedRoomMembers -> openBannedRoomMembers()
|
||||
}
|
||||
RoomProfileSharedAction.OpenRoomMembers -> openRoomMembers()
|
||||
RoomProfileSharedAction.OpenRoomSettings -> openRoomSettings()
|
||||
RoomProfileSharedAction.OpenRoomAliasesSettings -> openRoomAlias()
|
||||
RoomProfileSharedAction.OpenRoomPermissionsSettings -> openRoomPermissions()
|
||||
RoomProfileSharedAction.OpenRoomUploads -> openRoomUploads()
|
||||
RoomProfileSharedAction.OpenBannedRoomMembers -> openBannedRoomMembers()
|
||||
}.exhaustive
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
|
@ -144,6 +147,10 @@ class RoomProfileActivity :
|
|||
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomAliasFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
|
||||
private fun openRoomPermissions() {
|
||||
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomPermissionsFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
|
||||
private fun openRoomMembers() {
|
||||
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.app.core.platform.VectorSharedAction
|
|||
sealed class RoomProfileSharedAction : VectorSharedAction {
|
||||
object OpenRoomSettings : RoomProfileSharedAction()
|
||||
object OpenRoomAliasesSettings : RoomProfileSharedAction()
|
||||
object OpenRoomPermissionsSettings : RoomProfileSharedAction()
|
||||
object OpenRoomUploads : RoomProfileSharedAction()
|
||||
object OpenRoomMembers : RoomProfileSharedAction()
|
||||
object OpenBannedRoomMembers : RoomProfileSharedAction()
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import im.vector.app.R
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
|
||||
/**
|
||||
* Change on each permission has an effect on the power level event. Try to sort the effect by category.
|
||||
*/
|
||||
sealed class EditablePermission(@StringRes val labelResId: Int) {
|
||||
// Updates `content.events.[eventType]`
|
||||
open class EventTypeEditablePermission(val eventType: String, @StringRes labelResId: Int) : EditablePermission(labelResId)
|
||||
|
||||
class ModifyWidgets : EventTypeEditablePermission(
|
||||
// Note: Element Web still use legacy value
|
||||
EventType.STATE_ROOM_WIDGET_LEGACY,
|
||||
R.string.room_permissions_modify_widgets
|
||||
)
|
||||
|
||||
class ChangeRoomAvatar : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_AVATAR,
|
||||
R.string.room_permissions_change_room_avatar
|
||||
)
|
||||
|
||||
class ChangeMainAddressForTheRoom : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_CANONICAL_ALIAS,
|
||||
R.string.room_permissions_change_main_address_for_the_room
|
||||
)
|
||||
|
||||
class EnableRoomEncryption : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_ENCRYPTION,
|
||||
R.string.room_permissions_enable_room_encryption
|
||||
)
|
||||
|
||||
class ChangeHistoryVisibility : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_HISTORY_VISIBILITY,
|
||||
R.string.room_permissions_change_history_visibility
|
||||
)
|
||||
|
||||
class ChangeRoomName : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_NAME,
|
||||
R.string.room_permissions_change_room_name
|
||||
)
|
||||
|
||||
class ChangePermissions : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_POWER_LEVELS,
|
||||
R.string.room_permissions_change_permissions
|
||||
)
|
||||
|
||||
class SendRoomServerAclEvents : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_SERVER_ACL,
|
||||
R.string.room_permissions_send_m_room_server_acl_events
|
||||
)
|
||||
|
||||
class UpgradeTheRoom : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_TOMBSTONE,
|
||||
R.string.room_permissions_upgrade_the_room
|
||||
)
|
||||
|
||||
class ChangeTopic : EventTypeEditablePermission(
|
||||
EventType.STATE_ROOM_TOPIC,
|
||||
R.string.room_permissions_change_topic
|
||||
)
|
||||
|
||||
// Updates `content.users_default`
|
||||
class DefaultRole : EditablePermission(R.string.room_permissions_default_role)
|
||||
|
||||
// Updates `content.events_default`
|
||||
class SendMessages : EditablePermission(R.string.room_permissions_send_messages)
|
||||
|
||||
// Updates `content.invites`
|
||||
class InviteUsers : EditablePermission(R.string.room_permissions_invite_users)
|
||||
|
||||
// Updates `content.state_default`
|
||||
class ChangeSettings : EditablePermission(R.string.room_permissions_change_settings)
|
||||
|
||||
// Updates `content.kick`
|
||||
class KickUsers : EditablePermission(R.string.room_permissions_kick_users)
|
||||
|
||||
// Updates `content.ban`
|
||||
class BanUsers : EditablePermission(R.string.room_permissions_ban_users)
|
||||
|
||||
// Updates `content.redact`
|
||||
class RemoveMessagesSentByOthers : EditablePermission(R.string.room_permissions_remove_messages_sent_by_others)
|
||||
|
||||
// Updates `content.notification.room`
|
||||
class NotifyEveryone : EditablePermission(R.string.room_permissions_notify_everyone)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class RoomPermissionsAction : VectorViewModelAction {
|
||||
object ToggleShowAllPermissions : RoomPermissionsAction()
|
||||
|
||||
data class UpdatePermission(val editablePermission: EditablePermission, val powerLevel: Int) : RoomPermissionsAction()
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Success
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.loadingItem
|
||||
import im.vector.app.core.epoxy.profiles.buildProfileAction
|
||||
import im.vector.app.core.epoxy.profiles.buildProfileSection
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.discovery.settingsInfoItem
|
||||
import im.vector.app.features.form.formAdvancedToggleItem
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomPermissionsController @Inject constructor(
|
||||
private val stringProvider: StringProvider,
|
||||
colorProvider: ColorProvider
|
||||
) : TypedEpoxyController<RoomPermissionsViewState>() {
|
||||
|
||||
interface Callback {
|
||||
fun onEditPermission(editablePermission: EditablePermission, currentRole: Role)
|
||||
fun toggleShowAllPermissions()
|
||||
}
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
|
||||
|
||||
// Order is the order applied in the UI
|
||||
// Element Web order is not really nice, try to put the settings which are more likely to be updated first
|
||||
// And a second section, hidden by default
|
||||
private val usefulEditablePermissions = listOf(
|
||||
EditablePermission.ChangeRoomAvatar(),
|
||||
EditablePermission.ChangeRoomName(),
|
||||
EditablePermission.ChangeTopic()
|
||||
)
|
||||
|
||||
private val advancedEditablePermissions = listOf(
|
||||
EditablePermission.ChangeMainAddressForTheRoom(),
|
||||
|
||||
EditablePermission.DefaultRole(),
|
||||
EditablePermission.InviteUsers(),
|
||||
EditablePermission.KickUsers(),
|
||||
EditablePermission.BanUsers(),
|
||||
|
||||
EditablePermission.SendMessages(),
|
||||
|
||||
EditablePermission.RemoveMessagesSentByOthers(),
|
||||
EditablePermission.NotifyEveryone(),
|
||||
|
||||
EditablePermission.ChangeSettings(),
|
||||
EditablePermission.ModifyWidgets(),
|
||||
EditablePermission.ChangeHistoryVisibility(),
|
||||
EditablePermission.ChangePermissions(),
|
||||
EditablePermission.SendRoomServerAclEvents(),
|
||||
EditablePermission.EnableRoomEncryption(),
|
||||
EditablePermission.UpgradeTheRoom()
|
||||
)
|
||||
|
||||
init {
|
||||
setData(null)
|
||||
}
|
||||
|
||||
override fun buildModels(data: RoomPermissionsViewState?) {
|
||||
buildProfileSection(
|
||||
stringProvider.getString(R.string.room_permissions_title)
|
||||
)
|
||||
|
||||
when (val content = data?.currentPowerLevelsContent) {
|
||||
is Success -> buildPermissions(data, content())
|
||||
else -> {
|
||||
loadingItem {
|
||||
id("loading")
|
||||
loadingText(stringProvider.getString(R.string.loading))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPermissions(data: RoomPermissionsViewState, content: PowerLevelsContent) {
|
||||
val editable = data.actionPermissions.canChangePowerLevels
|
||||
settingsInfoItem {
|
||||
id("notice")
|
||||
helperText(stringProvider.getString(if (editable) R.string.room_permissions_notice else R.string.room_permissions_notice_read_only))
|
||||
}
|
||||
|
||||
// Useful permissions
|
||||
usefulEditablePermissions.forEach { buildPermission(it, content, editable) }
|
||||
|
||||
// Toggle
|
||||
formAdvancedToggleItem {
|
||||
id("showAdvanced")
|
||||
title(stringProvider.getString(if (data.showAdvancedPermissions) R.string.hide_advanced else R.string.show_advanced))
|
||||
expanded(!data.showAdvancedPermissions)
|
||||
listener { callback?.toggleShowAllPermissions() }
|
||||
}
|
||||
|
||||
// Advanced permissions
|
||||
if (data.showAdvancedPermissions) {
|
||||
advancedEditablePermissions.forEach { buildPermission(it, content, editable) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPermission(editablePermission: EditablePermission, content: PowerLevelsContent, editable: Boolean) {
|
||||
val currentRole = getCurrentRole(editablePermission, content)
|
||||
buildProfileAction(
|
||||
id = editablePermission.labelResId.toString(),
|
||||
title = stringProvider.getString(editablePermission.labelResId),
|
||||
subtitle = getSubtitle(currentRole),
|
||||
dividerColor = dividerColor,
|
||||
divider = true,
|
||||
editable = editable,
|
||||
action = {
|
||||
callback
|
||||
?.takeIf { editable }
|
||||
?.onEditPermission(editablePermission, currentRole)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getSubtitle(currentRole: Role): String {
|
||||
return when (currentRole) {
|
||||
Role.Admin,
|
||||
Role.Moderator,
|
||||
Role.Default -> stringProvider.getString(currentRole.res)
|
||||
is Role.Custom -> stringProvider.getString(currentRole.res, currentRole.value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentRole(editablePermission: EditablePermission, content: PowerLevelsContent): Role {
|
||||
val value = when (editablePermission) {
|
||||
is EditablePermission.EventTypeEditablePermission -> content.events[editablePermission.eventType] ?: content.stateDefault
|
||||
is EditablePermission.DefaultRole -> content.usersDefault
|
||||
is EditablePermission.SendMessages -> content.eventsDefault
|
||||
is EditablePermission.InviteUsers -> content.invite
|
||||
is EditablePermission.ChangeSettings -> content.stateDefault
|
||||
is EditablePermission.KickUsers -> content.kick
|
||||
is EditablePermission.BanUsers -> content.ban
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> content.redact
|
||||
is EditablePermission.NotifyEveryone -> content.notificationLevel(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY)
|
||||
}
|
||||
|
||||
return Role.fromValue(
|
||||
value,
|
||||
when (editablePermission) {
|
||||
is EditablePermission.EventTypeEditablePermission -> content.stateDefault
|
||||
is EditablePermission.DefaultRole -> Role.Default.value
|
||||
is EditablePermission.SendMessages -> Role.Default.value
|
||||
is EditablePermission.InviteUsers -> Role.Moderator.value
|
||||
is EditablePermission.ChangeSettings -> Role.Moderator.value
|
||||
is EditablePermission.KickUsers -> Role.Moderator.value
|
||||
is EditablePermission.BanUsers -> Role.Moderator.value
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> Role.Moderator.value
|
||||
is EditablePermission.NotifyEveryone -> Role.Moderator.value
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.FragmentRoomSettingGenericBinding
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomPermissionsFragment @Inject constructor(
|
||||
val viewModelFactory: RoomPermissionsViewModel.Factory,
|
||||
private val controller: RoomPermissionsController,
|
||||
private val avatarRenderer: AvatarRenderer
|
||||
) :
|
||||
VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
|
||||
RoomPermissionsController.Callback {
|
||||
|
||||
private val viewModel: RoomPermissionsViewModel by fragmentViewModel()
|
||||
|
||||
private val roomProfileArgs: RoomProfileArgs by args()
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding {
|
||||
return FragmentRoomSettingGenericBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
controller.callback = this
|
||||
setupToolbar(views.roomSettingsToolbar)
|
||||
views.roomSettingsRecyclerView.configureWith(controller, hasFixedSize = true)
|
||||
views.waitingView.waitingStatusText.setText(R.string.please_wait)
|
||||
views.waitingView.waitingStatusText.isVisible = true
|
||||
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is RoomPermissionsViewEvents.Failure -> showFailure(it.throwable)
|
||||
RoomPermissionsViewEvents.Success -> showSuccess()
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSuccess() {
|
||||
activity?.toast(R.string.room_settings_save_success)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
controller.callback = null
|
||||
views.roomSettingsRecyclerView.cleanup()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
views.waitingView.root.isVisible = state.isLoading
|
||||
controller.setData(state)
|
||||
renderRoomSummary(state)
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(state: RoomPermissionsViewState) {
|
||||
state.roomSummary()?.let {
|
||||
views.roomSettingsToolbarTitleView.text = it.displayName
|
||||
avatarRenderer.render(it.toMatrixItem(), views.roomSettingsToolbarAvatarImageView)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEditPermission(editablePermission: EditablePermission, currentRole: Role) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), editablePermission.labelResId, currentRole) { newPowerLevel ->
|
||||
viewModel.handle(RoomPermissionsAction.UpdatePermission(editablePermission, newPowerLevel))
|
||||
}
|
||||
}
|
||||
|
||||
override fun toggleShowAllPermissions() {
|
||||
viewModel.handle(RoomPermissionsAction.ToggleShowAllPermissions)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
|
||||
/**
|
||||
* Transient events for room settings screen
|
||||
*/
|
||||
sealed class RoomPermissionsViewEvents : VectorViewEvents {
|
||||
data class Failure(val throwable: Throwable) : RoomPermissionsViewEvents()
|
||||
object Success : RoomPermissionsViewEvents()
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.rx.unwrap
|
||||
|
||||
class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialState: RoomPermissionsViewState,
|
||||
private val session: Session)
|
||||
: VectorViewModel<RoomPermissionsViewState, RoomPermissionsAction, RoomPermissionsViewEvents>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: RoomPermissionsViewState): RoomPermissionsViewModel
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<RoomPermissionsViewModel, RoomPermissionsViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: RoomPermissionsViewState): RoomPermissionsViewModel? {
|
||||
val fragment: RoomPermissionsFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
return fragment.viewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)!!
|
||||
|
||||
init {
|
||||
observeRoomSummary()
|
||||
observePowerLevel()
|
||||
}
|
||||
|
||||
private fun observeRoomSummary() {
|
||||
room.rx().liveRoomSummary()
|
||||
.unwrap()
|
||||
.execute { async ->
|
||||
copy(
|
||||
roomSummary = async
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observePowerLevel() {
|
||||
PowerLevelsObservableFactory(room)
|
||||
.createObservable()
|
||||
.subscribe { powerLevelContent ->
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
|
||||
val permissions = RoomPermissionsViewState.ActionPermissions(
|
||||
canChangePowerLevels = powerLevelsHelper.isUserAllowedToSend(
|
||||
userId = session.myUserId,
|
||||
isState = true,
|
||||
eventType = EventType.STATE_ROOM_POWER_LEVELS
|
||||
)
|
||||
)
|
||||
setState {
|
||||
copy(
|
||||
actionPermissions = permissions,
|
||||
currentPowerLevelsContent = Success(powerLevelContent)
|
||||
)
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
override fun handle(action: RoomPermissionsAction) {
|
||||
when (action) {
|
||||
is RoomPermissionsAction.UpdatePermission -> updatePermission(action)
|
||||
RoomPermissionsAction.ToggleShowAllPermissions -> toggleShowAllPermissions()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun toggleShowAllPermissions() {
|
||||
setState {
|
||||
copy(showAdvancedPermissions = !showAdvancedPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePermission(action: RoomPermissionsAction.UpdatePermission) {
|
||||
withState { state ->
|
||||
val currentPowerLevel = state.currentPowerLevelsContent.invoke() ?: return@withState
|
||||
postLoading(true)
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val newPowerLevelsContent = when (action.editablePermission) {
|
||||
is EditablePermission.EventTypeEditablePermission -> currentPowerLevel.copy(
|
||||
events = currentPowerLevel.events.toMutableMap().apply {
|
||||
put(action.editablePermission.eventType, action.powerLevel)
|
||||
}
|
||||
)
|
||||
is EditablePermission.DefaultRole -> currentPowerLevel.copy(usersDefault = action.powerLevel)
|
||||
is EditablePermission.SendMessages -> currentPowerLevel.copy(eventsDefault = action.powerLevel)
|
||||
is EditablePermission.InviteUsers -> currentPowerLevel.copy(invite = action.powerLevel)
|
||||
is EditablePermission.ChangeSettings -> currentPowerLevel.copy(stateDefault = action.powerLevel)
|
||||
is EditablePermission.KickUsers -> currentPowerLevel.copy(kick = action.powerLevel)
|
||||
is EditablePermission.BanUsers -> currentPowerLevel.copy(ban = action.powerLevel)
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> currentPowerLevel.copy(redact = action.powerLevel)
|
||||
is EditablePermission.NotifyEveryone -> currentPowerLevel.copy(
|
||||
notifications = currentPowerLevel.notifications.toMutableMap().apply {
|
||||
put(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY, action.powerLevel)
|
||||
}
|
||||
)
|
||||
}
|
||||
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, null, newPowerLevelsContent.toContent())
|
||||
setState {
|
||||
copy(
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
postLoading(false)
|
||||
_viewEvents.post(RoomPermissionsViewEvents.Failure(failure))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun postLoading(isLoading: Boolean) {
|
||||
setState {
|
||||
copy(isLoading = isLoading)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 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.app.features.roomprofile.permissions
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
data class RoomPermissionsViewState(
|
||||
val roomId: String,
|
||||
val roomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val actionPermissions: ActionPermissions = ActionPermissions(),
|
||||
val showAdvancedPermissions: Boolean = false,
|
||||
val currentPowerLevelsContent: Async<PowerLevelsContent> = Uninitialized,
|
||||
val isLoading: Boolean = false
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
|
||||
|
||||
data class ActionPermissions(
|
||||
val canChangePowerLevels: Boolean = false
|
||||
)
|
||||
}
|
|
@ -46,6 +46,7 @@ class RoomSettingsController @Inject constructor(
|
|||
fun onTopicChanged(topic: String)
|
||||
fun onHistoryVisibilityClicked()
|
||||
fun onRoomAliasesClicked()
|
||||
fun onRoomPermissionsClicked()
|
||||
fun onJoinRuleClicked()
|
||||
}
|
||||
|
||||
|
@ -115,6 +116,16 @@ class RoomSettingsController @Inject constructor(
|
|||
action = { callback?.onRoomAliasesClicked() }
|
||||
)
|
||||
|
||||
buildProfileAction(
|
||||
id = "permissions",
|
||||
title = stringProvider.getString(R.string.room_settings_permissions_title),
|
||||
subtitle = stringProvider.getString(R.string.room_settings_permissions_subtitle),
|
||||
dividerColor = dividerColor,
|
||||
divider = true,
|
||||
editable = true,
|
||||
action = { callback?.onRoomPermissionsClicked() }
|
||||
)
|
||||
|
||||
buildProfileAction(
|
||||
id = "historyReadability",
|
||||
title = stringProvider.getString(R.string.room_settings_room_read_history_rules_pref_title),
|
||||
|
|
|
@ -178,6 +178,10 @@ class RoomSettingsFragment @Inject constructor(
|
|||
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomAliasesSettings)
|
||||
}
|
||||
|
||||
override fun onRoomPermissionsClicked() {
|
||||
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomPermissionsSettings)
|
||||
}
|
||||
|
||||
override fun onJoinRuleClicked() = withState(viewModel) { state ->
|
||||
val currentJoinRule = state.newRoomJoinRules.newJoinRules ?: state.currentRoomJoinRules
|
||||
val currentGuestAccess = state.newRoomJoinRules.newGuestAccess ?: state.currentGuestAccess
|
||||
|
|
|
@ -610,6 +610,33 @@
|
|||
<string name="ssl_expected_existing_expl">The certificate has changed from a previously trusted one to one that is not trusted. The server may have renewed its certificate. Contact the server administrator for the expected fingerprint.</string>
|
||||
<string name="ssl_only_accept">Only accept the certificate if the server administrator has published a fingerprint that matches the one above.</string>
|
||||
|
||||
<!-- Room Permissions -->
|
||||
<string name="room_settings_permissions_title">Room permissions</string>
|
||||
<string name="room_settings_permissions_subtitle">View and update the roles required to change various parts of the room.</string>
|
||||
|
||||
<string name="room_permissions_title">"Permissions"</string>
|
||||
<string name="room_permissions_notice">"Select the roles required to change various parts of the room"</string>
|
||||
<string name="room_permissions_notice_read_only">"You don't have permission to update the roles required to change various parts of the room"</string>
|
||||
|
||||
<string name="room_permissions_default_role">Default role</string>
|
||||
<string name="room_permissions_send_messages">Send messages</string>
|
||||
<string name="room_permissions_invite_users">Invite users</string>
|
||||
<string name="room_permissions_change_settings">Change settings</string>
|
||||
<string name="room_permissions_kick_users">Kick users</string>
|
||||
<string name="room_permissions_ban_users">Ban users</string>
|
||||
<string name="room_permissions_remove_messages_sent_by_others">Remove messages sent by others</string>
|
||||
<string name="room_permissions_notify_everyone">Notify everyone</string>
|
||||
<string name="room_permissions_modify_widgets">Modify widgets</string>
|
||||
<string name="room_permissions_change_room_avatar">Change room avatar</string>
|
||||
<string name="room_permissions_change_main_address_for_the_room">Change main address for the room</string>
|
||||
<string name="room_permissions_enable_room_encryption">Enable room encryption</string>
|
||||
<string name="room_permissions_change_history_visibility">Change history visibility</string>
|
||||
<string name="room_permissions_change_room_name">Change room name</string>
|
||||
<string name="room_permissions_change_permissions">Change permissions</string>
|
||||
<string name="room_permissions_send_m_room_server_acl_events">Send m.room.server_acl events</string>
|
||||
<string name="room_permissions_upgrade_the_room">Upgrade the room</string>
|
||||
<string name="room_permissions_change_topic">Change topic</string>
|
||||
|
||||
<!-- Room Details -->
|
||||
<string name="room_details_title">Room Details</string>
|
||||
<string name="room_details_people">People</string>
|
||||
|
|
Loading…
Reference in a new issue