diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index e2d5dd7af..e8b7249d0 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -145,6 +145,7 @@ 21BF2B7CEDFE3CA67C5355AD /* test_image.png in Resources */ = {isa = PBXBuildFile; fileRef = C733D11B421CFE3A657EF230 /* test_image.png */; }; 21F29351EDD7B2A5534EE862 /* SecureBackupKeyBackupScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD558A898847C179E4B7A237 /* SecureBackupKeyBackupScreen.swift */; }; 22882C710BC99EC34A5024A0 /* UITestsScreenIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */; }; + 22C5483D01EEB290B8339817 /* HomeScreenInviteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FC33C3F6BF597E095CE9FA /* HomeScreenInviteCell.swift */; }; 2335D1AB954C151FD8779F45 /* RoomPermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0096BC5DA86AF6B6E5742AC /* RoomPermissionsTests.swift */; }; 234E2C782981003971ABE96E /* PermalinkBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */; }; 23701DE32ACD6FD40AA992C3 /* MediaUploadingPreprocessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE203026B9AD3DB412439866 /* MediaUploadingPreprocessorTests.swift */; }; @@ -528,6 +529,7 @@ 7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */; }; 7F7EA51A9A43125A8CB6AC90 /* NotificationSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D560DDA3B20C82766ACFAD /* NotificationSettingsScreenViewModel.swift */; }; 7F941B063C94E1718DFC2CF3 /* RoomChangeRolesScreenRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23E6EB7960BC9D0F7396B3BD /* RoomChangeRolesScreenRow.swift */; }; + 7FED77802940EA7DF4D0D3A2 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */; }; 7FF6E1FBE6E9517FD29A1D8E /* RoomChangeRolesScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48A5C34C4E4268EF65D171EF /* RoomChangeRolesScreenModels.swift */; }; 8015842CB4DE1BE414D2CDED /* AppLockSetupBiometricsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C62E07C1164F5120727A2A8 /* AppLockSetupBiometricsScreenCoordinator.swift */; }; 804C15D8ADE0EA7A5268F58A /* OverridableAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648DD1C10E4957CB791FE0B8 /* OverridableAvatarImage.swift */; }; @@ -581,6 +583,7 @@ 8AB8ED1051216546CB35FA0E /* UserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5E9C044BEB7C70B1378E91 /* UserSession.swift */; }; 8AC256AF0EC54658321C9241 /* LegalInformationScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E5725BC6C63604CB769145B /* LegalInformationScreenViewModelTests.swift */; }; 8B1D5CE017EEC734CF5FE130 /* Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260004737C573A56FA01E86E /* Encodable.swift */; }; + 8B408C574E35E1C9B43A50CE /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */; }; 8B41D0357B91CD3B6F6A3BCA /* EmoteRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */; }; 8B76191B9DDD1AC90A6E3A35 /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; }; 8BC8EF6705A78946C1F22891 /* SoftLogoutScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A7D4DDEEE5D2CA0C8D63CD /* SoftLogoutScreen.swift */; }; @@ -1971,6 +1974,7 @@ D8E057FB1F07A5C201C89061 /* MockServerSelectionScreenState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockServerSelectionScreenState.swift; sourceTree = ""; }; D8E60332509665C00179ACF6 /* MessageForwardingScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModel.swift; sourceTree = ""; }; D8F5F9E02B1AB5350B1815E7 /* TimelineStartRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStartRoomTimelineItem.swift; sourceTree = ""; }; + D8FC33C3F6BF597E095CE9FA /* HomeScreenInviteCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenInviteCell.swift; sourceTree = ""; }; D93C94C30E3135BC9290DE13 /* VoiceMessageRecorderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorderTests.swift; sourceTree = ""; }; D95E8C0EFEC0C6F96EDAA71A /* PreviewTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = PreviewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DA14564EE143F73F7E4D1F79 /* RoomNotificationSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenModels.swift; sourceTree = ""; }; @@ -3147,6 +3151,7 @@ B902EA6CD3296B0E10EE432B /* HomeScreen.swift */, A3B4B58B79A6FA250B24A1EC /* HomeScreenContent.swift */, C0FEA560929DD73FFEF8C3DF /* HomeScreenEmptyStateView.swift */, + D8FC33C3F6BF597E095CE9FA /* HomeScreenInviteCell.swift */, 24227FF9A2797F6EA7F69CDD /* HomeScreenInvitesButton.swift */, 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */, ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */, @@ -5414,6 +5419,7 @@ 5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */, 0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */, 6860721DB3091BE08164C132 /* MapAssets.xcassets in Resources */, + 8B408C574E35E1C9B43A50CE /* PrivacyInfo.xcprivacy in Resources */, C3317EF833AB4060988DF098 /* SAS.strings in Resources */, CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */, 2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */, @@ -5426,6 +5432,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7FED77802940EA7DF4D0D3A2 /* PrivacyInfo.xcprivacy in Resources */, D2D70B5DB1A5E4AF0CD88330 /* target.yml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5988,6 +5995,7 @@ 62C5876C4254C58C2086F0DE /* HomeScreenContent.swift in Sources */, 8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */, 77BB228AEA861E50FFD6A228 /* HomeScreenEmptyStateView.swift in Sources */, + 22C5483D01EEB290B8339817 /* HomeScreenInviteCell.swift in Sources */, 64C373ACCFA26D42BA45CFAD /* HomeScreenInvitesButton.swift in Sources */, 8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */, B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */, @@ -7268,7 +7276,7 @@ repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 1.1.56; + version = 1.1.57; }; }; 821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3fb390733..e1ef1db24 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -139,8 +139,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { - "revision" : "1d47d496ca46e123e102e64d45635fab73de3d78", - "version" : "1.1.56" + "revision" : "e50657b5d9672d09e4ab0a6e8a3f8939eed49e04", + "version" : "1.1.57" } }, { @@ -263,7 +263,7 @@ { "identity" : "swiftui-introspect", "kind" : "remoteSourceControl", - "location" : "https://github.com/siteline/SwiftUI-Introspect", + "location" : "https://github.com/siteline/SwiftUI-Introspect.git", "state" : { "revision" : "b94da693e57eaf79d16464b8b7c90d09cba4e290", "version" : "0.9.2" diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 1e979777d..2c8a43fe8 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -47,13 +47,9 @@ final class AppSettings { // Feature flags case shouldCollapseRoomStateEvents - case userSuggestionsEnabled - case mentionsBadgeEnabled - case roomListFiltersEnabled - case markAsUnreadEnabled - case markAsFavouriteEnabled case publicSearchEnabled case qrCodeLoginEnabled + case roomListInvitesEnabled } private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier @@ -287,6 +283,9 @@ final class AppSettings { @UserPreference(key: UserDefaultsKeys.qrCodeLoginEnabled, defaultValue: false, storageType: .userDefaults(store)) var qrCodeLoginEnabled + @UserPreference(key: UserDefaultsKeys.roomListInvitesEnabled, defaultValue: false, storageType: .userDefaults(store)) + var roomListInvitesEnabled + #endif // MARK: - Shared diff --git a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift index 90e98574e..cb2456467 100644 --- a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 2.1.8 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 2.2.2 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable all @@ -478,16 +478,16 @@ class SDKClientMock: SDKClientProtocol { } public var loginUsernamePasswordInitialDeviceNameDeviceIdReceivedArguments: (username: String, password: String, initialDeviceName: String?, deviceId: String?)? public var loginUsernamePasswordInitialDeviceNameDeviceIdReceivedInvocations: [(username: String, password: String, initialDeviceName: String?, deviceId: String?)] = [] - public var loginUsernamePasswordInitialDeviceNameDeviceIdClosure: ((String, String, String?, String?) throws -> Void)? + public var loginUsernamePasswordInitialDeviceNameDeviceIdClosure: ((String, String, String?, String?) async throws -> Void)? - public func login(username: String, password: String, initialDeviceName: String?, deviceId: String?) throws { + public func login(username: String, password: String, initialDeviceName: String?, deviceId: String?) async throws { if let error = loginUsernamePasswordInitialDeviceNameDeviceIdThrowableError { throw error } loginUsernamePasswordInitialDeviceNameDeviceIdCallsCount += 1 loginUsernamePasswordInitialDeviceNameDeviceIdReceivedArguments = (username: username, password: password, initialDeviceName: initialDeviceName, deviceId: deviceId) loginUsernamePasswordInitialDeviceNameDeviceIdReceivedInvocations.append((username: username, password: password, initialDeviceName: initialDeviceName, deviceId: deviceId)) - try loginUsernamePasswordInitialDeviceNameDeviceIdClosure?(username, password, initialDeviceName, deviceId) + try await loginUsernamePasswordInitialDeviceNameDeviceIdClosure?(username, password, initialDeviceName, deviceId) } //MARK: - logout diff --git a/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift b/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift index 9dba4e86d..c4ac5c49e 100644 --- a/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift +++ b/ElementX/Sources/Mocks/RoomSummaryProviderMock.swift @@ -79,6 +79,8 @@ extension RoomSummaryProviderMock { extension Array where Element == RoomSummary { static let mockRooms: [Element] = [ .filled(details: RoomSummaryDetails(id: "1", + isInvite: false, + inviter: nil, name: "Foundation 🔭🪐🌌", isDirect: false, avatarURL: nil, @@ -89,11 +91,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 0, notificationMode: .allMessages, canonicalAlias: nil, - inviter: nil, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "2", + isInvite: false, + inviter: nil, name: "Foundation and Empire", isDirect: false, avatarURL: URL.picturesDirectory, @@ -104,11 +107,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 2, notificationMode: .mute, canonicalAlias: nil, - inviter: nil, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "3", + isInvite: false, + inviter: nil, name: "Second Foundation", isDirect: false, avatarURL: nil, @@ -119,11 +123,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 0, notificationMode: .mentionsAndKeywordsOnly, canonicalAlias: nil, - inviter: nil, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "4", + isInvite: false, + inviter: nil, name: "Foundation's Edge", isDirect: false, avatarURL: nil, @@ -134,11 +139,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 2, notificationMode: .allMessages, canonicalAlias: nil, - inviter: nil, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "5", + isInvite: false, + inviter: nil, name: "Foundation and Earth", isDirect: true, avatarURL: nil, @@ -149,11 +155,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 1, notificationMode: .allMessages, canonicalAlias: nil, - inviter: nil, hasOngoingCall: true, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "6", + isInvite: false, + inviter: nil, name: "Prelude to Foundation", isDirect: true, avatarURL: nil, @@ -164,11 +171,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 0, notificationMode: .mute, canonicalAlias: nil, - inviter: nil, hasOngoingCall: true, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "0", + isInvite: false, + inviter: nil, name: "Unknown", isDirect: false, avatarURL: nil, @@ -179,7 +187,6 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 0, notificationMode: nil, canonicalAlias: nil, - inviter: nil, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)), @@ -216,7 +223,10 @@ extension Array where Element == RoomSummary { }() static let mockInvites: [Element] = [ - .filled(details: RoomSummaryDetails(id: "someAwesomeRoomId1", name: "First room", + .filled(details: RoomSummaryDetails(id: "someAwesomeRoomId1", + isInvite: false, + inviter: RoomMemberProxyMock.mockCharlie, + name: "First room", isDirect: false, avatarURL: URL.picturesDirectory, lastMessage: nil, @@ -226,11 +236,12 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 0, notificationMode: nil, canonicalAlias: "#footest:somewhere.org", - inviter: RoomMemberProxyMock.mockCharlie, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)), .filled(details: RoomSummaryDetails(id: "someAwesomeRoomId2", + isInvite: false, + inviter: RoomMemberProxyMock.mockCharlie, name: "Second room", isDirect: true, avatarURL: nil, @@ -241,7 +252,6 @@ extension Array where Element == RoomSummary { unreadNotificationsCount: 0, notificationMode: nil, canonicalAlias: nil, - inviter: RoomMemberProxyMock.mockCharlie, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false)) diff --git a/ElementX/Sources/Other/PermalinkBuilder.swift b/ElementX/Sources/Other/PermalinkBuilder.swift index 6c8c97cee..41e6097e6 100644 --- a/ElementX/Sources/Other/PermalinkBuilder.swift +++ b/ElementX/Sources/Other/PermalinkBuilder.swift @@ -78,6 +78,7 @@ enum PermalinkBuilder { return nil } + @available(*, deprecated, message: "Use a room's `matrixToPermalink` method instead") static func permalinkTo(userIdentifier: String, baseURL: URL) throws -> URL { guard MatrixEntityRegex.isMatrixUserIdentifier(userIdentifier) else { throw PermalinkBuilderError.invalidUserIdentifier diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift index 8b7a973a5..2ba9962b6 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift @@ -48,6 +48,9 @@ enum HomeScreenViewAction { case markRoomAsRead(roomIdentifier: String) case markRoomAsFavourite(roomIdentifier: String, isFavourite: Bool) case selectRoomDirectorySearch + + case acceptInvite(roomIdentifier: String) + case declineInvite(roomIdentifier: String) } enum HomeScreenRoomListMode: CustomStringConvertible { @@ -130,6 +133,18 @@ struct HomeScreenViewStateBindings { } struct HomeScreenRoom: Identifiable, Equatable { + enum RoomType { + case placeholder + case room + case invite + } + + struct InviterDetails: Equatable { + let userID: String + let displayName: String? + let avatarURL: URL? + } + static let placeholderLastMessage = AttributedString("Hidden last message") /// The list item identifier can be a real room identifier, a custom one for invalidated entries @@ -139,9 +154,9 @@ struct HomeScreenRoom: Identifiable, Equatable { /// The real room identifier this item points to let roomId: String? - var name = "" + let type: RoomType - var badges: Badges + let badges: Badges struct Badges: Equatable { let isDotShown: Bool let isMentionShown: Bool @@ -149,28 +164,38 @@ struct HomeScreenRoom: Identifiable, Equatable { let isCallShown: Bool } + let name: String + + let isDirect: Bool + let isHighlighted: Bool let isFavourite: Bool - var timestamp: String? + let timestamp: String? - var lastMessage: AttributedString? + let lastMessage: AttributedString? - var avatarURL: URL? + let avatarURL: URL? - var isPlaceholder = false + let inviter: InviterDetails? + + let canonicalAlias: String? static func placeholder() -> HomeScreenRoom { HomeScreenRoom(id: UUID().uuidString, roomId: nil, - name: "Placeholder room name", + type: .placeholder, badges: .init(isDotShown: false, isMentionShown: false, isMuteShown: false, isCallShown: false), + name: "Placeholder room name", + isDirect: false, isHighlighted: false, isFavourite: false, timestamp: "Now", lastMessage: placeholderLastMessage, - isPlaceholder: true) + avatarURL: nil, + inviter: nil, + canonicalAlias: nil) } } @@ -186,17 +211,28 @@ extension HomeScreenRoom { let isCallShown = details.hasOngoingCall let isHighlighted = details.isMarkedUnread || (!details.isMuted && (details.hasUnreadNotifications || details.hasUnreadMentions)) + var inviter: InviterDetails? + if let roomMemberProxy = details.inviter { + inviter = .init(userID: roomMemberProxy.userID, + displayName: roomMemberProxy.displayName, + avatarURL: roomMemberProxy.avatarURL) + } + self.init(id: identifier, roomId: details.id, - name: details.name, + type: details.isInvite ? .invite : .room, badges: .init(isDotShown: isDotShown, isMentionShown: isMentionShown, isMuteShown: isMuteShown, isCallShown: isCallShown), + name: details.name, + isDirect: details.isDirect, isHighlighted: isHighlighted, isFavourite: details.isFavourite, timestamp: details.lastMessageFormattedTimestamp, lastMessage: details.lastMessage, - avatarURL: details.avatarURL) + avatarURL: details.avatarURL, + inviter: inviter, + canonicalAlias: details.canonicalAlias) } } diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 4588a0ad1..d23e1fa16 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -183,6 +183,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol } case .selectRoomDirectorySearch: actionsSubject.send(.presentRoomDirectorySearch) + case .acceptInvite(let roomIdentifier): + Task { + await acceptInvite(roomID: roomIdentifier) + } + case .declineInvite(let roomIdentifier): + showDeclineInviteConfirmationAlert(roomID: roomIdentifier) } } @@ -446,4 +452,69 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol } } } + + // MARK: Invites + + private func acceptInvite(roomID: String) async { + defer { + userIndicatorController.retractIndicatorWithId(roomID) + } + + userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true)) + + guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else { + displayError() + return + } + + switch await roomProxy.acceptInvitation() { + case .success: + actionsSubject.send(.presentRoom(roomIdentifier: roomID)) + analyticsService.trackJoinedRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace, activeMemberCount: UInt(roomProxy.activeMembersCount)) + case .failure: + displayError() + } + } + + private func showDeclineInviteConfirmationAlert(roomID: String) { + guard let room = state.rooms.first(where: { $0.id == roomID }) else { + displayError() + return + } + + let roomPlaceholder = room.isDirect ? (room.inviter?.displayName ?? room.name) : room.name + let title = room.isDirect ? L10n.screenInvitesDeclineDirectChatTitle : L10n.screenInvitesDeclineChatTitle + let message = room.isDirect ? L10n.screenInvitesDeclineDirectChatMessage(roomPlaceholder) : L10n.screenInvitesDeclineChatMessage(roomPlaceholder) + + state.bindings.alertInfo = .init(id: UUID(), + title: title, + message: message, + primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil), + secondaryButton: .init(title: L10n.actionDecline, role: .destructive, action: { Task { await self.declineInvite(roomID: room.id) } })) + } + + private func declineInvite(roomID: String) async { + defer { + userIndicatorController.retractIndicatorWithId(roomID) + } + + userIndicatorController.submitIndicator(UserIndicator(id: roomID, type: .modal, title: L10n.commonLoading, persistent: true)) + + guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else { + displayError() + return + } + + let result = await roomProxy.rejectInvitation() + + if case .failure = result { + displayError() + } + } + + private func displayError() { + state.bindings.alertInfo = .init(id: UUID(), + title: L10n.commonError, + message: L10n.errorUnknown) + } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift index 1b1ac568e..2a45d259e 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift @@ -29,6 +29,15 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { case people case rooms case favourites + case invites + + static var availableFilters: [RoomListFilter] { + if ServiceLocator.shared.settings.roomListInvitesEnabled { + return RoomListFilter.allCases + } else { + return RoomListFilter.allCases.filter { !($0 == .invites) } + } + } var localizedName: String { switch self { @@ -40,20 +49,24 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { return L10n.screenRoomlistFilterUnreads case .favourites: return L10n.screenRoomlistFilterFavourites + case .invites: + return L10n.screenRoomlistFilterInvites } } - var incompatibleFilter: RoomListFilter? { + var incompatibleFilters: [RoomListFilter] { switch self { case .people: - return .rooms + return [.rooms, .invites] case .rooms: - return .people + return [.people, .invites] case .unreads: - return nil + return [.invites] case .favourites: // When we will have Low Priority we may need to return it here - return nil + return [.invites] + case .invites: + return [.rooms, .people, .unreads, .favourites] } } @@ -67,6 +80,8 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { return .unread case .favourites: return .favourite + case .invites: + return .invite } } } @@ -79,13 +94,13 @@ struct RoomListFiltersState { } var availableFilters: [RoomListFilter] { - var availableFilters = OrderedSet(RoomListFilter.allCases) + var availableFilters = OrderedSet(RoomListFilter.availableFilters) + for filter in activeFilters { availableFilters.remove(filter) - if let incompatibleFilter = filter.incompatibleFilter { - availableFilters.remove(incompatibleFilter) - } + filter.incompatibleFilters.forEach { availableFilters.remove($0) } } + return availableFilters.elements } @@ -94,10 +109,12 @@ struct RoomListFiltersState { } mutating func activateFilter(_ filter: RoomListFilter) { - if let incompatibleFilter = filter.incompatibleFilter, - activeFilters.contains(incompatibleFilter) { - fatalError("[RoomListFiltersState] adding mutually exclusive filters is not allowed") + filter.incompatibleFilters.forEach { incompatibleFilter in + if activeFilters.contains(incompatibleFilter) { + fatalError("[RoomListFiltersState] adding mutually exclusive filters is not allowed") + } } + // We always want the most recently enabled filter to be at the bottom of the others. activeFilters.append(filter) } diff --git a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift index 9ecc38d3a..1f6ad911e 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift @@ -30,6 +30,8 @@ struct RoomListFiltersEmptyStateView: View { return L10n.screenRoomlistFilterRoomsEmptyStateTitle case .favourites: return L10n.screenRoomlistFilterFavouritesEmptyStateTitle + case .invites: + return L10n.screenRoomlistFilterInvitesEmptyStateTitle } } return L10n.screenRoomlistFilterMixedEmptyStateTitle diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift new file mode 100644 index 000000000..4cbaaf085 --- /dev/null +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenInviteCell.swift @@ -0,0 +1,254 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Combine +import SwiftUI + +@MainActor +struct HomeScreenInviteCell: View { + @Environment(\.dynamicTypeSize) var dynamicTypeSize + + let room: HomeScreenRoom + let context: HomeScreenViewModel.Context + + var body: some View { + HStack(alignment: .top, spacing: 16) { + if dynamicTypeSize < .accessibility3 { + LoadableAvatarImage(url: room.avatarURL, + name: title, + contentID: room.id, + avatarSize: .custom(52), + imageProvider: context.imageProvider) + .dynamicTypeSize(dynamicTypeSize < .accessibility1 ? dynamicTypeSize : .accessibility1) + .accessibilityHidden(true) + } + + mainContent + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.bottom, 16) + .padding(.trailing, 16) + .overlay(alignment: .bottom) { + separator + } + } + .padding(.top, 12) + .padding(.leading, 16) + } + + // MARK: - Private + + private var mainContent: some View { + VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .firstTextBaseline, spacing: 16) { + textualContent + badge + } + + inviterView + .padding(.top, 6) + .padding(.trailing, 16) + + buttons + .padding(.top, 14) + .padding(.trailing, 22) + } + } + + @ViewBuilder + private var inviterView: some View { + if let invitedText = attributedInviteText, let name = room.inviter?.displayName { + HStack(alignment: .firstTextBaseline, spacing: 8) { + LoadableAvatarImage(url: room.inviter?.avatarURL, + name: name, + contentID: name, + avatarSize: .custom(16), + imageProvider: context.imageProvider) + .alignmentGuide(.firstTextBaseline) { $0[.bottom] * 0.8 } + + Text(invitedText) + } + } + } + + @ViewBuilder + private var textualContent: some View { + VStack(alignment: .leading, spacing: 0) { + Text(title) + .font(.compound.bodyLGSemibold) + .foregroundColor(.compound.textPrimary) + .lineLimit(2) + + if let subtitle { + Text(subtitle) + .font(.compound.bodyMD) + .foregroundColor(.compound.textPlaceholder) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + + private var buttons: some View { + HStack(spacing: 12) { + Button(L10n.actionDecline) { + context.send(viewAction: .declineInvite(roomIdentifier: room.id)) + } + .buttonStyle(.compound(.secondary, size: .medium)) + .accessibilityIdentifier(A11yIdentifiers.invitesScreen.decline) + + Button(L10n.actionAccept) { + context.send(viewAction: .acceptInvite(roomIdentifier: room.id)) + } + .buttonStyle(.compound(.primary, size: .medium)) + .accessibilityIdentifier(A11yIdentifiers.invitesScreen.accept) + } + } + + private var separator: some View { + Rectangle() + .fill(Color.compound.borderDisabled) + .frame(height: 1 / UIScreen.main.scale) + } + + private var title: String { + room.name + } + + private var subtitle: String? { + room.isDirect ? room.inviter?.userID : room.canonicalAlias + } + + private var attributedInviteText: AttributedString? { + guard + room.isDirect == false, + let inviterName = room.inviter?.displayName, + let inviterID = room.inviter?.userID + else { + return nil + } + + let text = L10n.screenInvitesInvitedYou(inviterName, inviterID) + var attributedString = AttributedString(text) + attributedString.font = .compound.bodyMD + attributedString.foregroundColor = .compound.textPlaceholder + if let range = attributedString.range(of: inviterName) { + attributedString[range].foregroundColor = .compound.textPrimary + attributedString[range].font = .compound.bodyMDSemibold + } + return attributedString + } + + private var badge: some View { + Circle() + .scaledFrame(size: 12) + .foregroundColor(.compound.iconAccentTertiary) + } +} + +struct HomeScreenInviteCell_Previews: PreviewProvider, TestablePreview { + static var previews: some View { + ScrollView { + VStack(spacing: 0) { + HomeScreenInviteCell(room: .dmInvite, + context: viewModel().context) + + HomeScreenInviteCell(room: .dmInvite, + context: viewModel().context) + + HomeScreenInviteCell(room: .roomInvite(), + context: viewModel().context) + + HomeScreenInviteCell(room: .roomInvite(), + context: viewModel().context) + + HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org", avatarURL: .picturesDirectory), + context: viewModel().context) + + HomeScreenInviteCell(room: .roomInvite(alias: "#footest:somewhere.org"), + context: viewModel().context) + .dynamicTypeSize(.accessibility1) + .previewDisplayName("Aliased room (AX1)") + } + } + } + + static func viewModel() -> HomeScreenViewModel { + let clientProxy = ClientProxyMock(.init()) + + let userSession = MockUserSession(clientProxy: clientProxy, + mediaProvider: MockMediaProvider(), + voiceMessageMediaManager: VoiceMessageMediaManagerMock()) + + return HomeScreenViewModel(userSession: userSession, + analyticsService: ServiceLocator.shared.analytics, + appSettings: ServiceLocator.shared.settings, + selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), + userIndicatorController: ServiceLocator.shared.userIndicatorController) + } +} + +@MainActor +private extension HomeScreenRoom { + static var dmInvite: HomeScreenRoom { + let inviter = RoomMemberProxyMock() + inviter.displayName = "Jack" + inviter.userID = "@jack:somewhere.com" + + let details = RoomSummaryDetails(id: "@someone:somewhere.com", + isInvite: false, + inviter: inviter, + name: "Some Guy", + isDirect: true, + avatarURL: nil, + lastMessage: nil, + lastMessageFormattedTimestamp: nil, + unreadMessagesCount: 0, + unreadMentionsCount: 0, + unreadNotificationsCount: 0, + notificationMode: nil, + canonicalAlias: "#footest:somewhere.org", + hasOngoingCall: false, + isMarkedUnread: false, + isFavourite: false) + + return .init(details: details, invalidated: false, hideUnreadMessagesBadge: false) + } + + static func roomInvite(alias: String? = nil, avatarURL: URL? = nil) -> HomeScreenRoom { + let inviter = RoomMemberProxyMock() + inviter.displayName = "Luca" + inviter.userID = "@jack:somewhi.nl" + inviter.avatarURL = avatarURL + + let details = RoomSummaryDetails(id: "@someone:somewhere.com", + isInvite: false, + inviter: inviter, + name: "Awesome Room", + isDirect: false, + avatarURL: avatarURL, + lastMessage: nil, + lastMessageFormattedTimestamp: nil, + unreadMessagesCount: 0, + unreadMentionsCount: 0, + unreadNotificationsCount: 0, + notificationMode: nil, + canonicalAlias: alias, + hasOngoingCall: false, + isMarkedUnread: false, + isFavourite: false) + + return .init(details: details, invalidated: false, hideUnreadMessagesBadge: false) + } +} diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift index 91b38583e..1cc17fb25 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift @@ -35,10 +35,13 @@ struct HomeScreenRoomList: View { @ViewBuilder private var content: some View { ForEach(context.viewState.visibleRooms) { room in - if room.isPlaceholder { + switch room.type { + case .placeholder: HomeScreenRoomCell(room: room, context: context, isSelected: false) .redacted(reason: .placeholder) - } else { + case .invite: + HomeScreenInviteCell(room: room, context: context) + case .room: let isSelected = context.viewState.selectedRoomID == room.id HomeScreenRoomCell(room: room, context: context, isSelected: isSelected) diff --git a/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift b/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift index 786823500..0e912ac73 100644 --- a/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift +++ b/ElementX/Sources/Screens/InvitesScreen/View/InvitesScreenCell.swift @@ -181,6 +181,8 @@ private extension InvitesScreenRoomDetails { inviter.userID = "@jack:somewhere.com" let dmRoom = RoomSummaryDetails(id: "@someone:somewhere.com", + isInvite: false, + inviter: inviter, name: "Some Guy", isDirect: true, avatarURL: nil, @@ -191,7 +193,6 @@ private extension InvitesScreenRoomDetails { unreadNotificationsCount: 0, notificationMode: nil, canonicalAlias: "#footest:somewhere.org", - inviter: inviter, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false) @@ -205,6 +206,8 @@ private extension InvitesScreenRoomDetails { inviter.avatarURL = avatarURL let dmRoom = RoomSummaryDetails(id: "@someone:somewhere.com", + isInvite: false, + inviter: inviter, name: "Awesome Room", isDirect: false, avatarURL: avatarURL, @@ -215,7 +218,6 @@ private extension InvitesScreenRoomDetails { unreadNotificationsCount: 0, notificationMode: nil, canonicalAlias: alias, - inviter: inviter, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false) diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index 32055debf..0e4d72242 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -51,6 +51,7 @@ protocol DeveloperOptionsProtocol: AnyObject { var elementCallBaseURL: URL { get set } var publicSearchEnabled: Bool { get set } var qrCodeLoginEnabled: Bool { get set } + var roomListInvitesEnabled: Bool { get set } } extension AppSettings: DeveloperOptionsProtocol { } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index 80c6b76fe..d1e0bd5aa 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -32,16 +32,15 @@ struct DeveloperOptionsScreen: View { } } - Section("Room") { - Toggle(isOn: $context.shouldCollapseRoomStateEvents) { - Text("Collapse room state events") - } - } - Section("Room List") { Toggle(isOn: $context.hideUnreadMessagesBadge) { Text("Hide grey dots") } + + Toggle(isOn: $context.roomListInvitesEnabled) { + Text("Room list invites") + Text("Requires app reboot and, after disabling the feature, a cache clear.") + } } Section("Room Directory Search") { @@ -56,6 +55,12 @@ struct DeveloperOptionsScreen: View { } } + Section("Room") { + Toggle(isOn: $context.shouldCollapseRoomStateEvents) { + Text("Collapse room state events") + } + } + Section("Element Call") { TextField(context.elementCallBaseURL.absoluteString, text: $elementCallBaseURLString) .submitLabel(.done) diff --git a/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift b/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift index 4dcb0a177..73ecc1172 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift @@ -64,9 +64,7 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { do { var homeserver = LoginHomeserver(address: homeserverAddress, loginMode: .unknown) - try await Task.dispatch(on: .global()) { - try self.authenticationService.configureHomeserver(serverNameOrHomeserverUrl: homeserverAddress) - } + try await authenticationService.configureHomeserver(serverNameOrHomeserverUrl: homeserverAddress) if let details = authenticationService.homeserverDetails() { if details.supportsOidcLogin() { @@ -94,9 +92,7 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { func urlForOIDCLogin() async -> Result { do { - let oidcData = try await Task.dispatch(on: .global()) { - try self.authenticationService.urlForOidcLogin() - } + let oidcData = try await authenticationService.urlForOidcLogin() return .success(OIDCAuthenticationDataProxy(underlyingData: oidcData)) } catch { MXLog.error("Failed to get URL for OIDC login: \(error)") @@ -106,9 +102,7 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { func loginWithOIDCCallback(_ callbackURL: URL, data: OIDCAuthenticationDataProxy) async -> Result { do { - let client = try await Task.dispatch(on: .global()) { - try self.authenticationService.loginWithOidcCallback(authenticationData: data.underlyingData, callbackUrl: callbackURL.absoluteString) - } + let client = try await authenticationService.loginWithOidcCallback(authenticationData: data.underlyingData, callbackUrl: callbackURL.absoluteString) return await userSession(for: client) } catch AuthenticationError.OidcCancelled { return .failure(.oidcError(.userCancellation)) @@ -120,12 +114,10 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { func login(username: String, password: String, initialDeviceName: String?, deviceID: String?) async -> Result { do { - let client = try await Task.dispatch(on: .global()) { - try self.authenticationService.login(username: username, - password: password, - initialDeviceName: initialDeviceName, - deviceId: deviceID) - } + let client = try await authenticationService.login(username: username, + password: password, + initialDeviceName: initialDeviceName, + deviceId: deviceID) let refreshToken = try? await Task.dispatch(on: .global()) { try client.session().refreshToken diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 57975876f..e6ccf0029 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -676,6 +676,7 @@ class ClientProxy: ClientProxyProtocol { .syncService() .withCrossProcessLock(appIdentifier: "MainApp") .withUtdHook(delegate: ClientDecryptionErrorDelegate(actionsSubject: actionsSubject)) + .withUnifiedInvitesInRoomList(withUnifiedInvites: appSettings.roomListInvitesEnabled) .finish() let roomListService = syncService.roomListService() diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift index 30504333b..9cbaf5ff3 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryDetails.swift @@ -19,6 +19,10 @@ import MatrixRustSDK struct RoomSummaryDetails { let id: String + + let isInvite: Bool + let inviter: RoomMemberProxyProtocol? + let name: String let isDirect: Bool let avatarURL: URL? @@ -29,7 +33,7 @@ struct RoomSummaryDetails { let unreadNotificationsCount: UInt let notificationMode: RoomNotificationModeProxy? let canonicalAlias: String? - let inviter: RoomMemberProxyProtocol? + let hasOngoingCall: Bool let isMarkedUnread: Bool @@ -70,6 +74,7 @@ extension RoomSummaryDetails { inviter = nil hasOngoingCall = false + isInvite = false isMarkedUnread = false isFavourite = false } diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index c7cadaa59..c986c0929 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -240,6 +240,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { let notificationMode = roomInfo.userDefinedNotificationMode.flatMap { RoomNotificationModeProxy.from(roomNotificationMode: $0) } let details = RoomSummaryDetails(id: roomInfo.id, + isInvite: roomInfo.membership == .invited, + inviter: inviterProxy, name: roomInfo.name ?? roomInfo.id, isDirect: roomInfo.isDirect, avatarURL: roomInfo.avatarUrl.flatMap(URL.init(string:)), @@ -250,7 +252,6 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { unreadNotificationsCount: UInt(roomInfo.numUnreadNotifications), notificationMode: notificationMode, canonicalAlias: roomInfo.canonicalAlias, - inviter: inviterProxy, hasOngoingCall: roomInfo.hasRoomCall, isMarkedUnread: roomInfo.isMarkedUnread, isFavourite: roomInfo.isFavourite) diff --git a/ElementX/Sources/Services/UserSession/UserSessionStore.swift b/ElementX/Sources/Services/UserSession/UserSessionStore.swift index 41867ec1c..b52628562 100644 --- a/ElementX/Sources/Services/UserSession/UserSessionStore.swift +++ b/ElementX/Sources/Services/UserSession/UserSessionStore.swift @@ -135,11 +135,12 @@ class UserSessionStore: UserSessionStoreProtocol { let completeBuilder = builder do { - let client: Client = try await Task.dispatch(on: .global()) { - let client = try completeBuilder.build() + let client = try await completeBuilder.build() + + try await Task.dispatch(on: .global()) { try client.restoreSession(session: credentials.restorationToken.session) - return client } + return await .success(setupProxyForClient(client)) } catch { MXLog.error("Failed restoring login with error: \(error)") diff --git a/NSE/Sources/NotificationServiceExtension.swift b/NSE/Sources/NotificationServiceExtension.swift index a710c2eaf..8ca8750f8 100644 --- a/NSE/Sources/NotificationServiceExtension.swift +++ b/NSE/Sources/NotificationServiceExtension.swift @@ -102,7 +102,7 @@ class NotificationServiceExtension: UNNotificationServiceExtension { if let existingSession = userSessions[credentials.userID] { userSession = existingSession } else { - userSession = try NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController) + userSession = try await NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController) userSessions[credentials.userID] = userSession } diff --git a/NSE/Sources/Other/NSEUserSession.swift b/NSE/Sources/Other/NSEUserSession.swift index 8dc0dec45..68aa878ee 100644 --- a/NSE/Sources/Other/NSEUserSession.swift +++ b/NSE/Sources/Other/NSEUserSession.swift @@ -26,7 +26,7 @@ final class NSEUserSession { backgroundTaskService: nil) private let delegateHandle: TaskHandle? - init(credentials: KeychainCredentials, clientSessionDelegate: ClientSessionDelegate) throws { + init(credentials: KeychainCredentials, clientSessionDelegate: ClientSessionDelegate) async throws { userID = credentials.userID if credentials.restorationToken.passphrase != nil { MXLog.info("Restoring client with encrypted store.") @@ -47,7 +47,7 @@ final class NSEUserSession { clientBuilder = clientBuilder.proxy(url: proxy) } - baseClient = try clientBuilder.build() + baseClient = try await clientBuilder.build() delegateHandle = baseClient.setDelegate(delegate: ClientDelegateWrapper()) try baseClient.restoreSession(session: credentials.restorationToken.session) diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPad-en-GB.1.png new file mode 100644 index 000000000..039af9927 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cabf6a20f8d84ac42aa8530004819d426242d47915c089ec5927780719117309 +size 360689 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPad-pseudo.1.png new file mode 100644 index 000000000..404805233 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79c93c11d00ffbfe680c98e028df77b5c52372e50f838b19cdaa898afe3af5b4 +size 455052 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPhone-15-en-GB.1.png new file mode 100644 index 000000000..130ab8ce3 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8b3de354e827b006e96a851c36151fd751b946762291aeff65be3d05d0a0b73 +size 264975 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPhone-15-pseudo.1.png new file mode 100644 index 000000000..5bc263764 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenInviteCell-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86d886ea902cb3e747687583d8d2d1f7234745417afcc7fe9663e5fc2a2baa0c +size 291401 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-en-GB.1.png index 3f0285113..12c6b6879 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:32a91eea55ad3f5390a8eb5c8c8d7f79fffac17116df7865c6ade85c489d86c9 -size 247608 +oid sha256:2ff3e0cca0d515e26e1576f96536ba0e229f5ef9d2b20654c086ca88fa246afb +size 294336 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-pseudo.1.png index 174909276..db2b3e0e4 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71f2bdf8a134778a7b26fd8c3b857b38c62acde81955cdabdd6a7d5937760fd3 -size 425764 +oid sha256:f416d687d23f4f24f646121b3ea66a80f0d58fea974dc800dfda8d8b8ca4c47d +size 502829 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-en-GB.1.png index b5d3ce8be..d3b897e33 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53654e9db6e2f3b17d0cdb508a385d32278e293aa5b0e4667bc4fae282f8989d -size 201757 +oid sha256:6a067031e3d80df5299cfb220adf6a5c233dea22b73d64a4c664bde1143131b1 +size 242738 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-pseudo.1.png index 80a3516a1..c48d1c416 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView-iPhone-15-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0738712af911e441559111153e78c16ed1813e233b84bdef059a3ba1329d61a -size 413471 +oid sha256:bae41f43a49692a0b544c3879baf34007cb647937c1e1f7930c0fdb01d490732 +size 488272 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png index 6ed798e02..2a955fff0 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab3efcdfc97332d810f01cb838ac615f0770121c2c1f0de42d393f68bda82ff8 -size 174129 +oid sha256:72957ae7c97f9744b9b193a5dcf29186496e61e9c499bf1c3f89b9ebbad59899 +size 168810 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png index ae619b740..ea4a34b8a 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3111ff0c737c3116be2be066883fe9c465cf11f87c010d72e858c9817c43b2f2 -size 182959 +oid sha256:d2d6da8197ab943403b33b3c4703baed7a17640088532f39d0981dcfee731fd4 +size 179473 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png index 22c682366..74d262783 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee8e9679c7c5fd3006b8e2f576f2b519955593dc98478982e73e9f13cc91947e -size 186442 +oid sha256:570000708276664f570068aa2d3d37c7653b1b6648ec40225c6506b4ca470738 +size 182423 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png index fb3d03bf6..f55b91f44 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e13e97f37061d85c029343f3150da714ce14f6729a738e7813fb17ca38e7878 -size 267815 +oid sha256:25533cfa9ee0295d1e013299cb86f878f56c19cb1a94b198166fe440bcee5626 +size 248296 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png index 6df916f76..bd48c4031 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:019a816ecb2b43f9173cf9c7f0a1bd33dc1fd18b8054226b0eb669cab27dde9b -size 285018 +oid sha256:65299eb62433150284141905f7e25362c2ff63efe8b700bb5c4775bd180d4f2b +size 280657 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png index 52f40680e..d0d0c3d16 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28ae819adccdbe3a102bfc2ad9da4ff62def05028ad5d6c7f1ebbf2f797a2558 -size 272591 +oid sha256:6692132cf228596dcbcdf91663d7f4e4eebbe573d1bbfc01133572d9c96ee2ac +size 268702 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png index 1b6fc412d..37f2d7ec1 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb1c63c646edd81cdaf6fef9e1303ae71262aaf20ba42957fece706861ad0c7e -size 123884 +oid sha256:0cd66e7405960fac0328a7b46c8a11ab3bd8d168f3090ea57c8a29dd48545180 +size 115724 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png index 0e95a0c61..b225dc552 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a01669ff928c0e666c3ed63f792687c4885a0aae5367a8ea76f6c367c9545a08 -size 132763 +oid sha256:0c87320e363289ed3486d0aea25bcd1c17a051bd2c1d340b31cdf3683b87a7f4 +size 129588 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png index d43e922d2..ef81075da 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35a14da7a9341751d62f96ff820ff732b4960fba569c5aabb6f2e9c5c8d30adc -size 133546 +oid sha256:0f4f2c03a1c6c050acf89f4d9e669f42d79074df82f17cad489e3fd21df07e0e +size 130421 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png index 08ecf7710..14fb9f7ea 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da2f523dae023dd72a82edb161668f407eca3bc6988dee12bd2a6b08170701f1 -size 196851 +oid sha256:6a2013d8dbbbba6a8a69fc37f42d5e5ca213d08a1edddf3ab10cf6bdb189b368 +size 175688 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png index c6be50935..3cec45fbd 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce892eda5eee6cdcb632db5e85952c1cc272ddc01c99055abb3c8361e22ce3d8 -size 233922 +oid sha256:2802157a26f19cc5efb27cb559cef947692f5c83f9adce1b938e188fe176d427 +size 224966 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png index 7518f6989..a9ef18b81 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d957f49d101b3580b8680b7aa93eb8aed9ec61d40e973f63e4628ab8115414d4 -size 226464 +oid sha256:c86b602e9a4296ddda51636137afc9ff3687d5f144e6a5418c240102ee4a8912 +size 218871 diff --git a/UnitTests/Sources/HomeScreenRoomTests.swift b/UnitTests/Sources/HomeScreenRoomTests.swift index c88ad6143..6c2f8ab3d 100644 --- a/UnitTests/Sources/HomeScreenRoomTests.swift +++ b/UnitTests/Sources/HomeScreenRoomTests.swift @@ -31,6 +31,8 @@ class HomeScreenRoomTests: XCTestCase { notificationMode: RoomNotificationModeProxy, hasOngoingCall: Bool) { roomSummaryDetails = RoomSummaryDetails(id: "Test room", + isInvite: false, + inviter: nil, name: "Test room", isDirect: false, avatarURL: nil, @@ -41,7 +43,6 @@ class HomeScreenRoomTests: XCTestCase { unreadNotificationsCount: unreadNotificationsCount, notificationMode: notificationMode, canonicalAlias: nil, - inviter: nil, hasOngoingCall: hasOngoingCall, isMarkedUnread: isMarkedUnread, isFavourite: false) diff --git a/UnitTests/Sources/LoggingTests.swift b/UnitTests/Sources/LoggingTests.swift index 5117991c4..e479c565c 100644 --- a/UnitTests/Sources/LoggingTests.swift +++ b/UnitTests/Sources/LoggingTests.swift @@ -87,6 +87,8 @@ class LoggingTests: XCTestCase { let roomName = "Private Conversation" let lastMessage = "Secret information" let roomSummary = RoomSummaryDetails(id: "myroomid", + isInvite: false, + inviter: nil, name: roomName, isDirect: true, avatarURL: nil, @@ -97,7 +99,6 @@ class LoggingTests: XCTestCase { unreadNotificationsCount: 0, notificationMode: nil, canonicalAlias: nil, - inviter: nil, hasOngoingCall: false, isMarkedUnread: false, isFavourite: false) diff --git a/UnitTests/Sources/RoomListFiltersStateTests.swift b/UnitTests/Sources/RoomListFiltersStateTests.swift index 786330cbd..89d6e75a7 100644 --- a/UnitTests/Sources/RoomListFiltersStateTests.swift +++ b/UnitTests/Sources/RoomListFiltersStateTests.swift @@ -28,7 +28,7 @@ final class RoomListFiltersStateTests: XCTestCase { func testInitialState() { XCTAssertFalse(state.isFiltering) XCTAssertEqual(state.activeFilters, []) - XCTAssertEqual(state.availableFilters, RoomListFilter.allCases) + XCTAssertEqual(state.availableFilters, RoomListFilter.allCases.filter { $0 != .invites }) } func testSetAndUnsetFilters() { @@ -39,7 +39,7 @@ final class RoomListFiltersStateTests: XCTestCase { state.deactivateFilter(.unreads) XCTAssertFalse(state.isFiltering) XCTAssertEqual(state.activeFilters, []) - XCTAssertEqual(state.availableFilters, RoomListFilter.allCases) + XCTAssertEqual(state.availableFilters, RoomListFilter.allCases.filter { $0 != .invites }) } func testMutuallyExclusiveFilters() { @@ -51,7 +51,7 @@ final class RoomListFiltersStateTests: XCTestCase { state.deactivateFilter(.people) XCTAssertFalse(state.isFiltering) XCTAssertEqual(state.activeFilters, []) - XCTAssertEqual(state.availableFilters, RoomListFilter.allCases) + XCTAssertEqual(state.availableFilters, RoomListFilter.allCases.filter { $0 != .invites }) state.activateFilter(.rooms) XCTAssertTrue(state.isFiltering) @@ -80,7 +80,7 @@ final class RoomListFiltersStateTests: XCTestCase { state.clearFilters() XCTAssertFalse(state.isFiltering) XCTAssertEqual(state.activeFilters, []) - XCTAssertEqual(state.availableFilters, RoomListFilter.allCases) + XCTAssertEqual(state.availableFilters, RoomListFilter.allCases.filter { $0 != .invites }) } func testOrder() { @@ -90,7 +90,7 @@ final class RoomListFiltersStateTests: XCTestCase { state.deactivateFilter(.favourites) XCTAssertEqual(state.activeFilters, []) - XCTAssertEqual(state.availableFilters, RoomListFilter.allCases) + XCTAssertEqual(state.availableFilters, RoomListFilter.allCases.filter { $0 != .invites }) state.activateFilter(.rooms) XCTAssertEqual(state.activeFilters, [.rooms]) diff --git a/project.yml b/project.yml index 14afe3265..b4706c6fc 100644 --- a/project.yml +++ b/project.yml @@ -48,7 +48,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/matrix-org/matrix-rust-components-swift - exactVersion: 1.1.56 + exactVersion: 1.1.57 # path: ../matrix-rust-sdk Compound: url: https://github.com/element-hq/compound-ios