mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Rename properties and sort members in advance.
This commit is contained in:
@@ -34,7 +34,7 @@ nonisolated struct RoomMemberListScreenEntry: Equatable {
|
|||||||
let member: RoomMemberDetails
|
let member: RoomMemberDetails
|
||||||
let verificationState: UserIdentityVerificationState
|
let verificationState: UserIdentityVerificationState
|
||||||
/// Whether the member is currently joined to the room's active MatrixRTC call (e.g. Element Call).
|
/// Whether the member is currently joined to the room's active MatrixRTC call (e.g. Element Call).
|
||||||
var isInCall = false
|
var isActiveRoomCallParticipant = false
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomMembersListScreenViewState: BindableState {
|
struct RoomMembersListScreenViewState: BindableState {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
hideLoadingIndicator(Self.updateStateLoadingIndicatorIdentifier)
|
hideLoadingIndicator(Self.updateStateLoadingIndicatorIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
let members = members.sorted()
|
let members = members.sorted(prioritisingRoomCallParticipants: roomProxy.infoPublisher.value.activeRoomCallParticipants)
|
||||||
let roomMembersDetails = await buildMembersDetails(members: members)
|
let roomMembersDetails = await buildMembersDetails(members: members)
|
||||||
self.members = members
|
self.members = members
|
||||||
self.currentUserProxy = members.first { $0.userID == roomProxy.ownUserID }
|
self.currentUserProxy = members.first { $0.userID == roomProxy.ownUserID }
|
||||||
@@ -127,7 +127,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
let isEncrypted = roomProxy.infoPublisher.value.isEncrypted
|
let isEncrypted = roomProxy.infoPublisher.value.isEncrypted
|
||||||
let activeRoomCallParticipants = Set(roomProxy.infoPublisher.value.activeRoomCallParticipants)
|
let activeRoomCallParticipants = Set(roomProxy.infoPublisher.value.activeRoomCallParticipants)
|
||||||
|
|
||||||
let membersDetails: RoomMembersDetails = await Task.detached { [weak self] in
|
return await Task.detached { [weak self] in
|
||||||
// accessing RoomMember's properties is very slow. We need to do it in a background thread.
|
// accessing RoomMember's properties is very slow. We need to do it in a background thread.
|
||||||
var invitedMembers: [RoomMemberListScreenEntry] = .init()
|
var invitedMembers: [RoomMemberListScreenEntry] = .init()
|
||||||
var joinedMembers: [RoomMemberListScreenEntry] = .init()
|
var joinedMembers: [RoomMemberListScreenEntry] = .init()
|
||||||
@@ -138,15 +138,15 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
if isEncrypted, let fetchedState = await self?.userIdentityVerificationState(for: member.userID) {
|
if isEncrypted, let fetchedState = await self?.userIdentityVerificationState(for: member.userID) {
|
||||||
verificationState = fetchedState
|
verificationState = fetchedState
|
||||||
}
|
}
|
||||||
let isInCall = activeRoomCallParticipants.contains(member.userID)
|
let isActiveRoomCallParticipant = activeRoomCallParticipants.contains(member.userID)
|
||||||
|
|
||||||
switch member.membership {
|
switch member.membership {
|
||||||
case .invite:
|
case .invite:
|
||||||
invitedMembers.append(.init(member: .init(withProxy: member), verificationState: verificationState, isInCall: isInCall))
|
invitedMembers.append(.init(member: .init(withProxy: member), verificationState: verificationState, isActiveRoomCallParticipant: isActiveRoomCallParticipant))
|
||||||
case .join:
|
case .join:
|
||||||
joinedMembers.append(.init(member: .init(withProxy: member), verificationState: verificationState, isInCall: isInCall))
|
joinedMembers.append(.init(member: .init(withProxy: member), verificationState: verificationState, isActiveRoomCallParticipant: isActiveRoomCallParticipant))
|
||||||
case .ban:
|
case .ban:
|
||||||
bannedMembers.append(.init(member: .init(withProxy: member), verificationState: verificationState, isInCall: isInCall))
|
bannedMembers.append(.init(member: .init(withProxy: member), verificationState: verificationState, isActiveRoomCallParticipant: isActiveRoomCallParticipant))
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -157,10 +157,6 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
bannedMembers: bannedMembers.sorted { $0.member.id.localizedStandardCompare($1.member.id) == .orderedAscending }) // Re-sort ignoring display name.
|
bannedMembers: bannedMembers.sorted { $0.member.id.localizedStandardCompare($1.member.id) == .orderedAscending }) // Re-sort ignoring display name.
|
||||||
}
|
}
|
||||||
.value
|
.value
|
||||||
|
|
||||||
return .init(invitedMembers: membersDetails.invitedMembers,
|
|
||||||
joinedMembers: membersDetails.joinedMembers.filter(\.isInCall) + membersDetails.joinedMembers.filter { !$0.isInCall },
|
|
||||||
bannedMembers: membersDetails.bannedMembers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The client proxy isn't Sendable, fetch identities through this helper so
|
/// The client proxy isn't Sendable, fetch identities through this helper so
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
static let adminViewModel = makeViewModel(isAdmin: true, initialMode: .members)
|
static let adminViewModel = makeViewModel(isAdmin: true, initialMode: .members)
|
||||||
static let bannedViewModel = makeViewModel(isAdmin: true, initialMode: .banned)
|
static let bannedViewModel = makeViewModel(isAdmin: true, initialMode: .banned)
|
||||||
static let emptyBannedViewModel = makeViewModel(withBanned: false, isAdmin: false, initialMode: .members)
|
static let emptyBannedViewModel = makeViewModel(withBanned: false, isAdmin: false, initialMode: .members)
|
||||||
static let adminInCallViewModel = makeViewModel(withInCall: true, isAdmin: true)
|
static let activeRoomCallViewModel = makeViewModel(hasActiveRoomCall: true, isAdmin: true)
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ElementNavigationStack {
|
ElementNavigationStack {
|
||||||
@@ -207,12 +207,12 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
.previewDisplayName("Admin: Banned")
|
.previewDisplayName("Admin: Banned")
|
||||||
|
|
||||||
ElementNavigationStack {
|
ElementNavigationStack {
|
||||||
RoomMembersListScreen(context: adminInCallViewModel.context)
|
RoomMembersListScreen(context: activeRoomCallViewModel.context)
|
||||||
}
|
}
|
||||||
.snapshotPreferences(expect: adminInCallViewModel.context.$viewState.map { state in
|
.snapshotPreferences(expect: activeRoomCallViewModel.context.$viewState.map { state in
|
||||||
state.canBanUsers == true
|
state.canBanUsers == true
|
||||||
})
|
})
|
||||||
.previewDisplayName("Admin: In-Call")
|
.previewDisplayName("Active Room Call")
|
||||||
|
|
||||||
ElementNavigationStack {
|
ElementNavigationStack {
|
||||||
RoomMembersListScreen(context: emptyBannedViewModel.context)
|
RoomMembersListScreen(context: emptyBannedViewModel.context)
|
||||||
@@ -224,7 +224,7 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static func makeViewModel(withInvites: Bool = false,
|
static func makeViewModel(withInvites: Bool = false,
|
||||||
withBanned: Bool = true,
|
withBanned: Bool = true,
|
||||||
withInCall: Bool = false,
|
hasActiveRoomCall: Bool = false,
|
||||||
isAdmin: Bool = false,
|
isAdmin: Bool = false,
|
||||||
initialMode: RoomMembersListScreenMode = .members) -> RoomMembersListScreenViewModel {
|
initialMode: RoomMembersListScreenMode = .members) -> RoomMembersListScreenViewModel {
|
||||||
let mockAdmin = RoomMemberProxyMock.mockAdmin
|
let mockAdmin = RoomMemberProxyMock.mockAdmin
|
||||||
@@ -238,8 +238,7 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
mockAdmin,
|
mockAdmin,
|
||||||
.mockCreator,
|
.mockCreator,
|
||||||
.mockOwner,
|
.mockOwner,
|
||||||
.mockModerator,
|
.mockModerator
|
||||||
.mockFrank
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if withBanned {
|
if withBanned {
|
||||||
@@ -250,9 +249,11 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
members.append(.mockInvited)
|
members.append(.mockInvited)
|
||||||
}
|
}
|
||||||
|
|
||||||
let activeRoomCallParticipants = withInCall ? [RoomMemberProxyMock.mockAlice.userID,
|
let activeRoomCallParticipants: [String] = if hasActiveRoomCall {
|
||||||
RoomMemberProxyMock.mockOwner.userID,
|
[RoomMemberProxyMock.mockAlice.userID, RoomMemberProxyMock.mockOwner.userID, mockAdmin.userID]
|
||||||
mockAdmin.userID] : []
|
} else {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
|
||||||
let clientProxyMock = ClientProxyMock(.init())
|
let clientProxyMock = ClientProxyMock(.init())
|
||||||
clientProxyMock.userIdentityForFallBackToServerClosure = { userID, _ in
|
clientProxyMock.userIdentityForFallBackToServerClosure = { userID, _ in
|
||||||
|
|||||||
+2
-2
@@ -56,7 +56,7 @@ struct RoomMembersListScreenMemberCell: View {
|
|||||||
.foregroundStyle(.compound.textSecondary)
|
.foregroundStyle(.compound.textSecondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
if listEntry.isInCall {
|
if listEntry.isActiveRoomCallParticipant {
|
||||||
CompoundIcon(\.videoCallSolid, size: .small, relativeTo: .compound.bodyLG)
|
CompoundIcon(\.videoCallSolid, size: .small, relativeTo: .compound.bodyLG)
|
||||||
.foregroundStyle(.compound.iconAccentPrimary)
|
.foregroundStyle(.compound.iconAccentPrimary)
|
||||||
.accessibilityLabel(L10n.commonOnACall)
|
.accessibilityLabel(L10n.commonOnACall)
|
||||||
@@ -125,7 +125,7 @@ struct RoomMembersListMemberCell_Previews: PreviewProvider, TestablePreview {
|
|||||||
verificationState: .verificationViolation),
|
verificationState: .verificationViolation),
|
||||||
.init(member: .init(withProxy: RoomMemberProxyMock.mockFrank),
|
.init(member: .init(withProxy: RoomMemberProxyMock.mockFrank),
|
||||||
verificationState: .notVerified,
|
verificationState: .notVerified,
|
||||||
isInCall: true),
|
isActiveRoomCallParticipant: true),
|
||||||
.init(member: .init(withProxy: RoomMemberProxyMock(with: .init(userID: "@nodisplayname:matrix.org",
|
.init(member: .init(withProxy: RoomMemberProxyMock(with: .init(userID: "@nodisplayname:matrix.org",
|
||||||
membership: .join))),
|
membership: .join))),
|
||||||
verificationState: .notVerified),
|
verificationState: .notVerified),
|
||||||
|
|||||||
@@ -49,10 +49,15 @@ nonisolated extension RoomMemberProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nonisolated extension [RoomMemberProxyProtocol] {
|
nonisolated extension [RoomMemberProxyProtocol] {
|
||||||
/// The members, sorted first by power-level, and then alphabetically within each power-level.
|
/// The members, sorted first by call participation, then by power-level, and then alphabetically within each power-level.
|
||||||
func sorted() -> Self {
|
func sorted(prioritisingRoomCallParticipants roomCallParticipants: [String] = []) -> Self {
|
||||||
sorted { lhs, rhs in
|
sorted { lhs, rhs in
|
||||||
if lhs.powerLevel != rhs.powerLevel {
|
let lhsIsRoomCallParticipant = roomCallParticipants.contains(lhs.userID)
|
||||||
|
let rhsIsRoomCallParticipant = roomCallParticipants.contains(rhs.userID)
|
||||||
|
|
||||||
|
return if lhsIsRoomCallParticipant != rhsIsRoomCallParticipant {
|
||||||
|
lhsIsRoomCallParticipant
|
||||||
|
} else if lhs.powerLevel != rhs.powerLevel {
|
||||||
lhs.powerLevel > rhs.powerLevel
|
lhs.powerLevel > rhs.powerLevel
|
||||||
} else {
|
} else {
|
||||||
lhs.sortingName.localizedStandardCompare(rhs.sortingName) == .orderedAscending
|
lhs.sortingName.localizedStandardCompare(rhs.sortingName) == .orderedAscending
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0335c7aa8a403021b86780212554d28f04dc8caba12c56018a2edbbb53b6d373
|
oid sha256:77ae08f13c5ea29c3854bb2b8a6ddbcc8bc82980559c9f50168d5101a5400f83
|
||||||
size 172243
|
size 181974
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1cd812d91a85f54bdd9da4cdefd2ed605a999195bd3be68f9726fdd37fbeda96
|
oid sha256:448beb21d2a8ddbd0e7d0f25b7d0cdd211752ed146fb15bdd7985aa0b6f7b723
|
||||||
size 174277
|
size 183929
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8c52cb2c0a60e202b872c89f6ffb24ded4abc3f63c47794e9ee7bfecb05001d7
|
oid sha256:7e9558139bb02e1a7570e05375e5481ae4de4f6ac3648c8c8a64cd2566543bea
|
||||||
size 116931
|
size 125566
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ba230c28ad61dd3fa5e27e2e5e715e64c399fed072e8a10cb41a1feb06b5edca
|
oid sha256:8662f774ad0e927e88fba3034b2b11f180b8a1e54e5142644bccdd4757d1156b
|
||||||
size 122379
|
size 131231
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ca9c0c8e12a42f3c4ee76dd530e4fb46ef787dbaa15536c234e5694cbe3ddb4b
|
||||||
|
size 160033
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:e7a33ca9f604b6590b0a8478e9e45ae01bb50869a25aecef2652e9da51b71bd7
|
||||||
|
size 168357
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f64664d2c9f8aaa22bfa6f40fe7c2ff7d7e4b435bbb959e5e0b64ff22fad4385
|
||||||
|
size 105723
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f8c95e5f31573e3070bebb6f0b4d4b08595a7b89e4761d0fc7a3b9646c5c105f
|
||||||
|
size 117769
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:18395ebf158fcb6a95c2cb872dfe10c46524c1da11e1dde7606d641d3595dbec
|
|
||||||
size 168947
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:8baf2a6430be90309622852137282670f80acb65c134b954be2f15a68c26db72
|
|
||||||
size 176958
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:bf46ae15f2852960aed8d453219b03082bcc655c076946e66471e16c55b474fd
|
|
||||||
size 113640
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a83fb0e73446c7f567cf320974677ca744b101bdd0d18854d963f4f970329bfd
|
|
||||||
size 124639
|
|
||||||
@@ -68,7 +68,7 @@ struct RoomMembersListScreenViewModelTests {
|
|||||||
let sortedMembers: [RoomMemberListScreenEntry] = [
|
let sortedMembers: [RoomMemberListScreenEntry] = [
|
||||||
.init(member: .init(withProxy: RoomMemberProxyMock.mockFrank),
|
.init(member: .init(withProxy: RoomMemberProxyMock.mockFrank),
|
||||||
verificationState: .notVerified,
|
verificationState: .notVerified,
|
||||||
isInCall: true),
|
isActiveRoomCallParticipant: true),
|
||||||
.init(member: .init(withProxy: RoomMemberProxyMock.mockAdmin),
|
.init(member: .init(withProxy: RoomMemberProxyMock.mockAdmin),
|
||||||
verificationState: .notVerified),
|
verificationState: .notVerified),
|
||||||
.init(member: .init(withProxy: RoomMemberProxyMock.mockAlice),
|
.init(member: .init(withProxy: RoomMemberProxyMock.mockAlice),
|
||||||
|
|||||||
Reference in New Issue
Block a user