From 3b8ad24d103b2d8e84636fe1b17f6f5af9272d77 Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Wed, 30 Jul 2025 16:42:45 +0200 Subject: [PATCH] SDK Update + PowerLevels API update (#4366) * update the sdk, and updated the power levels APIs Revert "update the sdk, and updated the power levels APIs" This reverts commit d3b291003d2b6fd6346ef7e445af4970fda62348. x * pr suggestions --- ElementX.xcodeproj/project.pbxproj | 65 ++++++++----------- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../Sources/Mocks/BannedRoomProxyMock.swift | 2 +- .../Mocks/Generated/GeneratedMocks.swift | 6 +- .../Sources/Mocks/InvitedRoomProxyMock.swift | 6 +- .../Sources/Mocks/JoinedRoomProxyMock.swift | 2 +- .../Sources/Mocks/KnockedRoomProxyMock.swift | 2 +- .../Sources/Mocks/RoomMemberProxyMock.swift | 8 +-- .../ManageRoomMemberSheetModels.swift | 2 +- .../View/ManageRoomMemberSheetView.swift | 4 +- ...RoomChangePermissionsScreenViewModel.swift | 2 +- .../RoomChangeRolesScreenViewModel.swift | 5 +- .../RoomMembersListScreenViewModel.swift | 2 +- ...omRolesAndPermissionsScreenViewModel.swift | 2 +- .../Screens/Timeline/TimelineViewModel.swift | 2 +- .../Sources/Services/Room/RoomInfoProxy.swift | 2 +- .../Services/Room/RoomInfoProxyProtocol.swift | 2 +- .../Room/RoomMember/RoomMemberDetails.swift | 5 +- .../Room/RoomMember/RoomMemberProxy.swift | 2 +- .../RoomMember/RoomMemberProxyProtocol.swift | 2 +- .../Services/Room/RoomPermissions.swift | 46 +++++++++---- .../Services/Room/RoomPowerLevel.swift | 41 ++++++++++++ .../Services/Room/RoomPowerLevelsProxy.swift | 9 ++- ...esAndPermissionsScreenViewModelTests.swift | 4 +- project.yml | 2 +- 25 files changed, 141 insertions(+), 88 deletions(-) create mode 100644 ElementX/Sources/Services/Room/RoomPowerLevel.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 4b6192718..1908923c8 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 77; + objectVersion = 63; objects = { /* Begin PBXAggregateTarget section */ @@ -898,6 +898,7 @@ A6DEC1ADEC8FEEC206A0FA37 /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */; }; A6F345328CCC5C9B0DAE2257 /* LogViewerScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */; }; A6FFC4C5154C446BAD6B40D8 /* TimelineItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8520AFD6680CBAD388F6D927 /* TimelineItemProvider.swift */; }; + A70A35082E3A3B15008E35D2 /* RoomPowerLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A70A35072E3A3B00008E35D2 /* RoomPowerLevel.swift */; }; A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; }; A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; }; A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; }; @@ -1448,7 +1449,7 @@ 044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = ""; }; 045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; }; 046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = ""; }; - 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = ""; }; 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; 0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = ""; }; @@ -1522,7 +1523,7 @@ 128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = ""; }; 12B09A94C519227264A41208 /* RoomMembershipDetailsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembershipDetailsProxy.swift; sourceTree = ""; }; 12FD5280AF55AB7F50F8E47D /* preview_avatar_room.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_avatar_room.jpg; sourceTree = ""; }; - 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = ""; }; + 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = ""; }; 130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = ""; }; 136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = ""; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -1630,7 +1631,7 @@ 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = ""; }; 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = ""; }; 260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = ""; }; - 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = ""; }; + 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = ""; }; 26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = ""; }; 26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = ""; }; 2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = ""; }; @@ -1709,7 +1710,7 @@ 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = ""; }; 35A057BA9BE0F079784CD061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = ""; }; 37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModel.swift; sourceTree = ""; }; 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringTests.swift; sourceTree = ""; }; @@ -2130,7 +2131,7 @@ 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; 8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitorMock.swift; sourceTree = ""; }; - 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = ""; }; + 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = ""; }; 8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = ""; }; 8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSDKMock.swift; sourceTree = ""; }; 8F062DD2CCD95DC33528A16F /* KnockRequestProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KnockRequestProxy.swift; sourceTree = ""; }; @@ -2248,6 +2249,7 @@ A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = ""; }; A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = ""; }; A6EA0D8B0BBD8805F7D5A133 /* TextBasedRoomTimelineViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineViewProtocol.swift; sourceTree = ""; }; + A70A35072E3A3B00008E35D2 /* RoomPowerLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPowerLevel.swift; sourceTree = ""; }; A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = ""; }; A768CA51A59B8A5D8C8FD599 /* AuthenticationStartScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreen.swift; sourceTree = ""; }; A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationTokenTests.swift; sourceTree = ""; }; @@ -2272,7 +2274,7 @@ AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = ""; }; AB07F03461023BC39C730922 /* PhishingDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingDetector.swift; sourceTree = ""; }; AB26D5444A4A7E095222DE8B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = ""; }; - AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; path = AccessibilityTests.xctestplan; sourceTree = ""; }; + AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = AccessibilityTests.xctestplan; sourceTree = ""; }; ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelProtocol.swift; sourceTree = ""; }; AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModelTests.swift; sourceTree = ""; }; AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageCache.swift; sourceTree = ""; }; @@ -2337,7 +2339,7 @@ B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = ""; }; B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = ""; }; B5D829FD8958376614504B18 /* TargetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetConfiguration.swift; sourceTree = ""; }; - B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = ""; }; + B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = ""; }; B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = ""; }; B65DDCF8E41759890355ACBC /* AuthenticationStartScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModelProtocol.swift; sourceTree = ""; }; B68B31232312AFC844440BFE /* DeclineAndBlockScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenModels.swift; sourceTree = ""; }; @@ -2364,7 +2366,7 @@ BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = ""; }; BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = ""; }; BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionProtocol.swift; sourceTree = ""; }; - BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; path = test_apple_image.heic; sourceTree = ""; }; + BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_apple_image.heic; sourceTree = ""; }; BB5B00A014307CE37B2812CD /* TimelineViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModelProtocol.swift; sourceTree = ""; }; BB6ED50FE104992419310EEB /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = ""; }; BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = ""; }; @@ -2462,7 +2464,7 @@ CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = ""; }; CDE3F3911FF7CC639BDE5844 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = ""; }; - CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = ""; }; + CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = ""; }; CFFA5E881D281810AB428EA3 /* RoomPowerLevelsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPowerLevelsProxy.swift; sourceTree = ""; }; D01FD1171FF40E34D707FD00 /* BigIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigIcon.swift; sourceTree = ""; }; D03D7ECAC68C2FFB8CF01BCB /* DeactivateAccountScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreen.swift; sourceTree = ""; }; @@ -2526,7 +2528,7 @@ DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotification+Creator.swift"; sourceTree = ""; }; DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelProtocol.swift; sourceTree = ""; }; DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandler.swift; sourceTree = ""; }; - DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; path = test_voice_message.m4a; sourceTree = ""; }; + DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = ""; }; DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModels.swift; sourceTree = ""; }; DCDAB580109C09A6AA97AF7E /* PollFormScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenTests.swift; sourceTree = ""; }; DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = ""; }; @@ -2571,7 +2573,7 @@ E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = ""; }; E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = ""; }; - E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = ""; }; + E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = ""; }; E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = ""; }; E5F2B6443D1ED8602F328539 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = ""; }; E5FDFAA04174CC99FB66391C /* EditRoomAddressScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenViewModel.swift; sourceTree = ""; }; @@ -2616,7 +2618,7 @@ ED0CBEAB5F796BEFBAF7BB6A /* VideoRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineView.swift; sourceTree = ""; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = ""; }; ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = ""; }; - ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = ""; }; + ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = ""; }; ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = ""; }; ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = ""; }; EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = ""; }; @@ -3723,6 +3725,7 @@ 40E6246F03D1FE377BC5D963 /* Room */ = { isa = PBXGroup; children = ( + A70A35072E3A3B00008E35D2 /* RoomPowerLevel.swift */, C30F45308428A4D9FFDB2FB8 /* BannedRoomProxy.swift */, 0E95B3BDB80531C85CD50AE6 /* InvitedRoomProxy.swift */, 07C6B0B087FE6601C3F77816 /* JoinedRoomProxy.swift */, @@ -6653,7 +6656,6 @@ EC6D0C817B1C21D9D096505A /* XCRemoteSwiftPackageReference "Version" */, EE40B0E16A55BD23ECBFFD22 /* XCRemoteSwiftPackageReference "matrix-rich-text-editor-swift" */, ); - preferredProjectObjectVersion = 77; projectDirPath = ""; projectRoot = ""; targets = ( @@ -7479,6 +7481,7 @@ 62C5876C4254C58C2086F0DE /* HomeScreenContent.swift in Sources */, 8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */, 77BB228AEA861E50FFD6A228 /* HomeScreenEmptyStateView.swift in Sources */, + A70A35082E3A3B15008E35D2 /* RoomPowerLevel.swift in Sources */, 22C5483D01EEB290B8339817 /* HomeScreenInviteCell.swift in Sources */, 86DFA58FBBEB0AF671D2A1E1 /* HomeScreenKnockedCell.swift in Sources */, 8810A2A30A68252EBB54EE05 /* HomeScreenModels.swift in Sources */, @@ -8390,9 +8393,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - OTHER_SWIFT_FLAGS = ( - "-DRELEASE", - ); + OTHER_SWIFT_FLAGS = "-DRELEASE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests"; PRODUCT_NAME = AccessibilityTests; SDKROOT = iphoneos; @@ -8411,9 +8412,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - OTHER_SWIFT_FLAGS = ( - "-DDEBUG", - ); + OTHER_SWIFT_FLAGS = "-DDEBUG"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests"; PRODUCT_NAME = AccessibilityTests; SDKROOT = iphoneos; @@ -8435,9 +8434,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_NSE", - ); + OTHER_SWIFT_FLAGS = "-DIS_NSE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_NAME = NSE; @@ -8486,9 +8483,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_MAIN_APP", - ); + OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(APP_NAME)"; @@ -8514,9 +8509,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_MAIN_APP", - ); + OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(APP_NAME)"; @@ -8741,9 +8734,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - OTHER_SWIFT_FLAGS = ( - "-DDEBUG", - ); + OTHER_SWIFT_FLAGS = "-DDEBUG"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests"; PRODUCT_NAME = UITests; SDKROOT = iphoneos; @@ -8762,9 +8753,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - OTHER_SWIFT_FLAGS = ( - "-DRELEASE", - ); + OTHER_SWIFT_FLAGS = "-DRELEASE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests"; PRODUCT_NAME = UITests; SDKROOT = iphoneos; @@ -8786,9 +8775,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_NSE", - ); + OTHER_SWIFT_FLAGS = "-DIS_NSE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_NAME = NSE; @@ -9036,7 +9023,7 @@ repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 25.07.23; + version = 25.07.29; }; }; 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9d04edecd..4baeb497e 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -158,8 +158,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/element-hq/matrix-rust-components-swift", "state" : { - "revision" : "4a9adc537b42360b525474b1122678cb3394817f", - "version" : "25.7.23" + "revision" : "98e28f3ad2b54525f6abb17ab8e2ad49e6bf3614", + "version" : "25.7.29" } }, { diff --git a/ElementX/Sources/Mocks/BannedRoomProxyMock.swift b/ElementX/Sources/Mocks/BannedRoomProxyMock.swift index ab94a4525..01be5af53 100644 --- a/ElementX/Sources/Mocks/BannedRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/BannedRoomProxyMock.swift @@ -32,7 +32,7 @@ extension RoomInfoProxyMock { id = configuration.id isEncrypted = false - creator = nil + creators = [] displayName = configuration.name rawName = nil topic = nil diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 035ae43c6..baf1b4b1a 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -13272,7 +13272,7 @@ class RoomInfoProxyMock: RoomInfoProxyProtocol, @unchecked Sendable { set(value) { underlyingId = value } } var underlyingId: String! - var creator: String? + var creators: [String] = [] var displayName: String? var rawName: String? var topic: String? @@ -13393,11 +13393,11 @@ class RoomMemberProxyMock: RoomMemberProxyProtocol, @unchecked Sendable { set(value) { underlyingIsIgnored = value } } var underlyingIsIgnored: Bool! - var powerLevel: Int { + var powerLevel: RoomPowerLevel { get { return underlyingPowerLevel } set(value) { underlyingPowerLevel = value } } - var underlyingPowerLevel: Int! + var underlyingPowerLevel: RoomPowerLevel! var role: RoomMemberRole { get { return underlyingRole } set(value) { underlyingRole = value } diff --git a/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift b/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift index 6e9c68f25..d34ce9214 100644 --- a/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/InvitedRoomProxyMock.swift @@ -36,7 +36,7 @@ extension RoomInfoProxyMock { id = configuration.id isEncrypted = false - creator = nil + creators = [] displayName = configuration.name rawName = nil topic = nil @@ -79,8 +79,8 @@ private extension RoomMember { avatarUrl: proxy.avatarURL?.absoluteString, membership: proxy.membership, isNameAmbiguous: proxy.disambiguatedDisplayName != proxy.displayName, - powerLevel: Int64(proxy.powerLevel), - normalizedPowerLevel: Int64(proxy.powerLevel), + powerLevel: proxy.powerLevel.rustPowerLevel, + normalizedPowerLevel: proxy.powerLevel.rustPowerLevel, isIgnored: proxy.isIgnored, suggestedRoleForPowerLevel: proxy.role, membershipChangeReason: proxy.membershipChangeReason) diff --git a/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift b/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift index 20bc69b1d..132011d4c 100644 --- a/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/JoinedRoomProxyMock.swift @@ -165,7 +165,7 @@ extension RoomInfoProxyMock { id = configuration.id isEncrypted = configuration.isEncrypted - creator = nil + creators = [] displayName = configuration.name rawName = configuration.name topic = configuration.topic diff --git a/ElementX/Sources/Mocks/KnockedRoomProxyMock.swift b/ElementX/Sources/Mocks/KnockedRoomProxyMock.swift index d205f8089..4263ed94a 100644 --- a/ElementX/Sources/Mocks/KnockedRoomProxyMock.swift +++ b/ElementX/Sources/Mocks/KnockedRoomProxyMock.swift @@ -32,7 +32,7 @@ extension RoomInfoProxyMock { id = configuration.id isEncrypted = false - creator = nil + creators = [] displayName = configuration.name rawName = nil topic = nil diff --git a/ElementX/Sources/Mocks/RoomMemberProxyMock.swift b/ElementX/Sources/Mocks/RoomMemberProxyMock.swift index b894279d4..de9fa1328 100644 --- a/ElementX/Sources/Mocks/RoomMemberProxyMock.swift +++ b/ElementX/Sources/Mocks/RoomMemberProxyMock.swift @@ -16,7 +16,7 @@ struct RoomMemberProxyMockConfiguration { var membership: MembershipState var isIgnored = false - var powerLevel = 0 + var powerLevel = RoomPowerLevel(value: 0) var role = RoomMemberRole.user } @@ -52,7 +52,7 @@ extension RoomMemberProxyMock { displayName: "Me", avatarURL: .mockMXCUserAvatar, membership: .join, - powerLevel: 100, + powerLevel: .init(value: 100), role: .administrator)) } @@ -116,7 +116,7 @@ extension RoomMemberProxyMock { RoomMemberProxyMock(with: .init(userID: "@admin:matrix.org", displayName: "Arthur", membership: .join, - powerLevel: 100, + powerLevel: .init(value: 100), role: .administrator)) } @@ -124,7 +124,7 @@ extension RoomMemberProxyMock { RoomMemberProxyMock(with: .init(userID: "@mod:matrix.org", displayName: "Merlin", membership: .join, - powerLevel: 50, + powerLevel: .init(value: 50), role: .moderator)) } diff --git a/ElementX/Sources/Screens/ManageRoomMemberSheet/ManageRoomMemberSheetModels.swift b/ElementX/Sources/Screens/ManageRoomMemberSheet/ManageRoomMemberSheetModels.swift index 772c2cdf4..13a0533cb 100644 --- a/ElementX/Sources/Screens/ManageRoomMemberSheet/ManageRoomMemberSheetModels.swift +++ b/ElementX/Sources/Screens/ManageRoomMemberSheet/ManageRoomMemberSheetModels.swift @@ -86,5 +86,5 @@ enum ManageRoomMemberDetails { struct ManageRoomMemberPermissions { let canKick: Bool let canBan: Bool - let ownPowerLevel: Int + let ownPowerLevel: RoomPowerLevel } diff --git a/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift b/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift index 19d69e6b4..83bd19e8e 100644 --- a/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift +++ b/ElementX/Sources/Screens/ManageRoomMemberSheet/View/ManageRoomMemberSheetView.swift @@ -74,7 +74,7 @@ struct ManageRoomMemberSheetView: View { struct ManageRoomMemberSheetView_Previews: PreviewProvider, TestablePreview { static let allActionsViewModel = ManageRoomMemberSheetViewModel.mock() - static let allActionsDisabledViewModel = ManageRoomMemberSheetViewModel.mock(powerLevel: 0) + static let allActionsDisabledViewModel = ManageRoomMemberSheetViewModel.mock(powerLevel: .init(value: 0)) static let kickOnlyViewModel = ManageRoomMemberSheetViewModel.mock(canBan: false) @@ -100,7 +100,7 @@ private extension ManageRoomMemberSheetViewModel { static func mock(canKick: Bool = true, canBan: Bool = true, memberIsBanned: Bool = false, - powerLevel: Int = 100) -> ManageRoomMemberSheetViewModel { + powerLevel: RoomPowerLevel = .init(value: 100)) -> ManageRoomMemberSheetViewModel { let member = if memberIsBanned { RoomMemberDetails(withProxy: RoomMemberProxyMock.mockBanned[0]) } else { diff --git a/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenViewModel.swift b/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenViewModel.swift index d5d37a6ca..8e901cfc1 100644 --- a/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomChangePermissionsScreen/RoomChangePermissionsScreenViewModel.swift @@ -62,7 +62,7 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel var changes = RoomPowerLevelChanges() let changedSettings = state.bindings.settings.filter { state.currentPermissions[keyPath: $0.keyPath] != $0.value } for setting in changedSettings { - changes[keyPath: setting.rustKeyPath] = setting.value.rustPowerLevel + changes[keyPath: setting.rustKeyPath] = setting.value.powerLevelValue } switch await roomProxy.applyPowerLevelChanges(changes) { diff --git a/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift b/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift index 3de89a37d..b40126479 100644 --- a/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomChangeRolesScreen/RoomChangeRolesScreenViewModel.swift @@ -86,7 +86,8 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh let memberDetails = RoomMemberDetails(withProxy: member) switch member.role { - case .administrator: + // TODO: Create a owner list + case .administrator, .creator: administrators.append(memberDetails) case .moderator: moderators.append(memberDetails) @@ -139,7 +140,7 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh hideSavingIndicator() } - let promotingUpdates = state.membersToPromote.map { ($0.id, state.mode.rustPowerLevel) } + let promotingUpdates = state.membersToPromote.map { ($0.id, state.mode.powerLevelValue) } 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. diff --git a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift index e3f28fe9e..3dd08c98a 100644 --- a/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomMemberListScreen/RoomMembersListScreenViewModel.swift @@ -154,7 +154,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe let manageMemeberViewModel = ManageRoomMemberSheetViewModel(memberDetails: .memberDetails(roomMember: member), permissions: .init(canKick: state.canKickUsers, canBan: state.canBanUsers, - ownPowerLevel: currentUserProxy?.powerLevel ?? 0), + ownPowerLevel: currentUserProxy?.powerLevel ?? .init(value: 0)), roomProxy: roomProxy, userIndicatorController: userIndicatorController, analyticsService: analytics, diff --git a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift index 0bc9277f2..e7b8e13bb 100644 --- a/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomRolesAndPermissionsScreen/RoomRolesAndPermissionsScreenViewModel.swift @@ -95,7 +95,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM // 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.powerLevelValue)]) { case .success: _ = await infoTask.value await roomProxy.updateMembers() diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index 0059264d8..091bd5802 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -285,7 +285,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { let viewModel = ManageRoomMemberSheetViewModel(memberDetails: memberDetails, permissions: .init(canKick: state.canCurrentUserKick, canBan: state.canCurrentUserBan, - ownPowerLevel: currentUserProxy?.powerLevel ?? 0), + ownPowerLevel: currentUserProxy?.powerLevel ?? .init(value: 0)), roomProxy: roomProxy, userIndicatorController: userIndicatorController, analyticsService: analyticsService, diff --git a/ElementX/Sources/Services/Room/RoomInfoProxy.swift b/ElementX/Sources/Services/Room/RoomInfoProxy.swift index 260169597..77a048cbc 100644 --- a/ElementX/Sources/Services/Room/RoomInfoProxy.swift +++ b/ElementX/Sources/Services/Room/RoomInfoProxy.swift @@ -12,7 +12,7 @@ struct RoomInfoProxy: RoomInfoProxyProtocol { let roomInfo: RoomInfo var id: String { roomInfo.id } - var creator: String? { roomInfo.creator } + var creators: [String] { roomInfo.creators ?? [] } var displayName: String? { roomInfo.displayName } var rawName: String? { roomInfo.rawName } var topic: String? { roomInfo.topic } diff --git a/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift index 28280c16b..4905b1c69 100644 --- a/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomInfoProxyProtocol.swift @@ -26,7 +26,7 @@ protocol BaseRoomInfoProxyProtocol { // sourcery: AutoMockable protocol RoomInfoProxyProtocol: BaseRoomInfoProxyProtocol { var id: String { get } - var creator: String? { get } + var creators: [String] { get } var displayName: String? { get } var rawName: String? { get } var topic: String? { get } diff --git a/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift b/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift index 230177bd4..435c3bdd3 100644 --- a/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift +++ b/ElementX/Sources/Services/Room/RoomMember/RoomMemberDetails.swift @@ -21,7 +21,7 @@ struct RoomMemberDetails: Identifiable, Hashable { enum Role { case administrator, moderator, user } let role: Role - let powerLevel: Int + let powerLevel: RoomPowerLevel func matches(searchQuery: String) -> Bool { guard !searchQuery.isEmpty else { return true } @@ -47,7 +47,8 @@ extension RoomMemberDetails { extension RoomMemberDetails.Role { init(_ role: RoomMemberRole) { self = switch role { - case .administrator: .administrator + // TODO: Implement creator role + case .creator, .administrator: .administrator case .moderator: .moderator case .user: .user } diff --git a/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxy.swift b/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxy.swift index 308531480..0bbfc6ba0 100644 --- a/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxy.swift +++ b/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxy.swift @@ -35,7 +35,7 @@ final class RoomMemberProxy: RoomMemberProxyProtocol { var isIgnored: Bool { member.isIgnored } - var powerLevel: Int { Int(member.powerLevel) } + var powerLevel: RoomPowerLevel { .init(rustPowerLevel: member.powerLevel) } var role: RoomMemberRole { member.suggestedRoleForPowerLevel } } diff --git a/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift b/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift index 48129339c..f37f95aee 100644 --- a/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomMember/RoomMemberProxyProtocol.swift @@ -23,7 +23,7 @@ protocol RoomMemberProxyProtocol: AnyObject { var isIgnored: Bool { get } - var powerLevel: Int { get } + var powerLevel: RoomPowerLevel { get } var role: RoomMemberRole { get } } diff --git a/ElementX/Sources/Services/Room/RoomPermissions.swift b/ElementX/Sources/Services/Room/RoomPermissions.swift index 4d49d3536..24042c3b2 100644 --- a/ElementX/Sources/Services/Room/RoomPermissions.swift +++ b/ElementX/Sources/Services/Room/RoomPermissions.swift @@ -71,22 +71,27 @@ struct RoomPermissions { extension RoomPermissions { /// Create permissions from the room's power levels. init(powerLevels: RoomPowerLevelsValues) { - ban = RoomMemberDetails.Role(rustPowerLevel: powerLevels.ban) - invite = RoomMemberDetails.Role(rustPowerLevel: powerLevels.invite) - kick = RoomMemberDetails.Role(rustPowerLevel: powerLevels.kick) - redact = RoomMemberDetails.Role(rustPowerLevel: powerLevels.redact) - eventsDefault = RoomMemberDetails.Role(rustPowerLevel: powerLevels.eventsDefault) - stateDefault = RoomMemberDetails.Role(rustPowerLevel: powerLevels.stateDefault) - usersDefault = RoomMemberDetails.Role(rustPowerLevel: powerLevels.usersDefault) - roomName = RoomMemberDetails.Role(rustPowerLevel: powerLevels.roomName) - roomAvatar = RoomMemberDetails.Role(rustPowerLevel: powerLevels.roomAvatar) - roomTopic = RoomMemberDetails.Role(rustPowerLevel: powerLevels.roomTopic) + ban = RoomMemberDetails.Role(powerLevelValue: powerLevels.ban) + invite = RoomMemberDetails.Role(powerLevelValue: powerLevels.invite) + kick = RoomMemberDetails.Role(powerLevelValue: powerLevels.kick) + redact = RoomMemberDetails.Role(powerLevelValue: powerLevels.redact) + eventsDefault = RoomMemberDetails.Role(powerLevelValue: powerLevels.eventsDefault) + stateDefault = RoomMemberDetails.Role(powerLevelValue: powerLevels.stateDefault) + usersDefault = RoomMemberDetails.Role(powerLevelValue: powerLevels.usersDefault) + roomName = RoomMemberDetails.Role(powerLevelValue: powerLevels.roomName) + roomAvatar = RoomMemberDetails.Role(powerLevelValue: powerLevels.roomAvatar) + roomTopic = RoomMemberDetails.Role(powerLevelValue: powerLevels.roomTopic) } } extension RoomMemberDetails.Role { - init(rustPowerLevel: Int64) { - self.init(suggestedRoleForPowerLevel(powerLevel: rustPowerLevel)) + init(powerLevelValue: Int64) { + do { + try self.init(suggestedRoleForPowerLevel(powerLevel: .value(value: powerLevelValue))) + } catch { + MXLog.error("Falied to convert power level value to role: \(error)") + self.init(.user) + } } var rustRole: RoomMemberRole { @@ -100,7 +105,20 @@ extension RoomMemberDetails.Role { } } - var rustPowerLevel: Int64 { - suggestedPowerLevelForRole(role: rustRole) + /// To be used when setting the power level of a user to get the suggested equivalent power level value for that specific role + /// NOTE: Do not use for comparison, use the true power level instead. + var powerLevelValue: Int64 { + do { + switch try suggestedPowerLevelForRole(role: rustRole) { + case .infinite: + // Would be better if the SDK would return this, maybe a `suggestedPowerLevelValueForRole` function would solve the problem + return 150 + case .value(let value): + return value + } + } catch { + MXLog.error("Falied to convert role to power level value: \(error)") + return 0 + } } } diff --git a/ElementX/Sources/Services/Room/RoomPowerLevel.swift b/ElementX/Sources/Services/Room/RoomPowerLevel.swift new file mode 100644 index 000000000..830b18cf6 --- /dev/null +++ b/ElementX/Sources/Services/Room/RoomPowerLevel.swift @@ -0,0 +1,41 @@ +// +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import MatrixRustSDK + +enum RoomPowerLevel: Hashable, Comparable { + case value(Int) + case infinite + + init(rustPowerLevel: PowerLevel) { + self = rustPowerLevel.toRoomPowerLevel + } + + init(value: Int) { + self = .value(value) + } + + init(value: Int64) { + self = .value(Int(value)) + } + + var rustPowerLevel: PowerLevel { + switch self { + case .infinite: .infinite + case .value(let value): .value(value: Int64(value)) + } + } +} + +extension PowerLevel { + var toRoomPowerLevel: RoomPowerLevel { + switch self { + case .infinite: .infinite + case .value(let value): .value(Int(value)) + } + } +} diff --git a/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift b/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift index aeb3588ec..c2dfe1920 100644 --- a/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift +++ b/ElementX/Sources/Services/Room/RoomPowerLevelsProxy.swift @@ -27,8 +27,13 @@ struct RoomPowerLevelsProxy: RoomPowerLevelsProxyProtocol { } func suggestedRole(forUser userID: String) -> RoomMemberRole { - let powerLevel = powerLevels.userPowerLevels()[userID] ?? values.usersDefault - return suggestedRoleForPowerLevel(powerLevel: powerLevel) + do { + let powerLevelValue = powerLevels.userPowerLevels()[userID] ?? values.usersDefault + return try suggestedRoleForPowerLevel(powerLevel: .value(value: powerLevelValue)) + } catch { + MXLog.error("Falied to get suggested role for user: \(error)") + return .user + } } func canOwnUser(sendMessage messageType: MessageLikeEventType) -> Bool { diff --git a/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift b/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift index 124d50204..aef3cf289 100644 --- a/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomRolesAndPermissionsScreenViewModelTests.swift @@ -55,7 +55,7 @@ class RoomRolesAndPermissionsScreenViewModelTests: XCTestCase { XCTAssertTrue(roomProxy.updatePowerLevelsForUsersCalled) XCTAssertEqual(roomProxy.updatePowerLevelsForUsersReceivedUpdates?.first?.powerLevel, - RoomMemberDetails.Role.moderator.rustPowerLevel) + RoomMemberDetails.Role.moderator.powerLevelValue) } func testDemoteToMember() async throws { @@ -70,7 +70,7 @@ class RoomRolesAndPermissionsScreenViewModelTests: XCTestCase { XCTAssertTrue(roomProxy.updatePowerLevelsForUsersCalled) XCTAssertEqual(roomProxy.updatePowerLevelsForUsersReceivedUpdates?.first?.powerLevel, - RoomMemberDetails.Role.user.rustPowerLevel) + RoomMemberDetails.Role.user.powerLevelValue) } private func setupViewModel(members: [RoomMemberProxyMock]) { diff --git a/project.yml b/project.yml index 30799a955..e55c7b0f3 100644 --- a/project.yml +++ b/project.yml @@ -68,7 +68,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/element-hq/matrix-rust-components-swift - exactVersion: 25.07.23 + exactVersion: 25.07.29 # path: ../matrix-rust-sdk Compound: url: https://github.com/element-hq/compound-ios