Browse Source

Display banned users in room member list (#2415)

* Display banned users in room member list

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
pull/2425/head
Jorge Martin Espinosa 7 months ago committed by GitHub
parent
commit
e68139bf46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      changelog.d/2256.feature
  2. 21
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt
  3. 4
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt
  4. 14
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt
  5. 150
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt
  6. 2
      features/roomdetails/impl/src/main/res/values/localazy.xml
  7. 1
      features/verifysession/impl/src/main/res/values/localazy.xml
  8. 2
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt
  9. 5
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt
  10. 6
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt
  11. 9
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
  12. 1
      libraries/ui-strings/src/main/res/values/localazy.xml
  13. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberBannedList_null_RoomMemberBannedList-Day-3_4_null,NEXUS_5,1.0,en].png
  14. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberBannedList_null_RoomMemberBannedList-Night-3_5_null,NEXUS_5,1.0,en].png
  15. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberList_null_RoomMemberList-Day-2_3_null_8,NEXUS_5,1.0,en].png
  16. BIN
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberList_null_RoomMemberList-Night-2_4_null_8,NEXUS_5,1.0,en].png
  17. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png
  18. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_1,NEXUS_5,1.0,en].png
  19. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_2,NEXUS_5,1.0,en].png
  20. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_3,NEXUS_5,1.0,en].png
  21. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_4,NEXUS_5,1.0,en].png
  22. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_5,NEXUS_5,1.0,en].png
  23. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_6,NEXUS_5,1.0,en].png
  24. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png
  25. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_1,NEXUS_5,1.0,en].png
  26. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_2,NEXUS_5,1.0,en].png
  27. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_3,NEXUS_5,1.0,en].png
  28. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_4,NEXUS_5,1.0,en].png
  29. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_5,NEXUS_5,1.0,en].png
  30. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_6,NEXUS_5,1.0,en].png
  31. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-4_5_null,NEXUS_5,1.0,en].png
  32. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-4_6_null,NEXUS_5,1.0,en].png
  33. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-6_7_null_0,NEXUS_5,1.0,en].png
  34. 0
      tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-6_8_null_0,NEXUS_5,1.0,en].png

1
changelog.d/2256.feature

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
Add moderation to rooms:
- Sort member in room member list by powerlevel, display their roles.
- Display banner users in room member list for users with enough power level to ban/unban.

21
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt

