diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index cab6beddf..c7e981a70 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -8651,13 +8651,13 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable { return powerLevelsCallsCount > 0 } - var powerLevelsUnderlyingReturnValue: Result! - var powerLevelsReturnValue: Result! { + var powerLevelsUnderlyingReturnValue: Result! + var powerLevelsReturnValue: Result! { get { if Thread.isMainThread { return powerLevelsUnderlyingReturnValue } else { - var returnValue: Result? = nil + var returnValue: Result? = nil DispatchQueue.main.sync { returnValue = powerLevelsUnderlyingReturnValue } @@ -8675,9 +8675,9 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable { } } } - var powerLevelsClosure: (() async -> Result)? + var powerLevelsClosure: (() async -> Result)? - func powerLevels() async -> Result { + func powerLevels() async -> Result { powerLevelsCallsCount += 1 if let powerLevelsClosure = powerLevelsClosure { return await powerLevelsClosure() @@ -13518,11 +13518,7 @@ class RoomInfoProxyMock: RoomInfoProxyProtocol, @unchecked Sendable { set(value) { underlyingHistoryVisibility = value } } var underlyingHistoryVisibility: RoomHistoryVisibility! - var powerLevels: RoomPowerLevelsProxyProtocol { - get { return underlyingPowerLevels } - set(value) { underlyingPowerLevels = value } - } - var underlyingPowerLevels: RoomPowerLevelsProxyProtocol! + var powerLevels: RoomPowerLevelsProxyProtocol? var successor: SuccessorRoom? var heroes: [RoomHero] = [] @@ -13587,6 +13583,7 @@ class RoomPowerLevelsProxyMock: RoomPowerLevelsProxyProtocol, @unchecked Sendabl set(value) { underlyingValues = value } } var underlyingValues: RoomPowerLevelsValues! + var userPowerLevels: [String: Int64] = [:] //MARK: - canOwnUser diff --git a/ElementX/Sources/Screens/KnockRequestsListScreen/KnockRequestsListScreenViewModel.swift b/ElementX/Sources/Screens/KnockRequestsListScreen/KnockRequestsListScreenViewModel.swift index 663a9c29a..4ab609757 100644 --- a/ElementX/Sources/Screens/KnockRequestsListScreen/KnockRequestsListScreenViewModel.swift +++ b/ElementX/Sources/Screens/KnockRequestsListScreen/KnockRequestsListScreenViewModel.swift @@ -218,9 +218,10 @@ class KnockRequestsListScreenViewModel: KnockRequestsListScreenViewModelType, Kn state.isKnockableRoom = false } - state.canAccept = roomInfo.powerLevels.canOwnUserInvite() - state.canDecline = roomInfo.powerLevels.canOwnUserKick() - state.canBan = roomInfo.powerLevels.canOwnUserBan() + guard let powerLevels = roomProxy.infoPublisher.value.powerLevels else { fatalError("Missing room power levels") } + state.canAccept = powerLevels.canOwnUserInvite() + state.canDecline = powerLevels.canOwnUserKick() + state.canBan = powerLevels.canOwnUserBan() } private static let loadingIndicatorIdentifier = "\(KnockRequestsListScreenViewModel.self)-Loading" diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift index 9ca1c5dd8..2d9dda6af 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/RoomDetailsEditScreenViewModel.swift @@ -87,9 +87,10 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe // MARK: - Private private func updateRoomInfo(roomInfo: RoomInfoProxyProtocol) { - state.canEditAvatar = roomInfo.powerLevels.canOwnUser(sendStateEvent: .roomAvatar) - state.canEditName = roomInfo.powerLevels.canOwnUser(sendStateEvent: .roomName) - state.canEditTopic = roomInfo.powerLevels.canOwnUser(sendStateEvent: .roomTopic) + guard let powerLevels = roomInfo.powerLevels else { fatalError("Missing room power levels") } + state.canEditAvatar = powerLevels.canOwnUser(sendStateEvent: .roomAvatar) + state.canEditName = powerLevels.canOwnUser(sendStateEvent: .roomName) + state.canEditTopic = powerLevels.canOwnUser(sendStateEvent: .roomTopic) } private func saveRoomDetails() { diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift index 9d7bf1554..36d90d184 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift @@ -224,13 +224,17 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr state.isKnockableRoom = false } - state.canEditRoomName = roomInfo.powerLevels.canOwnUser(sendStateEvent: .roomName) - state.canEditRoomTopic = roomInfo.powerLevels.canOwnUser(sendStateEvent: .roomTopic) - state.canEditRoomAvatar = roomInfo.powerLevels.canOwnUser(sendStateEvent: .roomAvatar) - state.canInviteUsers = roomInfo.powerLevels.canOwnUserInvite() - state.canKickUsers = roomInfo.powerLevels.canOwnUserKick() - state.canBanUsers = roomInfo.powerLevels.canOwnUserBan() - state.canJoinCall = roomInfo.powerLevels.canOwnUserJoinCall() + if let powerLevels = roomInfo.powerLevels { + state.canEditRoomName = powerLevels.canOwnUser(sendStateEvent: .roomName) + state.canEditRoomTopic = powerLevels.canOwnUser(sendStateEvent: .roomTopic) + state.canEditRoomAvatar = powerLevels.canOwnUser(sendStateEvent: .roomAvatar) + state.canInviteUsers = powerLevels.canOwnUserInvite() + state.canKickUsers = powerLevels.canOwnUserKick() + state.canBanUsers = powerLevels.canOwnUserBan() + state.canJoinCall = powerLevels.canOwnUserJoinCall() + } else { + fatalError("Missing room power levels") + } Task { state.canEditRolesOrPermissions = await (try? roomProxy.suggestedRole(for: roomProxy.ownUserID).get()) == .administrator diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift index 47a816635..350594197 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift @@ -88,6 +88,10 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe Task { showLoadingIndicator(Self.updateStateLoadingIndicatorIdentifier) + defer { + hideLoadingIndicator(Self.updateStateLoadingIndicatorIdentifier) + } + let members = members.sorted() let roomMembersDetails = await buildMembersDetails(members: members) self.members = members @@ -99,12 +103,10 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe bannedMembers: roomMembersDetails.bannedMembers, bindings: state.bindings) - let powerLevels = roomProxy.infoPublisher.value.powerLevels + guard let powerLevels = roomProxy.infoPublisher.value.powerLevels else { fatalError("Missing room power levels") } self.state.canInviteUsers = powerLevels.canOwnUserInvite() self.state.canKickUsers = powerLevels.canOwnUserKick() self.state.canBanUsers = powerLevels.canOwnUserBan() - - hideLoadingIndicator(Self.updateStateLoadingIndicatorIdentifier) } } diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift index 82c894a15..e2db6b0d8 100644 --- a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift @@ -114,7 +114,8 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM // MARK: - Permissions private func updateRoomInfo(roomInfo: RoomInfoProxyProtocol) { - state.permissions = .init(powerLevels: roomInfo.powerLevels.values) + guard let powerLevels = roomInfo.powerLevels else { fatalError("Missing room power levels") } + state.permissions = .init(powerLevels: powerLevels.values) } private func editPermissions(group: RoomRolesAndPermissionsScreenPermissionsGroup) { diff --git a/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/CompletionSuggestionService.swift b/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/CompletionSuggestionService.swift index 2e1311db1..baf75bf3b 100644 --- a/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/CompletionSuggestionService.swift +++ b/ElementX/Sources/Screens/RoomScreen/ComposerToolbar/CompletionSuggestionService.swift @@ -47,7 +47,8 @@ final class CompletionSuggestionService: CompletionSuggestionServiceProtocol { self?.suggestionTriggerSubject.value != nil ? .milliseconds(500) : .milliseconds(0) } - canMentionAllUsers = roomProxy.infoPublisher.value.powerLevels.canOwnUserTriggerRoomNotification() + guard let powerLevels = roomProxy.infoPublisher.value.powerLevels else { fatalError("Missing room power levels") } + canMentionAllUsers = powerLevels.canOwnUserTriggerRoomNotification() } func processTextMessage(_ textMessage: String, selectedRange: NSRange) { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 60786ef5c..27104eef3 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -348,11 +348,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol state.isKnockableRoom = false } - state.canSendMessage = roomInfo.powerLevels.canOwnUser(sendMessage: .roomMessage) - state.canJoinCall = roomInfo.powerLevels.canOwnUserJoinCall() - state.canAcceptKnocks = roomInfo.powerLevels.canOwnUserInvite() - state.canDeclineKnocks = roomInfo.powerLevels.canOwnUserKick() - state.canBan = roomInfo.powerLevels.canOwnUserBan() + guard let powerLevels = roomInfo.powerLevels else { fatalError("Missing room power levels") } + state.canSendMessage = powerLevels.canOwnUser(sendMessage: .roomMessage) + state.canJoinCall = powerLevels.canOwnUserJoinCall() + state.canAcceptKnocks = powerLevels.canOwnUserInvite() + state.canDeclineKnocks = powerLevels.canOwnUserKick() + state.canBan = powerLevels.canOwnUserBan() } private func setupPinnedEventsTimelineItemProviderIfNeeded() { diff --git a/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenViewModel.swift b/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenViewModel.swift index af9a544d1..1a808dfe2 100644 --- a/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenViewModel.swift +++ b/ElementX/Sources/Screens/ThreadTimelineScreen/ThreadTimelineScreenViewModel.swift @@ -63,6 +63,7 @@ class ThreadTimelineScreenViewModel: ThreadTimelineScreenViewModelType, ThreadTi // MARK: - Private private func handleRoomInfoUpdate(_ roomInfo: RoomInfoProxyProtocol) { - state.canSendMessage = roomInfo.powerLevels.canOwnUser(sendMessage: .roomMessage) + guard let powerLevels = roomInfo.powerLevels else { fatalError("Missing room power levels") } + state.canSendMessage = powerLevels.canOwnUser(sendMessage: .roomMessage) } } diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index 850c24c5d..65a588298 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -405,12 +405,13 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { private func updateRoomInfo(roomInfo: RoomInfoProxyProtocol) { state.pinnedEventIDs = roomInfo.pinnedEventIDs - state.canCurrentUserSendMessage = roomInfo.powerLevels.canOwnUser(sendMessage: .roomMessage) - state.canCurrentUserRedactOthers = roomInfo.powerLevels.canOwnUserRedactOther() - state.canCurrentUserRedactSelf = roomInfo.powerLevels.canOwnUserRedactOwn() - state.canCurrentUserPin = roomInfo.powerLevels.canOwnUserPinOrUnpin() - state.canCurrentUserKick = roomInfo.powerLevels.canOwnUserKick() - state.canCurrentUserBan = roomInfo.powerLevels.canOwnUserBan() + guard let powerLevels = roomInfo.powerLevels else { fatalError("Missing room power levels") } + state.canCurrentUserSendMessage = powerLevels.canOwnUser(sendMessage: .roomMessage) + state.canCurrentUserRedactOthers = powerLevels.canOwnUserRedactOther() + state.canCurrentUserRedactSelf = powerLevels.canOwnUserRedactOwn() + state.canCurrentUserPin = powerLevels.canOwnUserPinOrUnpin() + state.canCurrentUserKick = powerLevels.canOwnUserKick() + state.canCurrentUserBan = powerLevels.canOwnUserBan() } private func setupSubscriptions() { diff --git a/ElementX/Sources/Services/Room/JoinedRoomProxy.swift b/ElementX/Sources/Services/Room/JoinedRoomProxy.swift index 0e1fa3074..aedfc07b6 100644 --- a/ElementX/Sources/Services/Room/JoinedRoomProxy.swift +++ b/ElementX/Sources/Services/Room/JoinedRoomProxy.swift @@ -552,7 +552,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol { // MARK: - Power Levels - func powerLevels() async -> Result { + func powerLevels() async -> Result { do { return try await .success(RoomPowerLevelsProxy(room.getPowerLevels())) } catch { diff --git a/ElementX/Sources/Services/Room/RoomInfoProxy.swift b/ElementX/Sources/Services/Room/RoomInfoProxy.swift index c4af9e950..0b176d84e 100644 --- a/ElementX/Sources/Services/Room/RoomInfoProxy.swift +++ b/ElementX/Sources/Services/Room/RoomInfoProxy.swift @@ -53,7 +53,7 @@ struct RoomInfoProxy: RoomInfoProxyProtocol { var joinRule: JoinRule? { roomInfo.joinRule } var historyVisibility: RoomHistoryVisibility { roomInfo.historyVisibility } - var powerLevels: RoomPowerLevelsProxyProtocol { RoomPowerLevelsProxy(roomInfo.powerLevels) } + var powerLevels: RoomPowerLevelsProxyProtocol? { RoomPowerLevelsProxy(roomInfo.powerLevels) } } struct RoomPreviewInfoProxy: BaseRoomInfoProxyProtocol { diff --git a/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift index fc6147f1a..df64cb7ce 100644 --- a/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift @@ -63,7 +63,7 @@ protocol RoomInfoProxyProtocol: BaseRoomInfoProxyProtocol { var joinRule: JoinRule? { get } var historyVisibility: RoomHistoryVisibility { get } - var powerLevels: RoomPowerLevelsProxyProtocol { get } + var powerLevels: RoomPowerLevelsProxyProtocol? { get } } extension BaseRoomInfoProxyProtocol { diff --git a/ElementX/Sources/Services/Room/RoomPowerLevelProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomPowerLevelProxyProtocol.swift index ac25cdafa..fd69b2238 100644 --- a/ElementX/Sources/Services/Room/RoomPowerLevelProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomPowerLevelProxyProtocol.swift @@ -11,6 +11,8 @@ import MatrixRustSDK protocol RoomPowerLevelsProxyProtocol { var values: RoomPowerLevelsValues { get } + var userPowerLevels: [String: Int64] { get } + func canOwnUser(sendMessage messageType: MessageLikeEventType) -> Bool func canOwnUser(sendStateEvent event: StateEventType) -> Bool func canOwnUserInvite() -> Bool diff --git a/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift b/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift index ae000502e..5efb0bcd3 100644 --- a/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift +++ b/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift @@ -10,7 +10,11 @@ import MatrixRustSDK struct RoomPowerLevelsProxy: RoomPowerLevelsProxyProtocol { private let powerLevels: RoomPowerLevels - init(_ powerLevels: RoomPowerLevels) { + init?(_ powerLevels: RoomPowerLevels?) { + guard let powerLevels else { + return nil + } + self.powerLevels = powerLevels } @@ -18,6 +22,10 @@ struct RoomPowerLevelsProxy: RoomPowerLevelsProxyProtocol { powerLevels.values() } + var userPowerLevels: [String: Int64] { + powerLevels.userPowerLevels() + } + func canOwnUser(sendMessage messageType: MessageLikeEventType) -> Bool { powerLevels.canOwnUserSendMessage(message: messageType) } diff --git a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift index dec47786a..9478c7f43 100644 --- a/ElementX/Sources/Services/Room/RoomProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomProxyProtocol.swift @@ -152,7 +152,7 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol { // MARK: - Power Levels - func powerLevels() async -> Result + func powerLevels() async -> Result func applyPowerLevelChanges(_ changes: RoomPowerLevelChanges) async -> Result func resetPowerLevels() async -> Result func suggestedRole(for userID: String) async -> Result