mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-11 13:59:13 +00:00
Replace individual RoomProxy properties with a stored RoomInfo. (#3445)
* Store RoomInfo updates in JoinedRoomProxy and read from them directly. * Remove all RoomProxy properties that were reading from the RoomInfo.
This commit is contained in:
parent
7c28d9709f
commit
7c75498b4d
@ -412,6 +412,7 @@
|
|||||||
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
||||||
5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
|
5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
|
||||||
5C164551F7D26E24F09083D3 /* StaticLocationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */; };
|
5C164551F7D26E24F09083D3 /* StaticLocationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */; };
|
||||||
|
5C8804B4F25903516E2DAB81 /* RoomInfoProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40A66E8BC8D9AE4A08EFB2DF /* RoomInfoProxy.swift */; };
|
||||||
5D27B6537591471A42C89027 /* EmoteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450E04B2A976CC4C8CC1807C /* EmoteRoomTimelineItem.swift */; };
|
5D27B6537591471A42C89027 /* EmoteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450E04B2A976CC4C8CC1807C /* EmoteRoomTimelineItem.swift */; };
|
||||||
5D52925FEB1B780C65B0529F /* PinnedEventsTimelineScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4F6D7000EDCD187E0989E7 /* PinnedEventsTimelineScreen.swift */; };
|
5D52925FEB1B780C65B0529F /* PinnedEventsTimelineScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4F6D7000EDCD187E0989E7 /* PinnedEventsTimelineScreen.swift */; };
|
||||||
5D53AE9342A4C06B704247ED /* MediaLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */; };
|
5D53AE9342A4C06B704247ED /* MediaLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */; };
|
||||||
@ -1495,6 +1496,7 @@
|
|||||||
40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageMediaManager.swift; sourceTree = "<group>"; };
|
40076C770A5FB83325252973 /* VoiceMessageMediaManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageMediaManager.swift; sourceTree = "<group>"; };
|
||||||
40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModelTests.swift; sourceTree = "<group>"; };
|
40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
406C90AF8C3E98DF5D4E5430 /* ElementCallServiceConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallServiceConstants.swift; sourceTree = "<group>"; };
|
406C90AF8C3E98DF5D4E5430 /* ElementCallServiceConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallServiceConstants.swift; sourceTree = "<group>"; };
|
||||||
|
40A66E8BC8D9AE4A08EFB2DF /* RoomInfoProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomInfoProxy.swift; sourceTree = "<group>"; };
|
||||||
40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
||||||
4100DDE6BF3C566AB66B80CC /* MentionSuggestionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSuggestionItemView.swift; sourceTree = "<group>"; };
|
4100DDE6BF3C566AB66B80CC /* MentionSuggestionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSuggestionItemView.swift; sourceTree = "<group>"; };
|
||||||
4137900E28201C314C835C11 /* RoomScreenFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenFooterView.swift; sourceTree = "<group>"; };
|
4137900E28201C314C835C11 /* RoomScreenFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenFooterView.swift; sourceTree = "<group>"; };
|
||||||
@ -3211,6 +3213,7 @@
|
|||||||
07C6B0B087FE6601C3F77816 /* JoinedRoomProxy.swift */,
|
07C6B0B087FE6601C3F77816 /* JoinedRoomProxy.swift */,
|
||||||
858DA81F2ACF484B7CAD6AE4 /* KnockedRoomProxy.swift */,
|
858DA81F2ACF484B7CAD6AE4 /* KnockedRoomProxy.swift */,
|
||||||
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */,
|
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */,
|
||||||
|
40A66E8BC8D9AE4A08EFB2DF /* RoomInfoProxy.swift */,
|
||||||
974AEAF3FE0C577A6C04AD6E /* RoomPermissions.swift */,
|
974AEAF3FE0C577A6C04AD6E /* RoomPermissions.swift */,
|
||||||
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */,
|
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */,
|
||||||
2C0F49BD446849654C0D24E0 /* RoomMember */,
|
2C0F49BD446849654C0D24E0 /* RoomMember */,
|
||||||
@ -6775,6 +6778,7 @@
|
|||||||
42F1C8731166633E35A6D7E6 /* RoomEventStringBuilder.swift in Sources */,
|
42F1C8731166633E35A6D7E6 /* RoomEventStringBuilder.swift in Sources */,
|
||||||
D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */,
|
D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */,
|
||||||
9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */,
|
9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */,
|
||||||
|
5C8804B4F25903516E2DAB81 /* RoomInfoProxy.swift in Sources */,
|
||||||
8A83D715940378B9BA9F739E /* RoomInviterLabel.swift in Sources */,
|
8A83D715940378B9BA9F739E /* RoomInviterLabel.swift in Sources */,
|
||||||
F4996C82A4B3A5FF0C8EDD03 /* RoomListFilterModels.swift in Sources */,
|
F4996C82A4B3A5FF0C8EDD03 /* RoomListFilterModels.swift in Sources */,
|
||||||
4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */,
|
4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */,
|
||||||
|
@ -584,7 +584,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
timelineItemFactory: timelineItemFactory)
|
timelineItemFactory: timelineItemFactory)
|
||||||
self.timelineController = timelineController
|
self.timelineController = timelineController
|
||||||
|
|
||||||
analytics.trackViewRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace)
|
analytics.trackViewRoom(isDM: roomProxy.infoPublisher.value.isDirect, isSpace: roomProxy.infoPublisher.value.isSpace)
|
||||||
|
|
||||||
let completionSuggestionService = CompletionSuggestionService(roomProxy: roomProxy)
|
let completionSuggestionService = CompletionSuggestionService(roomProxy: roomProxy)
|
||||||
|
|
||||||
@ -681,7 +681,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
await storeAndSubscribeToRoomProxy(roomProxy)
|
await storeAndSubscribeToRoomProxy(roomProxy)
|
||||||
stateMachine.tryEvent(.presentRoom(focussedEvent: nil), userInfo: EventUserInfo(animated: animated))
|
stateMachine.tryEvent(.presentRoom(focussedEvent: nil), userInfo: EventUserInfo(animated: animated))
|
||||||
|
|
||||||
analytics.trackJoinedRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace, activeMemberCount: UInt(roomProxy.activeMembersCount))
|
analytics.trackJoinedRoom(isDM: roomProxy.infoPublisher.value.isDirect,
|
||||||
|
isSpace: roomProxy.infoPublisher.value.isSpace,
|
||||||
|
activeMemberCount: UInt(roomProxy.infoPublisher.value.activeMembersCount))
|
||||||
} else {
|
} else {
|
||||||
stateMachine.tryEvent(.dismissFlow, userInfo: EventUserInfo(animated: animated))
|
stateMachine.tryEvent(.dismissFlow, userInfo: EventUserInfo(animated: animated))
|
||||||
}
|
}
|
||||||
|
@ -5824,67 +5824,21 @@ class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class InvitedRoomProxyMock: InvitedRoomProxyProtocol {
|
class InvitedRoomProxyMock: InvitedRoomProxyProtocol {
|
||||||
var inviterCallsCount = 0
|
var info: RoomInfoProxy {
|
||||||
var inviterCalled: Bool {
|
get { return underlyingInfo }
|
||||||
return inviterCallsCount > 0
|
set(value) { underlyingInfo = value }
|
||||||
}
|
}
|
||||||
|
var underlyingInfo: RoomInfoProxy!
|
||||||
var inviter: RoomMemberProxyProtocol? {
|
|
||||||
get async {
|
|
||||||
inviterCallsCount += 1
|
|
||||||
if let inviterClosure = inviterClosure {
|
|
||||||
return await inviterClosure()
|
|
||||||
} else {
|
|
||||||
return underlyingInviter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var underlyingInviter: RoomMemberProxyProtocol?
|
|
||||||
var inviterClosure: (() async -> RoomMemberProxyProtocol?)?
|
|
||||||
var id: String {
|
var id: String {
|
||||||
get { return underlyingId }
|
get { return underlyingId }
|
||||||
set(value) { underlyingId = value }
|
set(value) { underlyingId = value }
|
||||||
}
|
}
|
||||||
var underlyingId: String!
|
var underlyingId: String!
|
||||||
var canonicalAlias: String?
|
|
||||||
var ownUserID: String {
|
var ownUserID: String {
|
||||||
get { return underlyingOwnUserID }
|
get { return underlyingOwnUserID }
|
||||||
set(value) { underlyingOwnUserID = value }
|
set(value) { underlyingOwnUserID = value }
|
||||||
}
|
}
|
||||||
var underlyingOwnUserID: String!
|
var underlyingOwnUserID: String!
|
||||||
var name: String?
|
|
||||||
var topic: String?
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
get { return underlyingAvatar }
|
|
||||||
set(value) { underlyingAvatar = value }
|
|
||||||
}
|
|
||||||
var underlyingAvatar: RoomAvatar!
|
|
||||||
var avatarURL: URL?
|
|
||||||
var isPublic: Bool {
|
|
||||||
get { return underlyingIsPublic }
|
|
||||||
set(value) { underlyingIsPublic = value }
|
|
||||||
}
|
|
||||||
var underlyingIsPublic: Bool!
|
|
||||||
var isDirect: Bool {
|
|
||||||
get { return underlyingIsDirect }
|
|
||||||
set(value) { underlyingIsDirect = value }
|
|
||||||
}
|
|
||||||
var underlyingIsDirect: Bool!
|
|
||||||
var isSpace: Bool {
|
|
||||||
get { return underlyingIsSpace }
|
|
||||||
set(value) { underlyingIsSpace = value }
|
|
||||||
}
|
|
||||||
var underlyingIsSpace: Bool!
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
get { return underlyingJoinedMembersCount }
|
|
||||||
set(value) { underlyingJoinedMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingJoinedMembersCount: Int!
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
get { return underlyingActiveMembersCount }
|
|
||||||
set(value) { underlyingActiveMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingActiveMembersCount: Int!
|
|
||||||
|
|
||||||
//MARK: - rejectInvitation
|
//MARK: - rejectInvitation
|
||||||
|
|
||||||
@ -6021,46 +5975,11 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol {
|
|||||||
set(value) { underlyingIsEncrypted = value }
|
set(value) { underlyingIsEncrypted = value }
|
||||||
}
|
}
|
||||||
var underlyingIsEncrypted: Bool!
|
var underlyingIsEncrypted: Bool!
|
||||||
var isFavouriteCallsCount = 0
|
var infoPublisher: CurrentValuePublisher<RoomInfoProxy, Never> {
|
||||||
var isFavouriteCalled: Bool {
|
get { return underlyingInfoPublisher }
|
||||||
return isFavouriteCallsCount > 0
|
set(value) { underlyingInfoPublisher = value }
|
||||||
}
|
}
|
||||||
|
var underlyingInfoPublisher: CurrentValuePublisher<RoomInfoProxy, Never>!
|
||||||
var isFavourite: Bool {
|
|
||||||
get async {
|
|
||||||
isFavouriteCallsCount += 1
|
|
||||||
if let isFavouriteClosure = isFavouriteClosure {
|
|
||||||
return await isFavouriteClosure()
|
|
||||||
} else {
|
|
||||||
return underlyingIsFavourite
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var underlyingIsFavourite: Bool!
|
|
||||||
var isFavouriteClosure: (() async -> Bool)?
|
|
||||||
var pinnedEventIDsCallsCount = 0
|
|
||||||
var pinnedEventIDsCalled: Bool {
|
|
||||||
return pinnedEventIDsCallsCount > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var pinnedEventIDs: Set<String> {
|
|
||||||
get async {
|
|
||||||
pinnedEventIDsCallsCount += 1
|
|
||||||
if let pinnedEventIDsClosure = pinnedEventIDsClosure {
|
|
||||||
return await pinnedEventIDsClosure()
|
|
||||||
} else {
|
|
||||||
return underlyingPinnedEventIDs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var underlyingPinnedEventIDs: Set<String>!
|
|
||||||
var pinnedEventIDsClosure: (() async -> Set<String>)?
|
|
||||||
var hasOngoingCall: Bool {
|
|
||||||
get { return underlyingHasOngoingCall }
|
|
||||||
set(value) { underlyingHasOngoingCall = value }
|
|
||||||
}
|
|
||||||
var underlyingHasOngoingCall: Bool!
|
|
||||||
var activeRoomCallParticipants: [String] = []
|
|
||||||
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
||||||
get { return underlyingMembersPublisher }
|
get { return underlyingMembersPublisher }
|
||||||
set(value) { underlyingMembersPublisher = value }
|
set(value) { underlyingMembersPublisher = value }
|
||||||
@ -6076,11 +5995,6 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol {
|
|||||||
set(value) { underlyingIdentityStatusChangesPublisher = value }
|
set(value) { underlyingIdentityStatusChangesPublisher = value }
|
||||||
}
|
}
|
||||||
var underlyingIdentityStatusChangesPublisher: CurrentValuePublisher<[IdentityStatusChange], Never>!
|
var underlyingIdentityStatusChangesPublisher: CurrentValuePublisher<[IdentityStatusChange], Never>!
|
||||||
var actionsPublisher: AnyPublisher<JoinedRoomProxyAction, Never> {
|
|
||||||
get { return underlyingActionsPublisher }
|
|
||||||
set(value) { underlyingActionsPublisher = value }
|
|
||||||
}
|
|
||||||
var underlyingActionsPublisher: AnyPublisher<JoinedRoomProxyAction, Never>!
|
|
||||||
var timeline: TimelineProxyProtocol {
|
var timeline: TimelineProxyProtocol {
|
||||||
get { return underlyingTimeline }
|
get { return underlyingTimeline }
|
||||||
set(value) { underlyingTimeline = value }
|
set(value) { underlyingTimeline = value }
|
||||||
@ -6108,45 +6022,11 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol {
|
|||||||
set(value) { underlyingId = value }
|
set(value) { underlyingId = value }
|
||||||
}
|
}
|
||||||
var underlyingId: String!
|
var underlyingId: String!
|
||||||
var canonicalAlias: String?
|
|
||||||
var ownUserID: String {
|
var ownUserID: String {
|
||||||
get { return underlyingOwnUserID }
|
get { return underlyingOwnUserID }
|
||||||
set(value) { underlyingOwnUserID = value }
|
set(value) { underlyingOwnUserID = value }
|
||||||
}
|
}
|
||||||
var underlyingOwnUserID: String!
|
var underlyingOwnUserID: String!
|
||||||
var name: String?
|
|
||||||
var topic: String?
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
get { return underlyingAvatar }
|
|
||||||
set(value) { underlyingAvatar = value }
|
|
||||||
}
|
|
||||||
var underlyingAvatar: RoomAvatar!
|
|
||||||
var avatarURL: URL?
|
|
||||||
var isPublic: Bool {
|
|
||||||
get { return underlyingIsPublic }
|
|
||||||
set(value) { underlyingIsPublic = value }
|
|
||||||
}
|
|
||||||
var underlyingIsPublic: Bool!
|
|
||||||
var isDirect: Bool {
|
|
||||||
get { return underlyingIsDirect }
|
|
||||||
set(value) { underlyingIsDirect = value }
|
|
||||||
}
|
|
||||||
var underlyingIsDirect: Bool!
|
|
||||||
var isSpace: Bool {
|
|
||||||
get { return underlyingIsSpace }
|
|
||||||
set(value) { underlyingIsSpace = value }
|
|
||||||
}
|
|
||||||
var underlyingIsSpace: Bool!
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
get { return underlyingJoinedMembersCount }
|
|
||||||
set(value) { underlyingJoinedMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingJoinedMembersCount: Int!
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
get { return underlyingActiveMembersCount }
|
|
||||||
set(value) { underlyingActiveMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingActiveMembersCount: Int!
|
|
||||||
|
|
||||||
//MARK: - subscribeForUpdates
|
//MARK: - subscribeForUpdates
|
||||||
|
|
||||||
@ -9752,50 +9632,21 @@ class KeychainControllerMock: KeychainControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class KnockedRoomProxyMock: KnockedRoomProxyProtocol {
|
class KnockedRoomProxyMock: KnockedRoomProxyProtocol {
|
||||||
|
var info: RoomInfoProxy {
|
||||||
|
get { return underlyingInfo }
|
||||||
|
set(value) { underlyingInfo = value }
|
||||||
|
}
|
||||||
|
var underlyingInfo: RoomInfoProxy!
|
||||||
var id: String {
|
var id: String {
|
||||||
get { return underlyingId }
|
get { return underlyingId }
|
||||||
set(value) { underlyingId = value }
|
set(value) { underlyingId = value }
|
||||||
}
|
}
|
||||||
var underlyingId: String!
|
var underlyingId: String!
|
||||||
var canonicalAlias: String?
|
|
||||||
var ownUserID: String {
|
var ownUserID: String {
|
||||||
get { return underlyingOwnUserID }
|
get { return underlyingOwnUserID }
|
||||||
set(value) { underlyingOwnUserID = value }
|
set(value) { underlyingOwnUserID = value }
|
||||||
}
|
}
|
||||||
var underlyingOwnUserID: String!
|
var underlyingOwnUserID: String!
|
||||||
var name: String?
|
|
||||||
var topic: String?
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
get { return underlyingAvatar }
|
|
||||||
set(value) { underlyingAvatar = value }
|
|
||||||
}
|
|
||||||
var underlyingAvatar: RoomAvatar!
|
|
||||||
var avatarURL: URL?
|
|
||||||
var isPublic: Bool {
|
|
||||||
get { return underlyingIsPublic }
|
|
||||||
set(value) { underlyingIsPublic = value }
|
|
||||||
}
|
|
||||||
var underlyingIsPublic: Bool!
|
|
||||||
var isDirect: Bool {
|
|
||||||
get { return underlyingIsDirect }
|
|
||||||
set(value) { underlyingIsDirect = value }
|
|
||||||
}
|
|
||||||
var underlyingIsDirect: Bool!
|
|
||||||
var isSpace: Bool {
|
|
||||||
get { return underlyingIsSpace }
|
|
||||||
set(value) { underlyingIsSpace = value }
|
|
||||||
}
|
|
||||||
var underlyingIsSpace: Bool!
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
get { return underlyingJoinedMembersCount }
|
|
||||||
set(value) { underlyingJoinedMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingJoinedMembersCount: Int!
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
get { return underlyingActiveMembersCount }
|
|
||||||
set(value) { underlyingActiveMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingActiveMembersCount: Int!
|
|
||||||
|
|
||||||
//MARK: - cancelKnock
|
//MARK: - cancelKnock
|
||||||
|
|
||||||
@ -12934,45 +12785,11 @@ class RoomProxyMock: RoomProxyProtocol {
|
|||||||
set(value) { underlyingId = value }
|
set(value) { underlyingId = value }
|
||||||
}
|
}
|
||||||
var underlyingId: String!
|
var underlyingId: String!
|
||||||
var canonicalAlias: String?
|
|
||||||
var ownUserID: String {
|
var ownUserID: String {
|
||||||
get { return underlyingOwnUserID }
|
get { return underlyingOwnUserID }
|
||||||
set(value) { underlyingOwnUserID = value }
|
set(value) { underlyingOwnUserID = value }
|
||||||
}
|
}
|
||||||
var underlyingOwnUserID: String!
|
var underlyingOwnUserID: String!
|
||||||
var name: String?
|
|
||||||
var topic: String?
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
get { return underlyingAvatar }
|
|
||||||
set(value) { underlyingAvatar = value }
|
|
||||||
}
|
|
||||||
var underlyingAvatar: RoomAvatar!
|
|
||||||
var avatarURL: URL?
|
|
||||||
var isPublic: Bool {
|
|
||||||
get { return underlyingIsPublic }
|
|
||||||
set(value) { underlyingIsPublic = value }
|
|
||||||
}
|
|
||||||
var underlyingIsPublic: Bool!
|
|
||||||
var isDirect: Bool {
|
|
||||||
get { return underlyingIsDirect }
|
|
||||||
set(value) { underlyingIsDirect = value }
|
|
||||||
}
|
|
||||||
var underlyingIsDirect: Bool!
|
|
||||||
var isSpace: Bool {
|
|
||||||
get { return underlyingIsSpace }
|
|
||||||
set(value) { underlyingIsSpace = value }
|
|
||||||
}
|
|
||||||
var underlyingIsSpace: Bool!
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
get { return underlyingJoinedMembersCount }
|
|
||||||
set(value) { underlyingJoinedMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingJoinedMembersCount: Int!
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
get { return underlyingActiveMembersCount }
|
|
||||||
set(value) { underlyingActiveMembersCount = value }
|
|
||||||
}
|
|
||||||
var underlyingActiveMembersCount: Int!
|
|
||||||
|
|
||||||
}
|
}
|
||||||
class RoomSummaryProviderMock: RoomSummaryProviderProtocol {
|
class RoomSummaryProviderMock: RoomSummaryProviderProtocol {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
struct InvitedRoomProxyMockConfiguration {
|
struct InvitedRoomProxyMockConfiguration {
|
||||||
@ -22,10 +23,55 @@ extension InvitedRoomProxyMock {
|
|||||||
convenience init(_ configuration: InvitedRoomProxyMockConfiguration) {
|
convenience init(_ configuration: InvitedRoomProxyMockConfiguration) {
|
||||||
self.init()
|
self.init()
|
||||||
id = configuration.id
|
id = configuration.id
|
||||||
name = configuration.name
|
info = RoomInfoProxy(roomInfo: .init(configuration))
|
||||||
avatarURL = configuration.avatarURL
|
}
|
||||||
avatar = .room(id: configuration.id, name: configuration.name, avatarURL: configuration.avatarURL) // Note: This doesn't replicate the real proxy logic.
|
}
|
||||||
underlyingInviter = configuration.inviter
|
|
||||||
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
|
extension RoomInfo {
|
||||||
|
@MainActor init(_ configuration: InvitedRoomProxyMockConfiguration) {
|
||||||
|
self.init(id: configuration.id,
|
||||||
|
creator: nil,
|
||||||
|
displayName: configuration.name,
|
||||||
|
rawName: nil,
|
||||||
|
topic: nil,
|
||||||
|
avatarUrl: configuration.avatarURL?.absoluteString,
|
||||||
|
isDirect: false,
|
||||||
|
isPublic: false,
|
||||||
|
isSpace: false,
|
||||||
|
isTombstoned: false,
|
||||||
|
isFavourite: false,
|
||||||
|
canonicalAlias: nil,
|
||||||
|
alternativeAliases: [],
|
||||||
|
membership: .knocked,
|
||||||
|
inviter: .init(configuration.inviter),
|
||||||
|
heroes: [],
|
||||||
|
activeMembersCount: UInt64(configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count),
|
||||||
|
invitedMembersCount: UInt64(configuration.members.filter { $0.membership == .invite }.count),
|
||||||
|
joinedMembersCount: UInt64(configuration.members.filter { $0.membership == .join }.count),
|
||||||
|
userPowerLevels: [:],
|
||||||
|
highlightCount: 0,
|
||||||
|
notificationCount: 0,
|
||||||
|
cachedUserDefinedNotificationMode: nil,
|
||||||
|
hasRoomCall: false,
|
||||||
|
activeRoomCallParticipants: [],
|
||||||
|
isMarkedUnread: false,
|
||||||
|
numUnreadMessages: 0,
|
||||||
|
numUnreadNotifications: 0,
|
||||||
|
numUnreadMentions: 0,
|
||||||
|
pinnedEventIds: [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension RoomMember {
|
||||||
|
init(_ proxy: RoomMemberProxyProtocol) {
|
||||||
|
self.init(userId: proxy.userID,
|
||||||
|
displayName: proxy.displayName,
|
||||||
|
avatarUrl: proxy.avatarURL?.absoluteString,
|
||||||
|
membership: proxy.membership,
|
||||||
|
isNameAmbiguous: proxy.disambiguatedDisplayName != proxy.displayName,
|
||||||
|
powerLevel: Int64(proxy.powerLevel),
|
||||||
|
normalizedPowerLevel: Int64(proxy.powerLevel),
|
||||||
|
isIgnored: proxy.isIgnored,
|
||||||
|
suggestedRoleForPowerLevel: proxy.role)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
enum RoomProxyMockError: Error {
|
enum RoomProxyMockError: Error {
|
||||||
case generic
|
case generic
|
||||||
@ -46,18 +47,7 @@ extension JoinedRoomProxyMock {
|
|||||||
self.init()
|
self.init()
|
||||||
|
|
||||||
id = configuration.id
|
id = configuration.id
|
||||||
name = configuration.name
|
|
||||||
topic = configuration.topic
|
|
||||||
avatar = .room(id: configuration.id, name: configuration.name, avatarURL: configuration.avatarURL) // Note: This doesn't replicate the real proxy logic.
|
|
||||||
avatarURL = configuration.avatarURL
|
|
||||||
isDirect = configuration.isDirect
|
|
||||||
isSpace = configuration.isSpace
|
|
||||||
isPublic = configuration.isPublic
|
|
||||||
isEncrypted = configuration.isEncrypted
|
isEncrypted = configuration.isEncrypted
|
||||||
hasOngoingCall = configuration.hasOngoingCall
|
|
||||||
canonicalAlias = configuration.canonicalAlias
|
|
||||||
|
|
||||||
underlyingPinnedEventIDs = configuration.pinnedEventIDs
|
|
||||||
|
|
||||||
let timeline = TimelineProxyMock()
|
let timeline = TimelineProxyMock()
|
||||||
timeline.sendMessageEventContentReturnValue = .success(())
|
timeline.sendMessageEventContentReturnValue = .success(())
|
||||||
@ -78,15 +68,12 @@ extension JoinedRoomProxyMock {
|
|||||||
|
|
||||||
ownUserID = configuration.ownUserID
|
ownUserID = configuration.ownUserID
|
||||||
|
|
||||||
|
infoPublisher = CurrentValueSubject(.init(roomInfo: .init(configuration))).asCurrentValuePublisher()
|
||||||
membersPublisher = CurrentValueSubject(configuration.members).asCurrentValuePublisher()
|
membersPublisher = CurrentValueSubject(configuration.members).asCurrentValuePublisher()
|
||||||
typingMembersPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
typingMembersPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
||||||
identityStatusChangesPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
identityStatusChangesPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
||||||
|
|
||||||
joinedMembersCount = configuration.members.filter { $0.membership == .join }.count
|
|
||||||
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
|
|
||||||
|
|
||||||
updateMembersClosure = { }
|
updateMembersClosure = { }
|
||||||
underlyingActionsPublisher = Empty(completeImmediately: false).eraseToAnyPublisher()
|
|
||||||
setNameClosure = { _ in .success(()) }
|
setNameClosure = { _ in .success(()) }
|
||||||
setTopicClosure = { _ in .success(()) }
|
setTopicClosure = { _ in .success(()) }
|
||||||
getMemberUserIDClosure = { [weak self] userID in
|
getMemberUserIDClosure = { [weak self] userID in
|
||||||
@ -102,7 +89,6 @@ extension JoinedRoomProxyMock {
|
|||||||
|
|
||||||
flagAsUnreadReturnValue = .success(())
|
flagAsUnreadReturnValue = .success(())
|
||||||
markAsReadReceiptTypeReturnValue = .success(())
|
markAsReadReceiptTypeReturnValue = .success(())
|
||||||
underlyingIsFavourite = false
|
|
||||||
flagAsFavouriteReturnValue = .success(())
|
flagAsFavouriteReturnValue = .success(())
|
||||||
|
|
||||||
powerLevelsReturnValue = .success(.mock)
|
powerLevelsReturnValue = .success(.mock)
|
||||||
@ -154,3 +140,46 @@ extension JoinedRoomProxyMock {
|
|||||||
clearDraftReturnValue = .success(())
|
clearDraftReturnValue = .success(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension RoomInfo {
|
||||||
|
@MainActor init(_ configuration: JoinedRoomProxyMockConfiguration) {
|
||||||
|
self.init(id: configuration.id,
|
||||||
|
creator: nil,
|
||||||
|
displayName: configuration.name,
|
||||||
|
rawName: configuration.name,
|
||||||
|
topic: configuration.topic,
|
||||||
|
avatarUrl: configuration.avatarURL?.absoluteString,
|
||||||
|
isDirect: configuration.isDirect,
|
||||||
|
isPublic: configuration.isPublic,
|
||||||
|
isSpace: configuration.isSpace,
|
||||||
|
isTombstoned: false,
|
||||||
|
isFavourite: false,
|
||||||
|
canonicalAlias: configuration.canonicalAlias,
|
||||||
|
alternativeAliases: [],
|
||||||
|
membership: .joined,
|
||||||
|
inviter: configuration.inviter.map { RoomMember(userId: $0.userID,
|
||||||
|
displayName: $0.displayName,
|
||||||
|
avatarUrl: $0.avatarURL?.absoluteString,
|
||||||
|
membership: $0.membership,
|
||||||
|
isNameAmbiguous: false,
|
||||||
|
powerLevel: Int64($0.powerLevel),
|
||||||
|
normalizedPowerLevel: Int64($0.powerLevel),
|
||||||
|
isIgnored: $0.isIgnored,
|
||||||
|
suggestedRoleForPowerLevel: $0.role) },
|
||||||
|
heroes: [],
|
||||||
|
activeMembersCount: UInt64(configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count),
|
||||||
|
invitedMembersCount: UInt64(configuration.members.filter { $0.membership == .invite }.count),
|
||||||
|
joinedMembersCount: UInt64(configuration.members.filter { $0.membership == .join }.count),
|
||||||
|
userPowerLevels: [:],
|
||||||
|
highlightCount: 0,
|
||||||
|
notificationCount: 0,
|
||||||
|
cachedUserDefinedNotificationMode: .allMessages,
|
||||||
|
hasRoomCall: configuration.hasOngoingCall,
|
||||||
|
activeRoomCallParticipants: [],
|
||||||
|
isMarkedUnread: false,
|
||||||
|
numUnreadMessages: 0,
|
||||||
|
numUnreadNotifications: 0,
|
||||||
|
numUnreadMentions: 0,
|
||||||
|
pinnedEventIds: Array(configuration.pinnedEventIDs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
struct KnockedRoomProxyMockConfiguration {
|
struct KnockedRoomProxyMockConfiguration {
|
||||||
@ -21,9 +22,41 @@ extension KnockedRoomProxyMock {
|
|||||||
convenience init(_ configuration: KnockedRoomProxyMockConfiguration) {
|
convenience init(_ configuration: KnockedRoomProxyMockConfiguration) {
|
||||||
self.init()
|
self.init()
|
||||||
id = configuration.id
|
id = configuration.id
|
||||||
name = configuration.name
|
info = RoomInfoProxy(roomInfo: .init(configuration))
|
||||||
avatarURL = configuration.avatarURL
|
}
|
||||||
avatar = .room(id: configuration.id, name: configuration.name, avatarURL: configuration.avatarURL) // Note: This doesn't replicate the real proxy logic.
|
}
|
||||||
activeMembersCount = configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count
|
|
||||||
|
extension RoomInfo {
|
||||||
|
@MainActor init(_ configuration: KnockedRoomProxyMockConfiguration) {
|
||||||
|
self.init(id: configuration.id,
|
||||||
|
creator: nil,
|
||||||
|
displayName: configuration.name,
|
||||||
|
rawName: nil,
|
||||||
|
topic: nil,
|
||||||
|
avatarUrl: configuration.avatarURL?.absoluteString,
|
||||||
|
isDirect: false,
|
||||||
|
isPublic: false,
|
||||||
|
isSpace: false,
|
||||||
|
isTombstoned: false,
|
||||||
|
isFavourite: false,
|
||||||
|
canonicalAlias: nil,
|
||||||
|
alternativeAliases: [],
|
||||||
|
membership: .knocked,
|
||||||
|
inviter: nil,
|
||||||
|
heroes: [],
|
||||||
|
activeMembersCount: UInt64(configuration.members.filter { $0.membership == .join || $0.membership == .invite }.count),
|
||||||
|
invitedMembersCount: UInt64(configuration.members.filter { $0.membership == .invite }.count),
|
||||||
|
joinedMembersCount: UInt64(configuration.members.filter { $0.membership == .join }.count),
|
||||||
|
userPowerLevels: [:],
|
||||||
|
highlightCount: 0,
|
||||||
|
notificationCount: 0,
|
||||||
|
cachedUserDefinedNotificationMode: nil,
|
||||||
|
hasRoomCall: false,
|
||||||
|
activeRoomCallParticipants: [],
|
||||||
|
isMarkedUnread: false,
|
||||||
|
numUnreadMessages: 0,
|
||||||
|
numUnreadNotifications: 0,
|
||||||
|
numUnreadMentions: 0,
|
||||||
|
pinnedEventIds: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await elementCallService.setupCallSession(roomID: roomProxy.id, roomDisplayName: roomProxy.roomTitle)
|
await elementCallService.setupCallSession(roomID: roomProxy.id,
|
||||||
|
roomDisplayName: roomProxy.infoPublisher.value.displayName ?? roomProxy.id)
|
||||||
|
|
||||||
_ = await roomProxy.sendCallNotificationIfNeeded()
|
_ = await roomProxy.sendCallNotificationIfNeeded()
|
||||||
|
|
||||||
|
@ -360,10 +360,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if roomProxy.isPublic {
|
if roomProxy.infoPublisher.value.isPublic {
|
||||||
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .public)
|
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .public)
|
||||||
} else {
|
} else {
|
||||||
state.bindings.leaveRoomAlertItem = if roomProxy.joinedMembersCount > 1 {
|
state.bindings.leaveRoomAlertItem = if roomProxy.infoPublisher.value.joinedMembersCount > 1 {
|
||||||
LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .private)
|
LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .private)
|
||||||
} else {
|
} else {
|
||||||
LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
|
LeaveRoomAlertItem(roomID: roomID, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
|
||||||
@ -408,7 +408,9 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
|||||||
switch await roomProxy.acceptInvitation() {
|
switch await roomProxy.acceptInvitation() {
|
||||||
case .success:
|
case .success:
|
||||||
actionsSubject.send(.presentRoom(roomIdentifier: roomID))
|
actionsSubject.send(.presentRoom(roomIdentifier: roomID))
|
||||||
analyticsService.trackJoinedRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace, activeMemberCount: UInt(roomProxy.activeMembersCount))
|
analyticsService.trackJoinedRoom(isDM: roomProxy.info.isDirect,
|
||||||
|
isSpace: roomProxy.info.isSpace,
|
||||||
|
activeMemberCount: UInt(roomProxy.info.activeMembersCount))
|
||||||
case .failure:
|
case .failure:
|
||||||
displayError()
|
displayError()
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
|||||||
|
|
||||||
defer {
|
defer {
|
||||||
hideLoadingIndicator()
|
hideLoadingIndicator()
|
||||||
Task { await updateRoomDetails() }
|
updateRoomDetails()
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateRoom()
|
await updateRoom()
|
||||||
@ -82,7 +82,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
|||||||
switch await clientProxy.roomPreviewForIdentifier(roomID, via: via) {
|
switch await clientProxy.roomPreviewForIdentifier(roomID, via: via) {
|
||||||
case .success(let roomPreviewDetails):
|
case .success(let roomPreviewDetails):
|
||||||
self.roomPreviewDetails = roomPreviewDetails
|
self.roomPreviewDetails = roomPreviewDetails
|
||||||
await updateRoomDetails()
|
updateRoomDetails()
|
||||||
case .failure(.roomPreviewIsPrivate):
|
case .failure(.roomPreviewIsPrivate):
|
||||||
break // Handled by the mode, we don't need an error indicator.
|
break // Handled by the mode, we don't need an error indicator.
|
||||||
case .failure:
|
case .failure:
|
||||||
@ -97,32 +97,32 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
|||||||
// take priority over the preview one.
|
// take priority over the preview one.
|
||||||
if let room = await clientProxy.roomForIdentifier(roomID) {
|
if let room = await clientProxy.roomForIdentifier(roomID) {
|
||||||
self.room = room
|
self.room = room
|
||||||
await updateRoomDetails()
|
updateRoomDetails()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateRoomDetails() async {
|
private func updateRoomDetails() {
|
||||||
var roomProxy: RoomProxyProtocol?
|
var roomInfo: RoomInfoProxy?
|
||||||
var inviter: RoomInviterDetails?
|
var inviter: RoomInviterDetails?
|
||||||
|
|
||||||
switch room {
|
switch room {
|
||||||
case .joined(let joinedRoomProxy):
|
case .joined(let joinedRoomProxy):
|
||||||
roomProxy = joinedRoomProxy
|
roomInfo = joinedRoomProxy.infoPublisher.value
|
||||||
case .invited(let invitedRoomProxy):
|
case .invited(let invitedRoomProxy):
|
||||||
inviter = await invitedRoomProxy.inviter.flatMap(RoomInviterDetails.init)
|
inviter = invitedRoomProxy.info.inviter.flatMap(RoomInviterDetails.init)
|
||||||
roomProxy = invitedRoomProxy
|
roomInfo = invitedRoomProxy.info
|
||||||
case .knocked(let knockedRoomProxy):
|
case .knocked(let knockedRoomProxy):
|
||||||
roomProxy = knockedRoomProxy
|
roomInfo = knockedRoomProxy.info
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = roomProxy?.name ?? roomPreviewDetails?.name
|
let name = roomInfo?.displayName ?? roomPreviewDetails?.name
|
||||||
state.roomDetails = JoinRoomScreenRoomDetails(name: name,
|
state.roomDetails = JoinRoomScreenRoomDetails(name: name,
|
||||||
topic: roomProxy?.topic ?? roomPreviewDetails?.topic,
|
topic: roomInfo?.topic ?? roomPreviewDetails?.topic,
|
||||||
canonicalAlias: roomProxy?.canonicalAlias ?? roomPreviewDetails?.canonicalAlias,
|
canonicalAlias: roomInfo?.canonicalAlias ?? roomPreviewDetails?.canonicalAlias,
|
||||||
avatar: roomProxy?.avatar ?? .room(id: roomID, name: name ?? "", avatarURL: roomPreviewDetails?.avatarURL),
|
avatar: roomInfo?.avatar ?? .room(id: roomID, name: name ?? "", avatarURL: roomPreviewDetails?.avatarURL),
|
||||||
memberCount: UInt(roomProxy?.activeMembersCount ?? Int(roomPreviewDetails?.memberCount ?? 0)),
|
memberCount: UInt(roomInfo?.activeMembersCount ?? Int(roomPreviewDetails?.memberCount ?? 0)),
|
||||||
inviter: inviter)
|
inviter: inviter)
|
||||||
|
|
||||||
updateMode()
|
updateMode()
|
||||||
|
@ -143,7 +143,8 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh
|
|||||||
let demotingUpdates = state.membersToDemote.map { ($0.id, Int64(0)) }
|
let demotingUpdates = state.membersToDemote.map { ($0.id, Int64(0)) }
|
||||||
|
|
||||||
// A task we can await until the room's info gets modified with the new power levels.
|
// A task we can await until the room's info gets modified with the new power levels.
|
||||||
let infoTask = Task { await roomProxy.actionsPublisher.values.first { $0 == .roomInfoUpdate } }
|
// Note: Ignore the first value as the publisher is backed by a current value subject.
|
||||||
|
let infoTask = Task { await roomProxy.infoPublisher.dropFirst().values.first { _ in true } }
|
||||||
|
|
||||||
switch await roomProxy.updatePowerLevelsForUsers(promotingUpdates + demotingUpdates) {
|
switch await roomProxy.updatePowerLevelsForUsers(promotingUpdates + demotingUpdates) {
|
||||||
case .success:
|
case .success:
|
||||||
|
@ -28,9 +28,9 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe
|
|||||||
self.mediaUploadingPreprocessor = mediaUploadingPreprocessor
|
self.mediaUploadingPreprocessor = mediaUploadingPreprocessor
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
|
|
||||||
let roomAvatar = roomProxy.avatarURL
|
let roomAvatar = roomProxy.infoPublisher.value.avatarURL
|
||||||
let roomName = roomProxy.name
|
let roomName = roomProxy.infoPublisher.value.displayName
|
||||||
let roomTopic = roomProxy.topic
|
let roomTopic = roomProxy.infoPublisher.value.topic
|
||||||
|
|
||||||
super.init(initialViewState: RoomDetailsEditScreenViewState(roomID: roomProxy.id,
|
super.init(initialViewState: RoomDetailsEditScreenViewState(roomID: roomProxy.id,
|
||||||
initialAvatarURL: roomAvatar,
|
initialAvatarURL: roomAvatar,
|
||||||
|
@ -63,14 +63,14 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
self.attributedStringBuilder = attributedStringBuilder
|
self.attributedStringBuilder = attributedStringBuilder
|
||||||
self.appSettings = appSettings
|
self.appSettings = appSettings
|
||||||
|
|
||||||
let topic = attributedStringBuilder.fromPlain(roomProxy.topic)
|
let topic = attributedStringBuilder.fromPlain(roomProxy.infoPublisher.value.topic)
|
||||||
|
|
||||||
super.init(initialViewState: .init(details: roomProxy.details,
|
super.init(initialViewState: .init(details: roomProxy.details,
|
||||||
isEncrypted: roomProxy.isEncrypted,
|
isEncrypted: roomProxy.isEncrypted,
|
||||||
isDirect: roomProxy.isDirect,
|
isDirect: roomProxy.infoPublisher.value.isDirect,
|
||||||
topic: topic,
|
topic: topic,
|
||||||
topicSummary: topic?.unattributedStringByReplacingNewlinesWithSpaces(),
|
topicSummary: topic?.unattributedStringByReplacingNewlinesWithSpaces(),
|
||||||
joinedMembersCount: roomProxy.joinedMembersCount,
|
joinedMembersCount: roomProxy.infoPublisher.value.joinedMembersCount,
|
||||||
notificationSettingsState: .loading,
|
notificationSettingsState: .loading,
|
||||||
bindings: .init()),
|
bindings: .init()),
|
||||||
mediaProvider: mediaProvider)
|
mediaProvider: mediaProvider)
|
||||||
@ -96,7 +96,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRoomInfo()
|
updateRoomInfo(roomProxy.infoPublisher.value)
|
||||||
Task { await updatePowerLevelPermissions() }
|
Task { await updatePowerLevelPermissions() }
|
||||||
|
|
||||||
setupRoomSubscription()
|
setupRoomSubscription()
|
||||||
@ -124,7 +124,9 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
|
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: roomProxy.isPublic ? .public : .private)
|
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomProxy.id,
|
||||||
|
isDM: roomProxy.isEncryptedOneToOneRoom,
|
||||||
|
state: roomProxy.infoPublisher.value.isPublic ? .public : .private)
|
||||||
case .confirmLeave:
|
case .confirmLeave:
|
||||||
Task { await leaveRoom() }
|
Task { await leaveRoom() }
|
||||||
case .processTapIgnore:
|
case .processTapIgnore:
|
||||||
@ -164,27 +166,23 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func setupRoomSubscription() {
|
private func setupRoomSubscription() {
|
||||||
roomProxy.actionsPublisher
|
roomProxy.infoPublisher
|
||||||
.filter { $0 == .roomInfoUpdate }
|
|
||||||
.throttle(for: .milliseconds(200), scheduler: DispatchQueue.main, latest: true)
|
.throttle(for: .milliseconds(200), scheduler: DispatchQueue.main, latest: true)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] roomInfo in
|
||||||
self?.updateRoomInfo()
|
self?.updateRoomInfo(roomInfo)
|
||||||
Task { await self?.updatePowerLevelPermissions() }
|
Task { await self?.updatePowerLevelPermissions() }
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateRoomInfo() {
|
private func updateRoomInfo(_ roomInfo: RoomInfoProxy) {
|
||||||
state.details = roomProxy.details
|
state.details = roomProxy.details
|
||||||
|
|
||||||
let topic = attributedStringBuilder.fromPlain(roomProxy.topic)
|
let topic = attributedStringBuilder.fromPlain(roomInfo.topic)
|
||||||
state.topic = topic
|
state.topic = topic
|
||||||
state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
|
state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
|
||||||
state.joinedMembersCount = roomProxy.joinedMembersCount
|
state.joinedMembersCount = roomInfo.joinedMembersCount
|
||||||
|
state.bindings.isFavourite = roomInfo.isFavourite
|
||||||
Task {
|
|
||||||
state.bindings.isFavourite = await roomProxy.isFavourite
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func fetchMembersIfNeeded() async {
|
private func fetchMembersIfNeeded() async {
|
||||||
@ -240,7 +238,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
do {
|
do {
|
||||||
let notificationMode = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
|
let notificationMode = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
|
||||||
isEncrypted: roomProxy.isEncrypted,
|
isEncrypted: roomProxy.isEncrypted,
|
||||||
isOneToOne: roomProxy.activeMembersCount == 2)
|
isOneToOne: roomProxy.infoPublisher.value.activeMembersCount == 2)
|
||||||
state.notificationSettingsState = .loaded(settings: notificationMode)
|
state.notificationSettingsState = .loaded(settings: notificationMode)
|
||||||
} catch {
|
} catch {
|
||||||
state.notificationSettingsState = .error
|
state.notificationSettingsState = .error
|
||||||
@ -258,7 +256,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
do {
|
do {
|
||||||
try await notificationSettingsProxy.unmuteRoom(roomId: roomProxy.id,
|
try await notificationSettingsProxy.unmuteRoom(roomId: roomProxy.id,
|
||||||
isEncrypted: roomProxy.isEncrypted,
|
isEncrypted: roomProxy.isEncrypted,
|
||||||
isOneToOne: roomProxy.activeMembersCount == 2)
|
isOneToOne: roomProxy.infoPublisher.value.activeMembersCount == 2)
|
||||||
} catch {
|
} catch {
|
||||||
state.bindings.alertInfo = AlertInfo(id: .alert,
|
state.bindings.alertInfo = AlertInfo(id: .alert,
|
||||||
title: L10n.commonError,
|
title: L10n.commonError,
|
||||||
@ -352,7 +350,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
|||||||
|
|
||||||
// We don't actually know the mime type here, assume it's an image.
|
// We don't actually know the mime type here, assume it's an image.
|
||||||
if case let .success(file) = await mediaProvider.loadFileFromSource(.init(url: url, mimeType: "image/jpeg")) {
|
if case let .success(file) = await mediaProvider.loadFileFromSource(.init(url: url, mimeType: "image/jpeg")) {
|
||||||
state.bindings.mediaPreviewItem = MediaPreviewItem(file: file, title: roomProxy.roomTitle)
|
state.bindings.mediaPreviewItem = MediaPreviewItem(file: file, title: roomProxy.infoPublisher.value.displayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
|
|
||||||
super.init(initialViewState: .init(joinedMembersCount: roomProxy.joinedMembersCount,
|
super.init(initialViewState: .init(joinedMembersCount: roomProxy.infoPublisher.value.joinedMembersCount,
|
||||||
bindings: .init(mode: initialMode)),
|
bindings: .init(mode: initialMode)),
|
||||||
mediaProvider: mediaProvider)
|
mediaProvider: mediaProvider)
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
|||||||
let members = members.sorted()
|
let members = members.sorted()
|
||||||
let roomMembersDetails = await buildMembersDetails(members: members)
|
let roomMembersDetails = await buildMembersDetails(members: members)
|
||||||
self.members = members
|
self.members = members
|
||||||
self.state = .init(joinedMembersCount: roomProxy.joinedMembersCount,
|
self.state = .init(joinedMembersCount: roomProxy.infoPublisher.value.joinedMembersCount,
|
||||||
joinedMembers: roomMembersDetails.joinedMembers,
|
joinedMembers: roomMembersDetails.joinedMembers,
|
||||||
invitedMembers: roomMembersDetails.invitedMembers,
|
invitedMembers: roomMembersDetails.invitedMembers,
|
||||||
bannedMembers: roomMembersDetails.bannedMembers,
|
bannedMembers: roomMembersDetails.bannedMembers,
|
||||||
|
@ -26,11 +26,11 @@ class RoomNotificationSettingsScreenViewModel: RoomNotificationSettingsScreenVie
|
|||||||
let bindings = RoomNotificationSettingsScreenViewStateBindings()
|
let bindings = RoomNotificationSettingsScreenViewStateBindings()
|
||||||
self.notificationSettingsProxy = notificationSettingsProxy
|
self.notificationSettingsProxy = notificationSettingsProxy
|
||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
let navigationTitle = displayAsUserDefinedRoomSettings ? roomProxy.roomTitle : L10n.screenRoomDetailsNotificationTitle
|
let navigationTitle = displayAsUserDefinedRoomSettings ? roomProxy.infoPublisher.value.displayName : L10n.screenRoomDetailsNotificationTitle
|
||||||
let customSettingsSectionHeader = displayAsUserDefinedRoomSettings ? L10n.screenRoomNotificationSettingsRoomCustomSettingsTitle : L10n.screenRoomNotificationSettingsCustomSettingsTitle
|
let customSettingsSectionHeader = displayAsUserDefinedRoomSettings ? L10n.screenRoomNotificationSettingsRoomCustomSettingsTitle : L10n.screenRoomNotificationSettingsCustomSettingsTitle
|
||||||
super.init(initialViewState: RoomNotificationSettingsScreenViewState(bindings: bindings,
|
super.init(initialViewState: RoomNotificationSettingsScreenViewState(bindings: bindings,
|
||||||
displayAsUserDefinedRoomSettings: displayAsUserDefinedRoomSettings,
|
displayAsUserDefinedRoomSettings: displayAsUserDefinedRoomSettings,
|
||||||
navigationTitle: navigationTitle,
|
navigationTitle: navigationTitle ?? L10n.screenRoomDetailsNotificationTitle,
|
||||||
customSettingsSectionHeader: customSettingsSectionHeader))
|
customSettingsSectionHeader: customSettingsSectionHeader))
|
||||||
|
|
||||||
setupNotificationSettingsSubscription()
|
setupNotificationSettingsSubscription()
|
||||||
@ -80,7 +80,7 @@ class RoomNotificationSettingsScreenViewModel: RoomNotificationSettingsScreenVie
|
|||||||
// `isOneToOne` here is not the same as `isDirect` on the room. From the point of view of the push rule, a one-to-one room is a room with exactly two active members.
|
// `isOneToOne` here is not the same as `isDirect` on the room. From the point of view of the push rule, a one-to-one room is a room with exactly two active members.
|
||||||
let settings = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
|
let settings = try await notificationSettingsProxy.getNotificationSettings(roomId: roomProxy.id,
|
||||||
isEncrypted: roomProxy.isEncrypted,
|
isEncrypted: roomProxy.isEncrypted,
|
||||||
isOneToOne: roomProxy.activeMembersCount == 2)
|
isOneToOne: roomProxy.infoPublisher.value.activeMembersCount == 2)
|
||||||
guard !Task.isCancelled else { return }
|
guard !Task.isCancelled else { return }
|
||||||
state.notificationSettingsState = .loaded(settings: settings)
|
state.notificationSettingsState = .loaded(settings: settings)
|
||||||
if !state.isRestoringDefaultSetting {
|
if !state.isRestoringDefaultSetting {
|
||||||
|
@ -37,8 +37,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
updateMembers(roomProxy.membersPublisher.value)
|
updateMembers(roomProxy.membersPublisher.value)
|
||||||
|
|
||||||
// Automatically update the room permissions
|
// Automatically update the room permissions
|
||||||
roomProxy.actionsPublisher
|
roomProxy.infoPublisher
|
||||||
.filter { $0 == .roomInfoUpdate }
|
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
Task { await self?.updatePermissions() }
|
Task { await self?.updatePermissions() }
|
||||||
@ -93,7 +92,8 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
showSavingIndicator()
|
showSavingIndicator()
|
||||||
|
|
||||||
// A task we can await until the room's info gets modified with the new power levels.
|
// A task we can await until the room's info gets modified with the new power levels.
|
||||||
let infoTask = Task { await roomProxy.actionsPublisher.values.first { $0 == .roomInfoUpdate } }
|
// Note: Ignore the first value as the publisher is backed by a current value subject.
|
||||||
|
let infoTask = Task { await roomProxy.infoPublisher.dropFirst().values.first { _ in true } }
|
||||||
|
|
||||||
switch await roomProxy.updatePowerLevelsForUsers([(userID: roomProxy.ownUserID, powerLevel: role.rustPowerLevel)]) {
|
switch await roomProxy.updatePowerLevelsForUsers([(userID: roomProxy.ownUserID, powerLevel: role.rustPowerLevel)]) {
|
||||||
case .success:
|
case .success:
|
||||||
|
@ -51,7 +51,7 @@ final class CompletionSuggestionService: CompletionSuggestionServiceProtocol {
|
|||||||
membersSuggestion
|
membersSuggestion
|
||||||
.insert(SuggestionItem.allUsers(item: .init(id: PillConstants.atRoom,
|
.insert(SuggestionItem.allUsers(item: .init(id: PillConstants.atRoom,
|
||||||
displayName: PillConstants.everyone,
|
displayName: PillConstants.everyone,
|
||||||
avatarURL: self.roomProxy.avatarURL,
|
avatarURL: self.roomProxy.infoPublisher.value.avatarURL,
|
||||||
range: suggestionTrigger.range)), at: 0)
|
range: suggestionTrigger.range)), at: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,14 +68,14 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
self.initialSelectedPinnedEventID = initialSelectedPinnedEventID
|
self.initialSelectedPinnedEventID = initialSelectedPinnedEventID
|
||||||
pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID)
|
pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID)
|
||||||
|
|
||||||
super.init(initialViewState: .init(roomTitle: roomProxy.roomTitle,
|
super.init(initialViewState: .init(roomTitle: roomProxy.infoPublisher.value.displayName ?? roomProxy.id,
|
||||||
roomAvatar: roomProxy.avatar,
|
roomAvatar: roomProxy.infoPublisher.value.avatar,
|
||||||
hasOngoingCall: roomProxy.hasOngoingCall,
|
hasOngoingCall: roomProxy.infoPublisher.value.hasRoomCall,
|
||||||
bindings: .init()),
|
bindings: .init()),
|
||||||
mediaProvider: mediaProvider)
|
mediaProvider: mediaProvider)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
await handleRoomInfoUpdate()
|
await handleRoomInfoUpdate(roomProxy.infoPublisher.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSubscriptions(ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher)
|
setupSubscriptions(ongoingCallRoomIDPublisher: ongoingCallRoomIDPublisher)
|
||||||
@ -118,26 +118,25 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
|
|
||||||
private func setupSubscriptions(ongoingCallRoomIDPublisher: CurrentValuePublisher<String?, Never>) {
|
private func setupSubscriptions(ongoingCallRoomIDPublisher: CurrentValuePublisher<String?, Never>) {
|
||||||
let roomInfoSubscription = roomProxy
|
let roomInfoSubscription = roomProxy
|
||||||
.actionsPublisher
|
.infoPublisher
|
||||||
.filter { $0 == .roomInfoUpdate }
|
|
||||||
|
|
||||||
roomInfoSubscription
|
roomInfoSubscription
|
||||||
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
|
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] roomInfo in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
state.roomTitle = roomProxy.roomTitle
|
state.roomTitle = roomInfo.displayName ?? roomProxy.id
|
||||||
state.roomAvatar = roomProxy.avatar
|
state.roomAvatar = roomInfo.avatar
|
||||||
state.hasOngoingCall = roomProxy.hasOngoingCall
|
state.hasOngoingCall = roomInfo.hasRoomCall
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
Task { [weak self] in
|
Task { [weak self] in
|
||||||
for await _ in roomInfoSubscription.receive(on: DispatchQueue.main).values {
|
for await roomInfo in roomInfoSubscription.receive(on: DispatchQueue.main).values {
|
||||||
guard !Task.isCancelled else {
|
guard !Task.isCancelled else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await self?.handleRoomInfoUpdate()
|
await self?.handleRoomInfoUpdate(roomInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@ -230,8 +229,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleRoomInfoUpdate() async {
|
private func handleRoomInfoUpdate(_ roomInfo: RoomInfoProxy) async {
|
||||||
let pinnedEventIDs = await roomProxy.pinnedEventIDs
|
let pinnedEventIDs = roomInfo.pinnedEventIDs
|
||||||
// Only update the loading state of the banner
|
// Only update the loading state of the banner
|
||||||
if state.pinnedEventsBannerState.isLoading {
|
if state.pinnedEventsBannerState.isLoading {
|
||||||
state.pinnedEventsBannerState = .loading(numbersOfEvents: pinnedEventIDs.count)
|
state.pinnedEventsBannerState = .loading(numbersOfEvents: pinnedEventIDs.count)
|
||||||
|
@ -131,7 +131,7 @@ class NotificationSettingsEditScreenViewModel: NotificationSettingsEditScreenVie
|
|||||||
for roomSummary in filteredRoomsSummary {
|
for roomSummary in filteredRoomsSummary {
|
||||||
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomSummary.id) else { continue }
|
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomSummary.id) else { continue }
|
||||||
// `isOneToOneRoom` here is not the same as `isDirect` on the room. From the point of view of the push rule, a one-to-one room is a room with exactly two active members.
|
// `isOneToOneRoom` here is not the same as `isDirect` on the room. From the point of view of the push rule, a one-to-one room is a room with exactly two active members.
|
||||||
let isOneToOneRoom = roomProxy.activeMembersCount == 2
|
let isOneToOneRoom = roomProxy.infoPublisher.value.activeMembersCount == 2
|
||||||
// display only the rooms we're interested in
|
// display only the rooms we're interested in
|
||||||
switch chatType {
|
switch chatType {
|
||||||
case .oneToOneChat where isOneToOneRoom, .groupChat where !isOneToOneRoom:
|
case .oneToOneChat where isOneToOneRoom, .groupChat where !isOneToOneRoom:
|
||||||
|
@ -82,6 +82,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
ownUserID: roomProxy.ownUserID,
|
ownUserID: roomProxy.ownUserID,
|
||||||
isViewSourceEnabled: appSettings.viewSourceEnabled,
|
isViewSourceEnabled: appSettings.viewSourceEnabled,
|
||||||
hideTimelineMedia: appSettings.hideTimelineMedia,
|
hideTimelineMedia: appSettings.hideTimelineMedia,
|
||||||
|
pinnedEventIDs: roomProxy.infoPublisher.value.pinnedEventIDs,
|
||||||
bindings: .init(reactionsCollapsed: [:]),
|
bindings: .init(reactionsCollapsed: [:]),
|
||||||
emojiProvider: emojiProvider),
|
emojiProvider: emojiProvider),
|
||||||
mediaProvider: mediaProvider)
|
mediaProvider: mediaProvider)
|
||||||
@ -91,10 +92,6 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
showFocusLoadingIndicator()
|
showFocusLoadingIndicator()
|
||||||
}
|
}
|
||||||
|
|
||||||
Task {
|
|
||||||
await updatePinnedEventIDs()
|
|
||||||
}
|
|
||||||
|
|
||||||
setupSubscriptions()
|
setupSubscriptions()
|
||||||
setupDirectRoomSubscriptionsIfNeeded()
|
setupDirectRoomSubscriptionsIfNeeded()
|
||||||
|
|
||||||
@ -380,15 +377,13 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
let roomInfoSubscription = roomProxy
|
let roomInfoSubscription = roomProxy.infoPublisher
|
||||||
.actionsPublisher
|
|
||||||
.filter { $0 == .roomInfoUpdate }
|
|
||||||
Task { [weak self] in
|
Task { [weak self] in
|
||||||
for await _ in roomInfoSubscription.receive(on: DispatchQueue.main).values {
|
for await roomInfo in roomInfoSubscription.receive(on: DispatchQueue.main).values {
|
||||||
guard !Task.isCancelled else {
|
guard !Task.isCancelled else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await self?.updatePinnedEventIDs()
|
self?.state.pinnedEventIDs = roomInfo.pinnedEventIDs
|
||||||
await self?.updatePermissions()
|
await self?.updatePermissions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,12 +452,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updatePinnedEventIDs() async {
|
|
||||||
state.pinnedEventIDs = await roomProxy.pinnedEventIDs
|
|
||||||
}
|
|
||||||
|
|
||||||
private func setupDirectRoomSubscriptionsIfNeeded() {
|
private func setupDirectRoomSubscriptionsIfNeeded() {
|
||||||
guard roomProxy.isDirect else {
|
guard roomProxy.infoPublisher.value.isDirect else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +462,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
.map { [weak self] isFocused in
|
.map { [weak self] isFocused in
|
||||||
guard let self else { return false }
|
guard let self else { return false }
|
||||||
|
|
||||||
return isFocused && self.roomProxy.isUserAloneInDirectRoom
|
return isFocused && self.roomProxy.infoPublisher.value.isUserAloneInDirectRoom
|
||||||
}
|
}
|
||||||
// We want to show the alert just once, so we are taking the first "true" emitted
|
// We want to show the alert just once, so we are taking the first "true" emitted
|
||||||
.first { $0 }
|
.first { $0 }
|
||||||
@ -742,7 +733,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
private let inviteLoadingIndicatorID = UUID().uuidString
|
private let inviteLoadingIndicatorID = UUID().uuidString
|
||||||
|
|
||||||
private func inviteOtherDMUserBack() {
|
private func inviteOtherDMUserBack() {
|
||||||
guard roomProxy.isUserAloneInDirectRoom else {
|
guard roomProxy.infoPublisher.value.isUserAloneInDirectRoom else {
|
||||||
userIndicatorController.alertInfo = .init(id: .init(), title: L10n.commonError)
|
userIndicatorController.alertInfo = .init(id: .init(), title: L10n.commonError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -848,7 +839,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension RoomProxyProtocol {
|
private extension RoomInfoProxy {
|
||||||
/// Checks if the other person left the room in a direct chat
|
/// Checks if the other person left the room in a direct chat
|
||||||
var isUserAloneInDirectRoom: Bool {
|
var isUserAloneInDirectRoom: Bool {
|
||||||
isDirect && activeMembersCount == 1
|
isDirect && activeMembersCount == 1
|
||||||
|
@ -696,7 +696,7 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
|
|
||||||
for roomID in roomIdentifiers {
|
for roomID in roomIdentifiers {
|
||||||
guard case let .joined(roomProxy) = await roomForIdentifier(roomID),
|
guard case let .joined(roomProxy) = await roomForIdentifier(roomID),
|
||||||
roomProxy.isDirect,
|
roomProxy.infoPublisher.value.isDirect,
|
||||||
let members = await roomProxy.members() else {
|
let members = await roomProxy.members() else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -869,14 +869,14 @@ class ClientProxy: ClientProxyProtocol {
|
|||||||
|
|
||||||
switch roomListItem.membership() {
|
switch roomListItem.membership() {
|
||||||
case .invited:
|
case .invited:
|
||||||
return try .invited(InvitedRoomProxy(roomListItem: roomListItem,
|
return try await .invited(InvitedRoomProxy(roomListItem: roomListItem,
|
||||||
room: roomListItem.invitedRoom()))
|
room: roomListItem.invitedRoom()))
|
||||||
case .knocked:
|
case .knocked:
|
||||||
if appSettings.knockingEnabled {
|
if appSettings.knockingEnabled {
|
||||||
return try .knocked(KnockedRoomProxy(roomListItem: roomListItem,
|
return try await .knocked(KnockedRoomProxy(roomListItem: roomListItem,
|
||||||
room: roomListItem.invitedRoom()))
|
room: roomListItem.invitedRoom()))
|
||||||
} else {
|
} else {
|
||||||
return try .invited(InvitedRoomProxy(roomListItem: roomListItem,
|
return try await .invited(InvitedRoomProxy(roomListItem: roomListItem,
|
||||||
room: roomListItem.invitedRoom()))
|
room: roomListItem.invitedRoom()))
|
||||||
}
|
}
|
||||||
case .joined:
|
case .joined:
|
||||||
|
@ -291,16 +291,11 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
|
|||||||
// it from what we have. If the call is running before subscribing then wait
|
// it from what we have. If the call is running before subscribing then wait
|
||||||
// for it to change to `false` otherwise wait for it to turn `true` before
|
// for it to change to `false` otherwise wait for it to turn `true` before
|
||||||
// changing to `false`
|
// changing to `false`
|
||||||
let isCallOngoing = roomProxy.hasOngoingCall
|
let isCallOngoing = roomProxy.infoPublisher.value.hasRoomCall
|
||||||
|
|
||||||
roomProxy
|
roomProxy
|
||||||
.actionsPublisher
|
.infoPublisher
|
||||||
.compactMap { action -> (Bool, [String])? in
|
.compactMap { ($0.hasRoomCall, $0.activeRoomCallParticipants) }
|
||||||
switch action {
|
|
||||||
case .roomInfoUpdate:
|
|
||||||
return (roomProxy.hasOngoingCall, roomProxy.activeRoomCallParticipants)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.removeDuplicates { $0 == $1 }
|
.removeDuplicates { $0 == $1 }
|
||||||
.dropFirst(isCallOngoing ? 0 : 1)
|
.dropFirst(isCallOngoing ? 0 : 1)
|
||||||
.sink { [weak self] hasOngoingCall, activeRoomCallParticipants in
|
.sink { [weak self] hasOngoingCall, activeRoomCallParticipants in
|
||||||
|
@ -17,68 +17,15 @@ class InvitedRoomProxy: InvitedRoomProxyProtocol {
|
|||||||
// multiple times over FFI
|
// multiple times over FFI
|
||||||
lazy var id: String = room.id()
|
lazy var id: String = room.id()
|
||||||
|
|
||||||
var canonicalAlias: String? {
|
var ownUserID: String { room.ownUserId() }
|
||||||
room.canonicalAlias()
|
|
||||||
}
|
|
||||||
|
|
||||||
var ownUserID: String {
|
let info: RoomInfoProxy
|
||||||
room.ownUserId()
|
|
||||||
}
|
|
||||||
|
|
||||||
var name: String? {
|
|
||||||
roomListItem.displayName()
|
|
||||||
}
|
|
||||||
|
|
||||||
var topic: String? {
|
|
||||||
room.topic()
|
|
||||||
}
|
|
||||||
|
|
||||||
var avatarURL: URL? {
|
|
||||||
roomListItem.avatarUrl().flatMap(URL.init(string:))
|
|
||||||
}
|
|
||||||
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
if isDirect, avatarURL == nil {
|
|
||||||
let heroes = room.heroes()
|
|
||||||
|
|
||||||
if heroes.count == 1 {
|
|
||||||
return .heroes(heroes.map(UserProfileProxy.init))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .room(id: id, name: name, avatarURL: avatarURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDirect: Bool {
|
|
||||||
room.isDirect()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isPublic: Bool {
|
|
||||||
room.isPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSpace: Bool {
|
|
||||||
room.isSpace()
|
|
||||||
}
|
|
||||||
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
Int(room.joinedMembersCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
Int(room.activeMembersCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
var inviter: RoomMemberProxyProtocol? {
|
|
||||||
get async {
|
|
||||||
await (try? roomListItem.roomInfo().inviter).map(RoomMemberProxy.init)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(roomListItem: RoomListItemProtocol,
|
init(roomListItem: RoomListItemProtocol,
|
||||||
room: RoomProtocol) {
|
room: RoomProtocol) async throws {
|
||||||
self.roomListItem = roomListItem
|
self.roomListItem = roomListItem
|
||||||
self.room = room
|
self.room = room
|
||||||
|
info = try await RoomInfoProxy(roomInfo: room.roomInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
func acceptInvitation() async -> Result<Void, RoomProxyError> {
|
func acceptInvitation() async -> Result<Void, RoomProxyError> {
|
||||||
|
@ -63,6 +63,11 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
|
|
||||||
private var subscribedForUpdates = false
|
private var subscribedForUpdates = false
|
||||||
|
|
||||||
|
private let infoSubject: CurrentValueSubject<RoomInfoProxy, Never>
|
||||||
|
var infoPublisher: CurrentValuePublisher<RoomInfoProxy, Never> {
|
||||||
|
infoSubject.asCurrentValuePublisher()
|
||||||
|
}
|
||||||
|
|
||||||
private let membersSubject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
private let membersSubject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
|
||||||
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
|
||||||
membersSubject.asCurrentValuePublisher()
|
membersSubject.asCurrentValuePublisher()
|
||||||
@ -78,94 +83,16 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
identityStatusChangesSubject.asCurrentValuePublisher()
|
identityStatusChangesSubject.asCurrentValuePublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
|
||||||
var actionsPublisher: AnyPublisher<JoinedRoomProxyAction, Never> {
|
|
||||||
actionsSubject.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
|
|
||||||
// A room identifier is constant and lazy stops it from being fetched
|
// A room identifier is constant and lazy stops it from being fetched
|
||||||
// multiple times over FFI
|
// multiple times over FFI
|
||||||
lazy var id: String = room.id()
|
lazy var id: String = room.id()
|
||||||
|
var ownUserID: String { room.ownUserId() }
|
||||||
var canonicalAlias: String? {
|
var info: RoomInfoProxy { infoSubject.value }
|
||||||
room.canonicalAlias()
|
|
||||||
}
|
|
||||||
|
|
||||||
var ownUserID: String {
|
|
||||||
room.ownUserId()
|
|
||||||
}
|
|
||||||
|
|
||||||
var name: String? {
|
|
||||||
roomListItem.displayName()
|
|
||||||
}
|
|
||||||
|
|
||||||
var topic: String? {
|
|
||||||
room.topic()
|
|
||||||
}
|
|
||||||
|
|
||||||
var avatarURL: URL? {
|
|
||||||
roomListItem.avatarUrl().flatMap(URL.init(string:))
|
|
||||||
}
|
|
||||||
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
if isDirect, avatarURL == nil {
|
|
||||||
let heroes = room.heroes()
|
|
||||||
|
|
||||||
if heroes.count == 1 {
|
|
||||||
return .heroes(heroes.map(UserProfileProxy.init))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .room(id: id, name: name, avatarURL: avatarURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDirect: Bool {
|
|
||||||
room.isDirect()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isPublic: Bool {
|
|
||||||
room.isPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSpace: Bool {
|
|
||||||
room.isSpace()
|
|
||||||
}
|
|
||||||
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
Int(room.joinedMembersCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
Int(room.activeMembersCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
var isEncrypted: Bool {
|
var isEncrypted: Bool {
|
||||||
(try? room.isEncrypted()) ?? false
|
(try? room.isEncrypted()) ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
var isFavourite: Bool {
|
|
||||||
get async {
|
|
||||||
await (try? room.roomInfo().isFavourite) ?? false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pinnedEventIDs: Set<String> {
|
|
||||||
get async {
|
|
||||||
guard let pinnedEventIDs = try? await room.roomInfo().pinnedEventIds else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return .init(pinnedEventIDs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasOngoingCall: Bool {
|
|
||||||
room.hasActiveRoomCall()
|
|
||||||
}
|
|
||||||
|
|
||||||
var activeRoomCallParticipants: [String] {
|
|
||||||
room.activeRoomCallParticipants()
|
|
||||||
}
|
|
||||||
|
|
||||||
init(roomListService: RoomListServiceProtocol,
|
init(roomListService: RoomListServiceProtocol,
|
||||||
roomListItem: RoomListItemProtocol,
|
roomListItem: RoomListItemProtocol,
|
||||||
room: RoomProtocol) async throws {
|
room: RoomProtocol) async throws {
|
||||||
@ -173,6 +100,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
self.roomListItem = roomListItem
|
self.roomListItem = roomListItem
|
||||||
self.room = room
|
self.room = room
|
||||||
|
|
||||||
|
infoSubject = try await .init(RoomInfoProxy(roomInfo: room.roomInfo()))
|
||||||
timeline = try await TimelineProxy(timeline: room.timeline(), kind: .live)
|
timeline = try await TimelineProxy(timeline: room.timeline(), kind: .live)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
@ -210,9 +138,9 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
roomInfoObservationToken = room.subscribeToRoomInfoUpdates(listener: RoomInfoUpdateListener { [weak self] in
|
roomInfoObservationToken = room.subscribeToRoomInfoUpdates(listener: RoomInfoUpdateListener { [weak self] roomInfo in
|
||||||
MXLog.info("Received room info update")
|
MXLog.info("Received room info update")
|
||||||
self?.actionsSubject.send(.roomInfoUpdate)
|
self?.infoSubject.send(.init(roomInfo: roomInfo))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,14 +658,14 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class RoomInfoUpdateListener: RoomInfoListener {
|
private final class RoomInfoUpdateListener: RoomInfoListener {
|
||||||
private let onUpdateClosure: () -> Void
|
private let onUpdateClosure: (RoomInfo) -> Void
|
||||||
|
|
||||||
init(_ onUpdateClosure: @escaping () -> Void) {
|
init(_ onUpdateClosure: @escaping (RoomInfo) -> Void) {
|
||||||
self.onUpdateClosure = onUpdateClosure
|
self.onUpdateClosure = onUpdateClosure
|
||||||
}
|
}
|
||||||
|
|
||||||
func call(roomInfo: RoomInfo) {
|
func call(roomInfo: RoomInfo) {
|
||||||
onUpdateClosure()
|
onUpdateClosure(roomInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,62 +17,15 @@ class KnockedRoomProxy: KnockedRoomProxyProtocol {
|
|||||||
// multiple times over FFI
|
// multiple times over FFI
|
||||||
lazy var id: String = room.id()
|
lazy var id: String = room.id()
|
||||||
|
|
||||||
var canonicalAlias: String? {
|
var ownUserID: String { room.ownUserId() }
|
||||||
room.canonicalAlias()
|
|
||||||
}
|
|
||||||
|
|
||||||
var ownUserID: String {
|
let info: RoomInfoProxy
|
||||||
room.ownUserId()
|
|
||||||
}
|
|
||||||
|
|
||||||
var name: String? {
|
|
||||||
roomListItem.displayName()
|
|
||||||
}
|
|
||||||
|
|
||||||
var topic: String? {
|
|
||||||
room.topic()
|
|
||||||
}
|
|
||||||
|
|
||||||
var avatarURL: URL? {
|
|
||||||
roomListItem.avatarUrl().flatMap(URL.init(string:))
|
|
||||||
}
|
|
||||||
|
|
||||||
var avatar: RoomAvatar {
|
|
||||||
if isDirect, avatarURL == nil {
|
|
||||||
let heroes = room.heroes()
|
|
||||||
|
|
||||||
if heroes.count == 1 {
|
|
||||||
return .heroes(heroes.map(UserProfileProxy.init))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .room(id: id, name: name, avatarURL: avatarURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDirect: Bool {
|
|
||||||
room.isDirect()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isPublic: Bool {
|
|
||||||
room.isPublic()
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSpace: Bool {
|
|
||||||
room.isSpace()
|
|
||||||
}
|
|
||||||
|
|
||||||
var joinedMembersCount: Int {
|
|
||||||
Int(room.joinedMembersCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
var activeMembersCount: Int {
|
|
||||||
Int(room.activeMembersCount())
|
|
||||||
}
|
|
||||||
|
|
||||||
init(roomListItem: RoomListItemProtocol,
|
init(roomListItem: RoomListItemProtocol,
|
||||||
room: RoomProtocol) {
|
room: RoomProtocol) async throws {
|
||||||
self.roomListItem = roomListItem
|
self.roomListItem = roomListItem
|
||||||
self.room = room
|
self.room = room
|
||||||
|
info = try await RoomInfoProxy(roomInfo: room.roomInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
func cancelKnock() async -> Result<Void, RoomProxyError> {
|
func cancelKnock() async -> Result<Void, RoomProxyError> {
|
||||||
|
56
ElementX/Sources/Services/Room/RoomInfoProxy.swift
Normal file
56
ElementX/Sources/Services/Room/RoomInfoProxy.swift
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
// Please see LICENSE in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
|
struct RoomInfoProxy {
|
||||||
|
let roomInfo: RoomInfo
|
||||||
|
|
||||||
|
var id: String { roomInfo.id }
|
||||||
|
var creator: String? { roomInfo.creator }
|
||||||
|
var displayName: String? { roomInfo.displayName }
|
||||||
|
var rawName: String? { roomInfo.rawName }
|
||||||
|
var topic: String? { roomInfo.topic }
|
||||||
|
/// The room's avatar URL. Use this for editing and favour ``avatar`` for display.
|
||||||
|
var avatarURL: URL? { roomInfo.avatarUrl.flatMap(URL.init) }
|
||||||
|
/// The room's avatar info for use in a ``RoomAvatarImage``.
|
||||||
|
var avatar: RoomAvatar {
|
||||||
|
if isDirect, avatarURL == nil {
|
||||||
|
if heroes.count == 1 {
|
||||||
|
return .heroes(heroes.map(UserProfileProxy.init))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .room(id: id, name: displayName, avatarURL: avatarURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDirect: Bool { roomInfo.isDirect }
|
||||||
|
var isPublic: Bool { roomInfo.isPublic }
|
||||||
|
var isSpace: Bool { roomInfo.isSpace }
|
||||||
|
var isTombstoned: Bool { roomInfo.isTombstoned }
|
||||||
|
var isFavourite: Bool { roomInfo.isFavourite }
|
||||||
|
var canonicalAlias: String? { roomInfo.canonicalAlias }
|
||||||
|
var alternativeAliases: [String] { roomInfo.alternativeAliases }
|
||||||
|
var membership: Membership { roomInfo.membership }
|
||||||
|
var inviter: RoomMemberProxy? { roomInfo.inviter.map(RoomMemberProxy.init) }
|
||||||
|
var heroes: [RoomHero] { roomInfo.heroes }
|
||||||
|
var activeMembersCount: Int { Int(roomInfo.activeMembersCount) }
|
||||||
|
var invitedMembersCount: Int { Int(roomInfo.invitedMembersCount) }
|
||||||
|
var joinedMembersCount: Int { Int(roomInfo.joinedMembersCount) }
|
||||||
|
var userPowerLevels: [String: Int] { roomInfo.userPowerLevels.mapValues(Int.init) }
|
||||||
|
var highlightCount: Int { Int(roomInfo.highlightCount) }
|
||||||
|
var notificationCount: Int { Int(roomInfo.notificationCount) }
|
||||||
|
var cachedUserDefinedNotificationMode: RoomNotificationMode? { roomInfo.cachedUserDefinedNotificationMode }
|
||||||
|
var hasRoomCall: Bool { roomInfo.hasRoomCall }
|
||||||
|
var activeRoomCallParticipants: [String] { roomInfo.activeRoomCallParticipants }
|
||||||
|
var isMarkedUnread: Bool { roomInfo.isMarkedUnread }
|
||||||
|
var unreadMessagesCount: UInt { UInt(roomInfo.numUnreadMessages) }
|
||||||
|
var unreadNotificationsCount: UInt { UInt(roomInfo.numUnreadNotifications) }
|
||||||
|
var unreadMentionsCount: UInt { UInt(roomInfo.numUnreadMentions) }
|
||||||
|
var pinnedEventIDs: Set<String> { Set(roomInfo.pinnedEventIds) }
|
||||||
|
}
|
@ -28,37 +28,19 @@ enum RoomProxyType {
|
|||||||
// sourcery: AutoMockable
|
// sourcery: AutoMockable
|
||||||
protocol RoomProxyProtocol {
|
protocol RoomProxyProtocol {
|
||||||
var id: String { get }
|
var id: String { get }
|
||||||
var canonicalAlias: String? { get }
|
|
||||||
|
|
||||||
var ownUserID: String { get }
|
var ownUserID: String { get }
|
||||||
|
|
||||||
var name: String? { get }
|
|
||||||
var topic: String? { get }
|
|
||||||
|
|
||||||
/// The room's avatar info for use in a ``RoomAvatarImage``.
|
|
||||||
var avatar: RoomAvatar { get }
|
|
||||||
/// The room's avatar URL. Use this for editing and favour ``avatar`` for display.
|
|
||||||
var avatarURL: URL? { get }
|
|
||||||
|
|
||||||
var isPublic: Bool { get }
|
|
||||||
var isDirect: Bool { get }
|
|
||||||
var isSpace: Bool { get }
|
|
||||||
|
|
||||||
var joinedMembersCount: Int { get }
|
|
||||||
|
|
||||||
var activeMembersCount: Int { get }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sourcery: AutoMockable
|
// sourcery: AutoMockable
|
||||||
protocol InvitedRoomProxyProtocol: RoomProxyProtocol {
|
protocol InvitedRoomProxyProtocol: RoomProxyProtocol {
|
||||||
var inviter: RoomMemberProxyProtocol? { get async }
|
var info: RoomInfoProxy { get }
|
||||||
|
|
||||||
func rejectInvitation() async -> Result<Void, RoomProxyError>
|
func rejectInvitation() async -> Result<Void, RoomProxyError>
|
||||||
func acceptInvitation() async -> Result<Void, RoomProxyError>
|
func acceptInvitation() async -> Result<Void, RoomProxyError>
|
||||||
}
|
}
|
||||||
|
|
||||||
// sourcery: AutoMockable
|
// sourcery: AutoMockable
|
||||||
protocol KnockedRoomProxyProtocol: RoomProxyProtocol {
|
protocol KnockedRoomProxyProtocol: RoomProxyProtocol {
|
||||||
|
var info: RoomInfoProxy { get }
|
||||||
func cancelKnock() async -> Result<Void, RoomProxyError>
|
func cancelKnock() async -> Result<Void, RoomProxyError>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,11 +51,8 @@ enum JoinedRoomProxyAction: Equatable {
|
|||||||
// sourcery: AutoMockable
|
// sourcery: AutoMockable
|
||||||
protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
||||||
var isEncrypted: Bool { get }
|
var isEncrypted: Bool { get }
|
||||||
var isFavourite: Bool { get async }
|
|
||||||
var pinnedEventIDs: Set<String> { get async }
|
|
||||||
|
|
||||||
var hasOngoingCall: Bool { get }
|
var infoPublisher: CurrentValuePublisher<RoomInfoProxy, Never> { get }
|
||||||
var activeRoomCallParticipants: [String] { get }
|
|
||||||
|
|
||||||
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
|
var membersPublisher: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
|
||||||
|
|
||||||
@ -81,8 +60,6 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
|||||||
|
|
||||||
var identityStatusChangesPublisher: CurrentValuePublisher<[IdentityStatusChange], Never> { get }
|
var identityStatusChangesPublisher: CurrentValuePublisher<[IdentityStatusChange], Never> { get }
|
||||||
|
|
||||||
var actionsPublisher: AnyPublisher<JoinedRoomProxyAction, Never> { get }
|
|
||||||
|
|
||||||
var timeline: TimelineProxyProtocol { get }
|
var timeline: TimelineProxyProtocol { get }
|
||||||
|
|
||||||
var pinnedEventsTimeline: TimelineProxyProtocol? { get async }
|
var pinnedEventsTimeline: TimelineProxyProtocol? { get async }
|
||||||
@ -176,21 +153,15 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
|||||||
extension JoinedRoomProxyProtocol {
|
extension JoinedRoomProxyProtocol {
|
||||||
var details: RoomDetails {
|
var details: RoomDetails {
|
||||||
RoomDetails(id: id,
|
RoomDetails(id: id,
|
||||||
name: name,
|
name: infoPublisher.value.displayName,
|
||||||
avatar: avatar,
|
avatar: infoPublisher.value.avatar,
|
||||||
canonicalAlias: canonicalAlias,
|
canonicalAlias: infoPublisher.value.canonicalAlias,
|
||||||
isEncrypted: isEncrypted,
|
isEncrypted: isEncrypted,
|
||||||
isPublic: isPublic)
|
isPublic: infoPublisher.value.isPublic)
|
||||||
}
|
|
||||||
|
|
||||||
// Avoids to duplicate the same logic around in the app
|
|
||||||
// Probably this should be done in rust.
|
|
||||||
var roomTitle: String {
|
|
||||||
name ?? "Unknown room 💥"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isEncryptedOneToOneRoom: Bool {
|
var isEncryptedOneToOneRoom: Bool {
|
||||||
isDirect && isEncrypted && activeMembersCount <= 2
|
infoPublisher.value.isDirect && isEncrypted && infoPublisher.value.activeMembersCount <= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func members() async -> [RoomMemberProxyProtocol]? {
|
func members() async -> [RoomMemberProxyProtocol]? {
|
||||||
|
@ -326,7 +326,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
switch paginationState.backward {
|
switch paginationState.backward {
|
||||||
case .timelineEndReached:
|
case .timelineEndReached:
|
||||||
if timelineKind != .pinned, !roomProxy.isEncryptedOneToOneRoom {
|
if timelineKind != .pinned, !roomProxy.isEncryptedOneToOneRoom {
|
||||||
let timelineStart = TimelineStartRoomTimelineItem(name: roomProxy.name)
|
let timelineStart = TimelineStartRoomTimelineItem(name: roomProxy.infoPublisher.value.displayName)
|
||||||
newTimelineItems.insert(timelineStart, at: 0)
|
newTimelineItems.insert(timelineStart, at: 0)
|
||||||
}
|
}
|
||||||
case .paginating:
|
case .paginating:
|
||||||
|
@ -24,15 +24,16 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPinnedEventsBanner() async throws {
|
func testPinnedEventsBanner() async throws {
|
||||||
|
var configuration = JoinedRoomProxyMockConfiguration()
|
||||||
let timelineSubject = PassthroughSubject<TimelineProxyProtocol, Never>()
|
let timelineSubject = PassthroughSubject<TimelineProxyProtocol, Never>()
|
||||||
let updateSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
let infoSubject = CurrentValueSubject<RoomInfoProxy, Never>(.init(roomInfo: RoomInfo(configuration)))
|
||||||
let roomProxyMock = JoinedRoomProxyMock(.init())
|
let roomProxyMock = JoinedRoomProxyMock(configuration)
|
||||||
// setup a way to inject the mock of the pinned events timeline
|
// setup a way to inject the mock of the pinned events timeline
|
||||||
roomProxyMock.pinnedEventsTimelineClosure = {
|
roomProxyMock.pinnedEventsTimelineClosure = {
|
||||||
await timelineSubject.values.first()
|
await timelineSubject.values.first()
|
||||||
}
|
}
|
||||||
// setup the room proxy actions publisher
|
// setup the room proxy actions publisher
|
||||||
roomProxyMock.underlyingActionsPublisher = updateSubject.eraseToAnyPublisher()
|
roomProxyMock.underlyingInfoPublisher = infoSubject.asCurrentValuePublisher()
|
||||||
let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(),
|
let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(),
|
||||||
roomProxy: roomProxyMock,
|
roomProxy: roomProxyMock,
|
||||||
initialSelectedPinnedEventID: nil,
|
initialSelectedPinnedEventID: nil,
|
||||||
@ -56,8 +57,8 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
||||||
viewState.pinnedEventsBannerState.count == 2
|
viewState.pinnedEventsBannerState.count == 2
|
||||||
}
|
}
|
||||||
roomProxyMock.underlyingPinnedEventIDs = ["test1", "test2"]
|
configuration.pinnedEventIDs = ["test1", "test2"]
|
||||||
updateSubject.send(.roomInfoUpdate)
|
infoSubject.send(.init(roomInfo: RoomInfo(configuration)))
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
XCTAssertTrue(viewModel.context.viewState.pinnedEventsBannerState.isLoading)
|
XCTAssertTrue(viewModel.context.viewState.pinnedEventsBannerState.isLoading)
|
||||||
XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner)
|
XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner)
|
||||||
@ -157,11 +158,12 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testRoomInfoUpdate() async throws {
|
func testRoomInfoUpdate() async throws {
|
||||||
let updateSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
var configuration = JoinedRoomProxyMockConfiguration(id: "TestID", name: "StartingName", avatarURL: nil, hasOngoingCall: false)
|
||||||
let roomProxyMock = JoinedRoomProxyMock(.init(id: "TestID", name: "StartingName", avatarURL: nil, hasOngoingCall: false))
|
let infoSubject = CurrentValueSubject<RoomInfoProxy, Never>(.init(roomInfo: RoomInfo(configuration)))
|
||||||
|
let roomProxyMock = JoinedRoomProxyMock(configuration)
|
||||||
// setup the room proxy actions publisher
|
// setup the room proxy actions publisher
|
||||||
roomProxyMock.canUserJoinCallUserIDReturnValue = .success(false)
|
roomProxyMock.canUserJoinCallUserIDReturnValue = .success(false)
|
||||||
roomProxyMock.underlyingActionsPublisher = updateSubject.eraseToAnyPublisher()
|
roomProxyMock.underlyingInfoPublisher = infoSubject.asCurrentValuePublisher()
|
||||||
let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(),
|
let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(),
|
||||||
roomProxy: roomProxyMock,
|
roomProxy: roomProxyMock,
|
||||||
initialSelectedPinnedEventID: nil,
|
initialSelectedPinnedEventID: nil,
|
||||||
@ -181,9 +183,9 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
|
|
||||||
roomProxyMock.name = "NewName"
|
configuration.name = "NewName"
|
||||||
roomProxyMock.avatar = .room(id: "TestID", name: "NewName", avatarURL: .documentsDirectory)
|
configuration.avatarURL = .documentsDirectory
|
||||||
roomProxyMock.hasOngoingCall = true
|
configuration.hasOngoingCall = true
|
||||||
roomProxyMock.canUserJoinCallUserIDReturnValue = .success(true)
|
roomProxyMock.canUserJoinCallUserIDReturnValue = .success(true)
|
||||||
|
|
||||||
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
||||||
@ -193,7 +195,7 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
viewState.hasOngoingCall
|
viewState.hasOngoingCall
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSubject.send(.roomInfoUpdate)
|
infoSubject.send(.init(roomInfo: RoomInfo(configuration)))
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,10 +349,11 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
// MARK: - Pins
|
// MARK: - Pins
|
||||||
|
|
||||||
func testPinnedEvents() async throws {
|
func testPinnedEvents() async throws {
|
||||||
let roomProxyMock = JoinedRoomProxyMock(.init(name: "",
|
var configuration = JoinedRoomProxyMockConfiguration(name: "",
|
||||||
pinnedEventIDs: .init(["test1"])))
|
pinnedEventIDs: .init(["test1"]))
|
||||||
let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
let roomProxyMock = JoinedRoomProxyMock(configuration)
|
||||||
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()
|
let infoSubject = CurrentValueSubject<RoomInfoProxy, Never>(.init(roomInfo: RoomInfo(configuration)))
|
||||||
|
roomProxyMock.underlyingInfoPublisher = infoSubject.asCurrentValuePublisher()
|
||||||
|
|
||||||
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
||||||
timelineController: MockRoomTimelineController(),
|
timelineController: MockRoomTimelineController(),
|
||||||
@ -364,24 +365,21 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analyticsService: ServiceLocator.shared.analytics,
|
analyticsService: ServiceLocator.shared.analytics,
|
||||||
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
|
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
|
||||||
|
XCTAssertEqual(configuration.pinnedEventIDs, viewModel.context.viewState.pinnedEventIDs)
|
||||||
|
|
||||||
var deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
configuration.pinnedEventIDs = ["test1", "test2"]
|
||||||
value.pinnedEventIDs == ["test1"]
|
let deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
||||||
}
|
|
||||||
try await deferred.fulfill()
|
|
||||||
|
|
||||||
roomProxyMock.underlyingPinnedEventIDs = ["test1", "test2"]
|
|
||||||
deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
|
||||||
value.pinnedEventIDs == ["test1", "test2"]
|
value.pinnedEventIDs == ["test1", "test2"]
|
||||||
}
|
}
|
||||||
actionsSubject.send(.roomInfoUpdate)
|
infoSubject.send(.init(roomInfo: RoomInfo(configuration)))
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCanUserPinEvents() async throws {
|
func testCanUserPinEvents() async throws {
|
||||||
let roomProxyMock = JoinedRoomProxyMock(.init(name: "", canUserPin: true))
|
let configuration = JoinedRoomProxyMockConfiguration(name: "", canUserPin: true)
|
||||||
let actionsSubject = PassthroughSubject<JoinedRoomProxyAction, Never>()
|
let roomProxyMock = JoinedRoomProxyMock(configuration)
|
||||||
roomProxyMock.underlyingActionsPublisher = actionsSubject.eraseToAnyPublisher()
|
let infoSubject = CurrentValueSubject<RoomInfoProxy, Never>(.init(roomInfo: RoomInfo(configuration)))
|
||||||
|
roomProxyMock.underlyingInfoPublisher = infoSubject.asCurrentValuePublisher()
|
||||||
|
|
||||||
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
let viewModel = TimelineViewModel(roomProxy: roomProxyMock,
|
||||||
timelineController: MockRoomTimelineController(),
|
timelineController: MockRoomTimelineController(),
|
||||||
@ -403,7 +401,7 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
deferred = deferFulfillment(viewModel.context.$viewState) { value in
|
||||||
!value.canCurrentUserPin
|
!value.canCurrentUserPin
|
||||||
}
|
}
|
||||||
actionsSubject.send(.roomInfoUpdate)
|
infoSubject.send(.init(roomInfo: RoomInfo(configuration)))
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user