@ -27,14 +27,18 @@ import androidx.compose.runtime.saveable.rememberSaveable @@ -27,14 +27,18 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.powerlevels.canBan
import io.element.android.libraries.matrix.api.room.powerlevels.canInvite
import io.element.android.libraries.matrix.api.room.roomMembers
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import javax.inject.Inject
@ -57,6 +61,20 @@ class RoomMemberListPresenter @Inject constructor( @@ -57,6 +61,20 @@ class RoomMemberListPresenter @Inject constructor(
value = room.canInvite().getOrElse { false }
}
val canDisplayBannedUsers by produceState(initialValue = false) {
val roomIsNotDmAndUserCanBan = !room.isDm && room.canBan().getOrElse { false }
if (roomIsNotDmAndUserCanBan) {
room.membersStateFlow
.onEach { members ->
val hasBannedUsers = members.roomMembers()?.any { it.membership == RoomMembershipState.BAN }.orFalse()
value = hasBannedUsers
}
.collect()
} else {
value = false
}
}
LaunchedEffect(membersState) {
if (membersState is MatrixRoomMembersState.Unknown) {
return@LaunchedEffect
@ -69,6 +87,7 @@ class RoomMemberListPresenter @Inject constructor( @@ -69,6 +87,7 @@ class RoomMemberListPresenter @Inject constructor(
joined = members.getOrDefault(RoomMembershipState.JOIN, emptyList())
.sortedWith(PowerLevelRoomMemberComparator())
.toImmutableList(),
banned = members.getOrDefault(RoomMembershipState.BAN, emptyList()).sortedBy { it.userId.value }.toImmutableList(),
)
)
}
@ -89,6 +108,7 @@ class RoomMemberListPresenter @Inject constructor( @@ -89,6 +108,7 @@ class RoomMemberListPresenter @Inject constructor(
joined = results.getOrDefault(RoomMembershipState.JOIN, emptyList())
.sortedWith(PowerLevelRoomMemberComparator())
.toImmutableList(),
banned = results.getOrDefault(RoomMembershipState.BAN, emptyList()).sortedBy { it.userId.value }.toImmutableList(),
)
)
}
@ -102,6 +122,7 @@ class RoomMemberListPresenter @Inject constructor( @@ -102,6 +122,7 @@ class RoomMemberListPresenter @Inject constructor(
searchResults = searchResults,
isSearchActive = isSearchActive,
canInvite = canInvite,
canDisplayBannedUsers = canDisplayBannedUsers,
eventSink = { event ->
when (event) {
is RoomMemberListEvents.OnSearchActiveChanged -> isSearchActive = event.active

4
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt

@ -27,10 +27,12 @@ data class RoomMemberListState( @@ -27,10 +27,12 @@ data class RoomMemberListState(
val searchResults: SearchBarResultState<RoomMembers>,
val isSearchActive: Boolean,
val canInvite: Boolean,
val canDisplayBannedUsers: Boolean,
val eventSink: (RoomMemberListEvents) -> Unit,
)
data class RoomMembers(
val invited: ImmutableList<RoomMember>,
val joined: ImmutableList<RoomMember>
val joined: ImmutableList<RoomMember>,
val banned: ImmutableList<RoomMember>,
)

14
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt

@ -32,6 +32,7 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMember @@ -32,6 +32,7 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMember
RoomMembers(
invited = persistentListOf(aVictor(), aWalter()),
joined = persistentListOf(anAlice(), aBob(), aWalter()),
banned = persistentListOf(),
)
)
),
@ -47,6 +48,7 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMember @@ -47,6 +48,7 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMember
RoomMembers(
invited = persistentListOf(aVictor()),
joined = persistentListOf(anAlice()),
banned = persistentListOf(),
)
),
),
@ -55,18 +57,30 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMember @@ -55,18 +57,30 @@ internal class RoomMemberListStateProvider : PreviewParameterProvider<RoomMember
searchQuery = "something-with-no-results",
searchResults = SearchBarResultState.NoResultsFound()
),
aRoomMemberListState().copy(
roomMembers = AsyncData.Success(
RoomMembers(
invited = persistentListOf(aVictor(), aWalter()),
joined = persistentListOf(anAlice(), aBob(), aWalter()),
banned = persistentListOf(),
)
),
canDisplayBannedUsers = true,
),
)
}
internal fun aRoomMemberListState(
roomMembers: AsyncData<RoomMembers> = AsyncData.Uninitialized,
searchResults: SearchBarResultState<RoomMembers> = SearchBarResultState.Initial(),
canDisplayBannedUsers: Boolean = false,
) = RoomMemberListState(
roomMembers = roomMembers,
searchQuery = "",
searchResults = searchResults,
isSearchActive = false,
canInvite = false,
canDisplayBannedUsers = canDisplayBannedUsers,
eventSink = {}
)

150
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListView.kt

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
package io.element.android.features.roomdetails.impl.members
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -30,7 +32,12 @@ import androidx.compose.foundation.lazy.items @@ -30,7 +32,12 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
@ -49,6 +56,7 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre @@ -49,6 +56,7 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.SearchBar
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.designsystem.theme.components.SegmentedButton
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar
@ -58,6 +66,12 @@ import io.element.android.libraries.matrix.api.user.MatrixUser @@ -58,6 +66,12 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.MatrixUserRow
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
private enum class SelectedSection {
MEMBERS,
BANNED
}
@Composable
fun RoomMemberListView(
@ -66,6 +80,7 @@ fun RoomMemberListView( @@ -66,6 +80,7 @@ fun RoomMemberListView(
onInvitePressed: () -> Unit,
onMemberSelected: (UserId) -> Unit,
modifier: Modifier = Modifier,
initialSelectedSectionIndex: Int = 0,
) {
fun onUserSelected(roomMember: RoomMember) {
onMemberSelected(roomMember.userId)
@ -83,6 +98,7 @@ fun RoomMemberListView( @@ -83,6 +98,7 @@ fun RoomMemberListView(
}
}
) { padding ->
var selectedSection by remember { mutableStateOf(SelectedSection.entries[initialSelectedSectionIndex]) }
Column(
modifier = Modifier
.fillMaxWidth()
@ -98,7 +114,8 @@ fun RoomMemberListView( @@ -98,7 +114,8 @@ fun RoomMemberListView(
onActiveChanged = { state.eventSink(RoomMemberListEvents.OnSearchActiveChanged(it)) },
onTextChanged = { state.eventSink(RoomMemberListEvents.UpdateSearchQuery(it)) },
onUserSelected = ::onUserSelected,
modifier = Modifier.fillMaxWidth()
selectedSection = selectedSection,
modifier = Modifier.fillMaxWidth(),
)
if (!state.isSearchActive) {
@ -106,7 +123,10 @@ fun RoomMemberListView( @@ -106,7 +123,10 @@ fun RoomMemberListView(
RoomMemberList(
roomMembers = state.roomMembers.data,
showMembersCount = true,
onUserSelected = ::onUserSelected
canDisplayBannedUsersControls = state.canDisplayBannedUsers,
selectedSection = selectedSection,
onSelectedSectionChanged = { selectedSection = it },
onUserSelected = ::onUserSelected,
)
} else if (state.roomMembers.isLoading()) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
@ -118,49 +138,90 @@ fun RoomMemberListView( @@ -118,49 +138,90 @@ fun RoomMemberListView(
}
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
private fun RoomMemberList(
roomMembers: RoomMembers,
showMembersCount: Boolean,
selectedSection: SelectedSection,
onSelectedSectionChanged: (SelectedSection) -> Unit,
canDisplayBannedUsersControls: Boolean,
onUserSelected: (RoomMember) -> Unit,
) {
LazyColumn(modifier = Modifier.fillMaxWidth(), state = rememberLazyListState()) {
if (roomMembers.invited.isNotEmpty()) {
roomMemberListSection(
headerText = { stringResource(id = R.string.screen_room_member_list_pending_header_title) },
members = roomMembers.invited,
onMemberSelected = { onUserSelected(it) }
)
}
if (roomMembers.joined.isNotEmpty()) {
roomMemberListSection(
headerText = {
if (showMembersCount) {
val memberCount = roomMembers.joined.count()
pluralStringResource(id = R.plurals.screen_room_member_list_header_title, count = memberCount, memberCount)
} else {
stringResource(id = R.string.screen_room_member_list_room_members_header_title)
if (canDisplayBannedUsersControls) {
stickyHeader {
val segmentedButtonTitles = persistentListOf(
stringResource(id = R.string.screen_room_member_list_mode_members),
stringResource(id = R.string.screen_room_member_list_mode_banned),
)
SingleChoiceSegmentedButtonRow(
modifier = Modifier
.background(ElementTheme.colors.bgCanvasDefault)
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
) {
for ((index, title) in segmentedButtonTitles.withIndex()) {
SegmentedButton(
index = index,
count = segmentedButtonTitles.size,
selected = selectedSection.ordinal == index,
onClick = { onSelectedSectionChanged(SelectedSection.entries[index]) },
text = title,
)
}
},
members = roomMembers.joined,
onMemberSelected = { onUserSelected(it) }
)
}
}
}
when (selectedSection) {
SelectedSection.MEMBERS -> {
if (roomMembers.invited.isNotEmpty()) {
roomMemberListSection(
headerText = { stringResource(id = R.string.screen_room_member_list_pending_header_title) },
members = roomMembers.invited,
onMemberSelected = { onUserSelected(it) }
)
}
if (roomMembers.joined.isNotEmpty()) {
roomMemberListSection(
headerText = {
if (showMembersCount) {
val memberCount = roomMembers.joined.count()
pluralStringResource(id = R.plurals.screen_room_member_list_header_title, count = memberCount, memberCount)
} else {
stringResource(id = R.string.screen_room_member_list_room_members_header_title)
}
},
members = roomMembers.joined,
onMemberSelected = { onUserSelected(it) }
)
}
}
SelectedSection.BANNED -> { // Banned users
roomMemberListSection(
headerText = null,
members = roomMembers.banned,
onMemberSelected = { onUserSelected(it) }
)
}
}
}
}
private fun LazyListScope.roomMemberListSection(
headerText: @Composable () -> String,
headerText: @Composable (() -> String)?,
members: ImmutableList<RoomMember>,
onMemberSelected: (RoomMember) -> Unit,
) {
item {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
text = headerText(),
style = ElementTheme.typography.fontBodyLgRegular,
color = MaterialTheme.colorScheme.secondary,
)
headerText?.let {
item {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
text = it(),
style = ElementTheme.typography.fontBodyLgRegular,
color = MaterialTheme.colorScheme.secondary,
)
}
}
items(members) { matrixUser ->
RoomMemberListItem(
@ -238,6 +299,7 @@ private fun RoomMemberSearchBar( @@ -238,6 +299,7 @@ private fun RoomMemberSearchBar(
onActiveChanged: (Boolean) -> Unit,
onTextChanged: (String) -> Unit,
onUserSelected: (RoomMember) -> Unit,
selectedSection: SelectedSection,
modifier: Modifier = Modifier,
) {
SearchBar(
@ -252,7 +314,10 @@ private fun RoomMemberSearchBar( @@ -252,7 +314,10 @@ private fun RoomMemberSearchBar(
RoomMemberList(
roomMembers = results,
showMembersCount = false,
onUserSelected = { onUserSelected(it) }
onUserSelected = { onUserSelected(it) },
canDisplayBannedUsersControls = false,
selectedSection = selectedSection,
onSelectedSectionChanged = {},
)
},
)
@ -268,3 +333,28 @@ internal fun RoomMemberListPreview(@PreviewParameter(RoomMemberListStateProvider @@ -268,3 +333,28 @@ internal fun RoomMemberListPreview(@PreviewParameter(RoomMemberListStateProvider
onInvitePressed = {},
)
}
@PreviewsDayNight
@Composable
internal fun RoomMemberBannedListPreview() = ElementPreview {
RoomMemberListView(
initialSelectedSectionIndex = 1,
state = aRoomMemberListState(
roomMembers = AsyncData.Success(
RoomMembers(
invited = persistentListOf(),
joined = persistentListOf(),
banned = persistentListOf(
aRoomMember(userId = UserId("@alice:example.com"), displayName = "Alice"),
aRoomMember(userId = UserId("@bob:example.com"), displayName = "Bob"),
aRoomMember(userId = UserId("@charlie:example.com"), displayName = "Charlie"),
),
)
),
canDisplayBannedUsers = true,
),
onBackPressed = {},
onMemberSelected = {},
onInvitePressed = {},
)
}

2
features/roomdetails/impl/src/main/res/values/localazy.xml

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
<string name="screen_room_details_notification_title">"Notifications"</string>
<string name="screen_room_details_share_room_title">"Share room"</string>
<string name="screen_room_details_updating_room">"Updating room…"</string>
<string name="screen_room_member_list_mode_banned">"Banned"</string>
<string name="screen_room_member_list_mode_members">"Members"</string>
<string name="screen_room_member_list_pending_header_title">"Pending"</string>
<string name="screen_room_member_list_role_administrator">"Admin"</string>
<string name="screen_room_member_list_role_moderator">"Moderator"</string>

1
features/verifysession/impl/src/main/res/values/localazy.xml

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
<string name="screen_session_verification_compare_numbers_subtitle">"Confirm that the numbers below match those shown on your other session."</string>
<string name="screen_session_verification_compare_numbers_title">"Compare numbers"</string>
<string name="screen_session_verification_complete_subtitle">"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted."</string>
<string name="screen_session_verification_enter_recovery_key">"Enter recovery key"</string>
<string name="screen_session_verification_open_existing_session_subtitle">"Prove it’s you in order to access your encrypted message history."</string>
<string name="screen_session_verification_open_existing_session_title">"Open an existing session"</string>
<string name="screen_session_verification_positive_button_canceled">"Retry verification"</string>

2
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt

@ -129,6 +129,8 @@ interface MatrixRoom : Closeable { @@ -129,6 +129,8 @@ interface MatrixRoom : Closeable {
suspend fun canUserInvite(userId: UserId): Result<Boolean>
suspend fun canUserBan(userId: UserId): Result<Boolean>
suspend fun canUserRedactOwn(userId: UserId): Result<Boolean>
suspend fun canUserRedactOther(userId: UserId): Result<Boolean>

5
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt

@ -25,6 +25,11 @@ import io.element.android.libraries.matrix.api.room.StateEventType @@ -25,6 +25,11 @@ import io.element.android.libraries.matrix.api.room.StateEventType
*/
suspend fun MatrixRoom.canInvite(): Result<Boolean> = canUserInvite(sessionId)
/**
* Shortcut for calling [MatrixRoom.canBanUser] with our own user.
*/
suspend fun MatrixRoom.canBan(): Result<Boolean> = canUserBan(sessionId)
/**
* Shortcut for calling [MatrixRoom.canUserSendState] with our own user.
*/

6
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt

@ -319,6 +319,12 @@ class RustMatrixRoom( @@ -319,6 +319,12 @@ class RustMatrixRoom(
}
}
override suspend fun canUserBan(userId: UserId): Result<Boolean> {
return runCatching {
innerRoom.canUserBan(userId.value)
}
}
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> {
return runCatching {
innerRoom.canUserRedactOwn(userId.value)

9
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt

@ -90,6 +90,7 @@ class FakeMatrixRoom( @@ -90,6 +90,7 @@ class FakeMatrixRoom(
private var joinRoomResult = Result.success(Unit)
private var inviteUserResult = Result.success(Unit)
private var canInviteResult = Result.success(true)
private var canBanResult = Result.success(false)
private var canRedactOwnResult = Result.success(canRedactOwn)
private var canRedactOtherResult = Result.success(canRedactOther)
private val canSendStateResults = mutableMapOf<StateEventType, Result<Boolean>>()
@ -280,6 +281,10 @@ class FakeMatrixRoom( @@ -280,6 +281,10 @@ class FakeMatrixRoom(
inviteUserResult
}
override suspend fun canUserBan(userId: UserId): Result<Boolean> {
return canBanResult
}
override suspend fun canUserInvite(userId: UserId): Result<Boolean> {
return canInviteResult
}
@ -495,6 +500,10 @@ class FakeMatrixRoom( @@ -495,6 +500,10 @@ class FakeMatrixRoom(
joinRoomResult = result
}
fun givenCanBanResult(result: Result<Boolean>) {
canBanResult = result
}
fun givenInviteUserResult(result: Result<Unit>) {
inviteUserResult = result
}

1
libraries/ui-strings/src/main/res/values/localazy.xml

@ -120,6 +120,7 @@ @@ -120,6 +120,7 @@
<string name="common_error">"Error"</string>
<string name="common_everyone">"Everyone"</string>
<string name="common_favourite">"Favourite"</string>
<string name="common_favourited">"Favourited"</string>
<string name="common_file">"File"</string>
<string name="common_file_saved_on_disk_android">"File saved to Downloads"</string>
<string name="common_forward_message">"Forward message"</string>

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberBannedList_null_RoomMemberBannedList-Day-3_4_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberBannedList_null_RoomMemberBannedList-Night-3_5_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberList_null_RoomMemberList-Day-2_3_null_8,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.members_RoomMemberList_null_RoomMemberList-Night-2_4_null_8,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_0,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_1,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_2,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_3,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_3,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_4,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_4,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_5,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_5,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-4_5_null_6,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Day-5_6_null_6,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_0,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_1,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_1,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_2,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_2,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_3,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_3,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_4,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_4,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_5,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_5,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-4_6_null_6,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomNotificationSettings_null_RoomNotificationSettings-Night-5_7_null_6,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-3_4_null,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Day-4_5_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-3_5_null,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_RoomPrivacyOption_null_RoomPrivacyOption-Night-4_6_null,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-5_6_null_0,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Day-6_7_null_0,NEXUS_5,1.0,en].png

0
tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-5_7_null_0,NEXUS_5,1.0,en].png → tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_UserDefinedRoomNotificationSettings_null_UserDefinedRoomNotificationSettings-Night-6_8_null_0,NEXUS_5,1.0,en].png

Loading…
Cancel
Save