Pinned events banner loading state (#3118)

This commit is contained in:
Mauro
2024-08-06 15:46:56 +02:00
committed by GitHub
parent 0c9da2cee9
commit 08347e15a5
26 changed files with 468 additions and 113 deletions
+24 -24
View File
@@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 54; objectVersion = 56;
objects = { objects = {
/* Begin PBXAggregateTarget section */ /* Begin PBXAggregateTarget section */
@@ -731,6 +731,8 @@
A6F345328CCC5C9B0DAE2257 /* LogViewerScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */; }; A6F345328CCC5C9B0DAE2257 /* LogViewerScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */; };
A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; }; A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; };
A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; }; A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; };
A7580E042C622A5300A0991D /* PinnedEventsBannerStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7580E032C622A5300A0991D /* PinnedEventsBannerStateTests.swift */; };
A75B3BF22C61460B000CE956 /* NetworkMonitorMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75B3BF12C61460B000CE956 /* NetworkMonitorMock.swift */; };
A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; }; A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; };
A816F7087C495D85048AC50E /* RoomMemberDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */; }; A816F7087C495D85048AC50E /* RoomMemberDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */; };
A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; }; A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; };
@@ -1174,13 +1176,13 @@
033DB41C51865A2E83174E87 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; }; 033DB41C51865A2E83174E87 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
035177BCD8E8308B098AC3C2 /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = "<group>"; }; 035177BCD8E8308B098AC3C2 /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = "<group>"; };
0376C429FAB1687C3D905F3E /* MockCoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCoder.swift; sourceTree = "<group>"; }; 0376C429FAB1687C3D905F3E /* MockCoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCoder.swift; sourceTree = "<group>"; };
0392E3FDE372C9B56FEEED8B /* test_voice_message.m4a */ = {isa = PBXFileReference; path = test_voice_message.m4a; sourceTree = "<group>"; }; 0392E3FDE372C9B56FEEED8B /* test_voice_message.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = "<group>"; };
03DD998E523D4EC93C7ED703 /* RoomNotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 03DD998E523D4EC93C7ED703 /* RoomNotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
03FABD73FD8086EFAB699F42 /* MediaUploadPreviewScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenViewModelTests.swift; sourceTree = "<group>"; }; 03FABD73FD8086EFAB699F42 /* MediaUploadPreviewScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenViewModelTests.swift; sourceTree = "<group>"; };
044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = "<group>"; }; 044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = "<group>"; };
045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; }; 045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = "<group>"; }; 046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = "<group>"; };
048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = "<group>"; }; 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = "<group>"; };
04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = "<group>"; }; 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = "<group>"; };
0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = "<group>"; }; 0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = "<group>"; };
@@ -1240,7 +1242,7 @@
127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = "<group>"; }; 127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = "<group>"; };
128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; }; 128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; };
12F1E7F9C2BE8BB751037826 /* WaitlistScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenCoordinator.swift; sourceTree = "<group>"; }; 12F1E7F9C2BE8BB751037826 /* WaitlistScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenCoordinator.swift; sourceTree = "<group>"; };
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = "<group>"; }; 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; }; 130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = "<group>"; }; 136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = "<group>"; };
13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -1331,7 +1333,7 @@
25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = "<group>"; }; 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = "<group>"; };
25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = "<group>"; }; 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = "<group>"; };
260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = "<group>"; }; 260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = "<group>"; };
267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = "<group>"; }; 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = "<group>"; };
26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = "<group>"; }; 26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = "<group>"; };
26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = "<group>"; }; 26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = "<group>"; };
2721D7B051F0159AA919DA05 /* RoomChangePermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 2721D7B051F0159AA919DA05 /* RoomChangePermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
@@ -1396,7 +1398,7 @@
3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = "<group>"; }; 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = "<group>"; };
35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
35FA991289149D31F4286747 /* UserPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreference.swift; sourceTree = "<group>"; }; 35FA991289149D31F4286747 /* UserPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreference.swift; sourceTree = "<group>"; };
36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; }; 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; };
376D941BF8BB294389C0DE24 /* MapTilerURLBuildersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerURLBuildersTests.swift; sourceTree = "<group>"; }; 376D941BF8BB294389C0DE24 /* MapTilerURLBuildersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerURLBuildersTests.swift; sourceTree = "<group>"; };
37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItem.swift; sourceTree = "<group>"; }; 37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItem.swift; sourceTree = "<group>"; };
@@ -1745,7 +1747,7 @@
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; }; 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; }; 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; }; 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; };
8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = "<group>"; }; 8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = "<group>"; };
8F21ED7205048668BEB44A38 /* AppActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppActivityView.swift; sourceTree = "<group>"; }; 8F21ED7205048668BEB44A38 /* AppActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppActivityView.swift; sourceTree = "<group>"; };
8F6210134203BE1F2DD5C679 /* RoomDirectoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectoryCell.swift; sourceTree = "<group>"; }; 8F6210134203BE1F2DD5C679 /* RoomDirectoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectoryCell.swift; sourceTree = "<group>"; };
@@ -1840,6 +1842,8 @@
A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = "<group>"; }; A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = "<group>"; };
A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = "<group>"; }; A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = "<group>"; };
A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; }; A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; };
A7580E032C622A5300A0991D /* PinnedEventsBannerStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsBannerStateTests.swift; sourceTree = "<group>"; };
A75B3BF12C61460B000CE956 /* NetworkMonitorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitorMock.swift; sourceTree = "<group>"; };
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; }; A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = "<group>"; }; A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = "<group>"; }; A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = "<group>"; };
@@ -1909,7 +1913,7 @@
B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = "<group>"; }; B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = "<group>"; };
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; }; B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; };
B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; }; B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; }; B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; };
B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = "<group>"; }; B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = "<group>"; };
B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = "<group>"; }; B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = "<group>"; };
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; }; B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; };
@@ -2022,7 +2026,7 @@
CE47A97726F0675DEE387BF9 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = "<group>"; }; CE47A97726F0675DEE387BF9 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = "<group>"; };
CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; }; CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = "<group>"; }; CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; }; CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; }; D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; };
D086854995173E897F993C26 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; D086854995173E897F993C26 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
D09A267106B9585D3D0CFC0D /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = "<group>"; }; D09A267106B9585D3D0CFC0D /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = "<group>"; };
@@ -2150,7 +2154,7 @@
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; }; ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; }; ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; };
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; }; ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; };
ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = "<group>"; }; ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = "<group>"; };
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; }; ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; }; EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
@@ -2173,7 +2177,7 @@
F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = "<group>"; }; F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = "<group>"; };
F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = "<group>"; }; F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = "<group>"; };
F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = "<group>"; }; F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = "<group>"; };
F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = "<group>"; }; F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = "<group>"; };
F2E4EF80DFB8FE7C4469B15D /* RoomDirectorySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreen.swift; sourceTree = "<group>"; }; F2E4EF80DFB8FE7C4469B15D /* RoomDirectorySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreen.swift; sourceTree = "<group>"; };
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; }; F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; }; F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
@@ -2773,6 +2777,7 @@
AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */, AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */,
F4469F6AE311BDC439B3A5EC /* UserSessionMock.swift */, F4469F6AE311BDC439B3A5EC /* UserSessionMock.swift */,
B23135B06B044CB811139D2F /* Generated */, B23135B06B044CB811139D2F /* Generated */,
A75B3BF12C61460B000CE956 /* NetworkMonitorMock.swift */,
); );
path = Mocks; path = Mocks;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3738,6 +3743,7 @@
7583EAC171059A86B767209F /* MediaProvider */, 7583EAC171059A86B767209F /* MediaProvider */,
7DBC911559934065993A5FF4 /* NotificationManager */, 7DBC911559934065993A5FF4 /* NotificationManager */,
1C62F5382CC9D9F7DCEC344A /* UserDiscoveryService */, 1C62F5382CC9D9F7DCEC344A /* UserDiscoveryService */,
A7580E032C622A5300A0991D /* PinnedEventsBannerStateTests.swift */,
); );
path = Sources; path = Sources;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -5979,6 +5985,7 @@
04F17DE71A50206336749BAC /* UserPreferenceTests.swift in Sources */, 04F17DE71A50206336749BAC /* UserPreferenceTests.swift in Sources */,
73F547BEB41D3DAFAAF6E0AF /* UserProfileScreenViewModelTests.swift in Sources */, 73F547BEB41D3DAFAAF6E0AF /* UserProfileScreenViewModelTests.swift in Sources */,
627139A3D79F032BA81E3A53 /* UserSessionFlowCoordinatorTests.swift in Sources */, 627139A3D79F032BA81E3A53 /* UserSessionFlowCoordinatorTests.swift in Sources */,
A7580E042C622A5300A0991D /* PinnedEventsBannerStateTests.swift in Sources */,
81A7C020CB5F6232242A8414 /* UserSessionTests.swift in Sources */, 81A7C020CB5F6232242A8414 /* UserSessionTests.swift in Sources */,
21AFEFB8CEFE56A3811A1F5B /* VoiceMessageCacheTests.swift in Sources */, 21AFEFB8CEFE56A3811A1F5B /* VoiceMessageCacheTests.swift in Sources */,
44BDD670FF9095ACE240A3A2 /* VoiceMessageMediaManagerTests.swift in Sources */, 44BDD670FF9095ACE240A3A2 /* VoiceMessageMediaManagerTests.swift in Sources */,
@@ -6005,6 +6012,7 @@
34433A509DFEC93579B3B35B /* AdvancedSettingsScreen.swift in Sources */, 34433A509DFEC93579B3B35B /* AdvancedSettingsScreen.swift in Sources */,
4557192F5B15A8D9BB920232 /* AdvancedSettingsScreenCoordinator.swift in Sources */, 4557192F5B15A8D9BB920232 /* AdvancedSettingsScreenCoordinator.swift in Sources */,
0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */, 0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */,
A75B3BF22C61460B000CE956 /* NetworkMonitorMock.swift in Sources */,
B879446FD8E65A711EF8F9F7 /* AdvancedSettingsScreenViewModel.swift in Sources */, B879446FD8E65A711EF8F9F7 /* AdvancedSettingsScreenViewModel.swift in Sources */,
62910B515BCB4B455E24D7C1 /* AdvancedSettingsScreenViewModelProtocol.swift in Sources */, 62910B515BCB4B455E24D7C1 /* AdvancedSettingsScreenViewModelProtocol.swift in Sources */,
53C1E7F6A7D6409D89F36ED7 /* AggregatedReactionMock.swift in Sources */, 53C1E7F6A7D6409D89F36ED7 /* AggregatedReactionMock.swift in Sources */,
@@ -7016,9 +7024,7 @@
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = ( OTHER_SWIFT_FLAGS = "-DIS_NSE";
"-DIS_NSE",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse";
PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
PRODUCT_NAME = NSE; PRODUCT_NAME = NSE;
@@ -7067,9 +7073,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = ( OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP";
"-DIS_MAIN_APP",
);
PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills";
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(APP_NAME)"; PRODUCT_NAME = "$(APP_NAME)";
@@ -7095,9 +7099,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = ( OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP";
"-DIS_MAIN_APP",
);
PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills";
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(APP_NAME)"; PRODUCT_NAME = "$(APP_NAME)";
@@ -7342,9 +7344,7 @@
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = ( OTHER_SWIFT_FLAGS = "-DIS_NSE";
"-DIS_NSE",
);
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse";
PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
PRODUCT_NAME = NSE; PRODUCT_NAME = NSE;
@@ -7561,7 +7561,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = { requirement = {
kind = exactVersion; kind = exactVersion;
version = 1.0.31; version = 1.0.32;
}; };
}; };
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
@@ -149,8 +149,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift", "location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : { "state" : {
"revision" : "8e2b4049fb492dcf5b0c796784b7aa7a3c099943", "revision" : "9a9d116e5f00b31ad4f727d0875fed13a230806b",
"version" : "1.0.31" "version" : "1.0.32"
} }
}, },
{ {
@@ -318,6 +318,7 @@
"screen_room_mentions_at_room_subtitle" = "Notify the whole room"; "screen_room_mentions_at_room_subtitle" = "Notify the whole room";
"screen_room_pinned_banner_indicator" = "%1$@ of %2$@"; "screen_room_pinned_banner_indicator" = "%1$@ of %2$@";
"screen_room_pinned_banner_indicator_description" = "%1$@ Pinned messages"; "screen_room_pinned_banner_indicator_description" = "%1$@ Pinned messages";
"screen_room_pinned_banner_loading_description" = "Loading message…";
"screen_room_pinned_banner_view_all_button_title" = "View All"; "screen_room_pinned_banner_view_all_button_title" = "View All";
"screen_account_provider_change" = "Change account provider"; "screen_account_provider_change" = "Change account provider";
"screen_account_provider_form_hint" = "Homeserver address"; "screen_account_provider_form_hint" = "Homeserver address";
@@ -851,6 +852,12 @@
"state_event_room_name_removed_by_you" = "You removed the room name"; "state_event_room_name_removed_by_you" = "You removed the room name";
"state_event_room_none" = "%1$@ made no changes"; "state_event_room_none" = "%1$@ made no changes";
"state_event_room_none_by_you" = "You made no changes"; "state_event_room_none_by_you" = "You made no changes";
"state_event_room_pinned_events_changed" = "%1$@ changed the pinned messages";
"state_event_room_pinned_events_changed_by_you" = "You changed the pinned messages";
"state_event_room_pinned_events_pinned" = "%1$@ pinned a message";
"state_event_room_pinned_events_pinned_by_you" = "You pinned a message";
"state_event_room_pinned_events_unpinned" = "%1$@ unpinned a message";
"state_event_room_pinned_events_unpinned_by_you" = "You unpinned a message";
"state_event_room_reject" = "%1$@ rejected the invitation"; "state_event_room_reject" = "%1$@ rejected the invitation";
"state_event_room_reject_by_you" = "You rejected the invitation"; "state_event_room_reject_by_you" = "You rejected the invitation";
"state_event_room_remove" = "%1$@ removed %2$@"; "state_event_room_remove" = "%1$@ removed %2$@";
+20
View File
@@ -1675,6 +1675,8 @@ internal enum L10n {
internal static func screenRoomPinnedBannerIndicatorDescription(_ p1: Any) -> String { internal static func screenRoomPinnedBannerIndicatorDescription(_ p1: Any) -> String {
return L10n.tr("Localizable", "screen_room_pinned_banner_indicator_description", String(describing: p1)) return L10n.tr("Localizable", "screen_room_pinned_banner_indicator_description", String(describing: p1))
} }
/// Loading message…
internal static var screenRoomPinnedBannerLoadingDescription: String { return L10n.tr("Localizable", "screen_room_pinned_banner_loading_description") }
/// View All /// View All
internal static var screenRoomPinnedBannerViewAllButtonTitle: String { return L10n.tr("Localizable", "screen_room_pinned_banner_view_all_button_title") } internal static var screenRoomPinnedBannerViewAllButtonTitle: String { return L10n.tr("Localizable", "screen_room_pinned_banner_view_all_button_title") }
/// Send again /// Send again
@@ -2111,6 +2113,24 @@ internal enum L10n {
} }
/// You made no changes /// You made no changes
internal static var stateEventRoomNoneByYou: String { return L10n.tr("Localizable", "state_event_room_none_by_you") } internal static var stateEventRoomNoneByYou: String { return L10n.tr("Localizable", "state_event_room_none_by_you") }
/// %1$@ changed the pinned messages
internal static func stateEventRoomPinnedEventsChanged(_ p1: Any) -> String {
return L10n.tr("Localizable", "state_event_room_pinned_events_changed", String(describing: p1))
}
/// You changed the pinned messages
internal static var stateEventRoomPinnedEventsChangedByYou: String { return L10n.tr("Localizable", "state_event_room_pinned_events_changed_by_you") }
/// %1$@ pinned a message
internal static func stateEventRoomPinnedEventsPinned(_ p1: Any) -> String {
return L10n.tr("Localizable", "state_event_room_pinned_events_pinned", String(describing: p1))
}
/// You pinned a message
internal static var stateEventRoomPinnedEventsPinnedByYou: String { return L10n.tr("Localizable", "state_event_room_pinned_events_pinned_by_you") }
/// %1$@ unpinned a message
internal static func stateEventRoomPinnedEventsUnpinned(_ p1: Any) -> String {
return L10n.tr("Localizable", "state_event_room_pinned_events_unpinned", String(describing: p1))
}
/// You unpinned a message
internal static var stateEventRoomPinnedEventsUnpinnedByYou: String { return L10n.tr("Localizable", "state_event_room_pinned_events_unpinned_by_you") }
/// %1$@ rejected the invitation /// %1$@ rejected the invitation
internal static func stateEventRoomReject(_ p1: Any) -> String { internal static func stateEventRoomReject(_ p1: Any) -> String {
return L10n.tr("Localizable", "state_event_room_reject", String(describing: p1)) return L10n.tr("Localizable", "state_event_room_reject", String(describing: p1))
@@ -0,0 +1,26 @@
//
// 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 Foundation
extension NetworkMonitorMock {
static var `default`: NetworkMonitorMock {
let mock = NetworkMonitorMock()
mock.underlyingReachabilityPublisher = .init(.init(.reachable))
return mock
}
}
@@ -67,6 +67,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
mediaPlayerProvider: parameters.mediaPlayerProvider, mediaPlayerProvider: parameters.mediaPlayerProvider,
voiceMessageMediaManager: parameters.voiceMessageMediaManager, voiceMessageMediaManager: parameters.voiceMessageMediaManager,
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: parameters.appMediator, appMediator: parameters.appMediator,
appSettings: parameters.appSettings, appSettings: parameters.appSettings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -177,10 +177,10 @@ struct RoomScreenViewState: BindableState {
// It's updated from the room info, so it's faster than using the timeline // It's updated from the room info, so it's faster than using the timeline
var pinnedEventIDs: Set<String> = [] var pinnedEventIDs: Set<String> = []
// This is used to control the banner // This is used to control the banner
var pinnedEventsState = PinnedEventsState() var pinnedEventsBannerState: PinnedEventsBannerState = .loading(numbersOfEvents: 0)
var shouldShowPinnedEventsBanner: Bool { var shouldShowPinnedEventsBanner: Bool {
isPinningEnabled && !pinnedEventsState.pinnedEventContents.isEmpty && lastScrollDirection != .top isPinningEnabled && !pinnedEventsBannerState.isEmpty && lastScrollDirection != .top
} }
var canJoinCall = false var canJoinCall = false
@@ -306,11 +306,12 @@ struct PinnedEventsState: Equatable {
var pinnedEventContents: OrderedDictionary<String, AttributedString> = [:] { var pinnedEventContents: OrderedDictionary<String, AttributedString> = [:] {
didSet { didSet {
if selectedPinEventID == nil, !pinnedEventContents.keys.isEmpty { if selectedPinEventID == nil, !pinnedEventContents.keys.isEmpty {
// The default selected event should always be the last one.
selectedPinEventID = pinnedEventContents.keys.last selectedPinEventID = pinnedEventContents.keys.last
} else if pinnedEventContents.isEmpty { } else if pinnedEventContents.isEmpty {
selectedPinEventID = nil selectedPinEventID = nil
} else if let selectedPinEventID, !pinnedEventContents.keys.set.contains(selectedPinEventID) { } else if let selectedPinEventID, !pinnedEventContents.keys.set.contains(selectedPinEventID) {
self.selectedPinEventID = pinnedEventContents.firstNonNil { $0.key } self.selectedPinEventID = pinnedEventContents.keys.last
} }
} }
} }
@@ -326,24 +327,15 @@ struct PinnedEventsState: Equatable {
} }
var selectedPinContent: AttributedString { var selectedPinContent: AttributedString {
guard let selectedPinEventID, var content = AttributedString(" ")
var content = pinnedEventContents[selectedPinEventID] else { if let selectedPinEventID,
return AttributedString() var pinnedEventContent = pinnedEventContents[selectedPinEventID] {
content = pinnedEventContent
} }
content.font = .compound.bodyMD content.font = .compound.bodyMD
return content return content
} }
var bannerIndicatorDescription: AttributedString {
let index = selectedPinIndex + 1
let boldPlaceholder = "{bold}"
var finalString = AttributedString(L10n.screenRoomPinnedBannerIndicatorDescription(boldPlaceholder))
var boldString = AttributedString(L10n.screenRoomPinnedBannerIndicator(index, pinnedEventContents.count))
boldString.bold()
finalString.replace(boldPlaceholder, with: boldString)
return finalString
}
mutating func nextPin() { mutating func nextPin() {
guard !pinnedEventContents.isEmpty else { guard !pinnedEventContents.isEmpty else {
return return
@@ -353,3 +345,94 @@ struct PinnedEventsState: Equatable {
selectedPinEventID = pinnedEventContents.keys[nextIndex] selectedPinEventID = pinnedEventContents.keys[nextIndex]
} }
} }
enum PinnedEventsBannerState: Equatable {
case loading(numbersOfEvents: Int)
case loaded(state: PinnedEventsState)
var isEmpty: Bool {
switch self {
case .loaded(let state):
return state.pinnedEventContents.isEmpty
case .loading(let numberOfEvents):
return numberOfEvents == 0
}
}
var isLoading: Bool {
switch self {
case .loading:
return true
default:
return false
}
}
var selectedPinEventID: String? {
switch self {
case .loaded(let state):
return state.selectedPinEventID
default:
return nil
}
}
var count: Int {
switch self {
case .loaded(let state):
return state.pinnedEventContents.count
case .loading(let numberOfEvents):
return numberOfEvents
}
}
var selectedPinIndex: Int {
switch self {
case .loaded(let state):
return state.selectedPinIndex
case .loading(let numbersOfEvents):
// We always want the index to be the last one when loading, since is the default one.
return numbersOfEvents - 1
}
}
var displayedMessage: AttributedString {
switch self {
case .loading:
return AttributedString(L10n.screenRoomPinnedBannerLoadingDescription)
case .loaded(let state):
return state.selectedPinContent
}
}
var bannerIndicatorDescription: AttributedString {
let index = selectedPinIndex + 1
let boldPlaceholder = "{bold}"
var finalString = AttributedString(L10n.screenRoomPinnedBannerIndicatorDescription(boldPlaceholder))
var boldString = AttributedString(L10n.screenRoomPinnedBannerIndicator(index, count))
boldString.bold()
finalString.replace(boldPlaceholder, with: boldString)
return finalString
}
mutating func nextPin() {
switch self {
case .loaded(var state):
state.nextPin()
self = .loaded(state: state)
default:
break
}
}
mutating func setPinnedEventContents(_ pinnedEventContents: OrderedDictionary<String, AttributedString>) {
switch self {
case .loading:
// The default selected event should always be the last one.
self = .loaded(state: .init(pinnedEventContents: pinnedEventContents, selectedPinEventID: pinnedEventContents.keys.last))
case .loaded(var state):
state.pinnedEventContents = pinnedEventContents
self = .loaded(state: state)
}
}
}
@@ -33,6 +33,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
private let timelineController: RoomTimelineControllerProtocol private let timelineController: RoomTimelineControllerProtocol
private let mediaPlayerProvider: MediaPlayerProviderProtocol private let mediaPlayerProvider: MediaPlayerProviderProtocol
private let userIndicatorController: UserIndicatorControllerProtocol private let userIndicatorController: UserIndicatorControllerProtocol
private let networkMonitor: NetworkMonitorProtocol
private let appMediator: AppMediatorProtocol private let appMediator: AppMediatorProtocol
private let appSettings: AppSettings private let appSettings: AppSettings
private let analyticsService: AnalyticsService private let analyticsService: AnalyticsService
@@ -49,6 +50,25 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
private var paginateBackwardsTask: Task<Void, Never>? private var paginateBackwardsTask: Task<Void, Never>?
private var paginateForwardsTask: Task<Void, Never>? private var paginateForwardsTask: Task<Void, Never>?
private var pinnedEventsTimelineProviderSetupTask: Task<Void, Never>?
private var pinnedEventsTimelineProvider: RoomTimelineProviderProtocol? {
didSet {
guard let pinnedEventsTimelineProvider else {
return
}
buildPinnedEventContent(timelineItems: pinnedEventsTimelineProvider.itemProxies)
pinnedEventsTimelineProvider.updatePublisher
// When pinning or unpinning an item, the timeline might return empty for a short while, so we need to debounce it to prevent weird UI behaviours like the banner disappearing
.debounce(for: .milliseconds(100), scheduler: DispatchQueue.main)
.sink { [weak self] updatedItems, _ in
guard let self else { return }
buildPinnedEventContent(timelineItems: updatedItems)
}
.store(in: &cancellables)
}
}
init(roomProxy: RoomProxyProtocol, init(roomProxy: RoomProxyProtocol,
focussedEventID: String? = nil, focussedEventID: String? = nil,
@@ -57,6 +77,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
mediaPlayerProvider: MediaPlayerProviderProtocol, mediaPlayerProvider: MediaPlayerProviderProtocol,
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol, voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
userIndicatorController: UserIndicatorControllerProtocol, userIndicatorController: UserIndicatorControllerProtocol,
networkMonitor: NetworkMonitorProtocol,
appMediator: AppMediatorProtocol, appMediator: AppMediatorProtocol,
appSettings: AppSettings, appSettings: AppSettings,
analyticsService: AnalyticsService) { analyticsService: AnalyticsService) {
@@ -67,6 +88,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
self.analyticsService = analyticsService self.analyticsService = analyticsService
self.userIndicatorController = userIndicatorController self.userIndicatorController = userIndicatorController
self.appMediator = appMediator self.appMediator = appMediator
self.networkMonitor = networkMonitor
pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID) pinnedEventStringBuilder = .pinnedEventStringBuilder(userID: roomProxy.ownUserID)
let voiceMessageRecorder = VoiceMessageRecorder(audioRecorder: AudioRecorder(), mediaPlayerProvider: mediaPlayerProvider) let voiceMessageRecorder = VoiceMessageRecorder(audioRecorder: AudioRecorder(), mediaPlayerProvider: mediaPlayerProvider)
@@ -127,22 +149,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
} }
} }
Task { setupPinnedEventsTimelineProviderIfNeeded()
guard let pinnedEventsTimelineProvider = await roomProxy.pinnedEventsTimeline?.timelineProvider else {
return
}
buildPinnedEventContent(timelineItems: pinnedEventsTimelineProvider.itemProxies)
pinnedEventsTimelineProvider.updatePublisher
// When pinning or unpinning an item, the timeline might return empty for a short while, so we need to debounce it to prevent weird UI behaviours like the banner disappearing
.debounce(for: .milliseconds(100), scheduler: DispatchQueue.main)
.sink { [weak self] updatedItems, _ in
guard let self else { return }
buildPinnedEventContent(timelineItems: updatedItems)
}
.store(in: &cancellables)
}
} }
// MARK: - Public // MARK: - Public
@@ -218,10 +225,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
case let .hasScrolled(direction): case let .hasScrolled(direction):
state.lastScrollDirection = direction state.lastScrollDirection = direction
case .tappedPinnedEventsBanner: case .tappedPinnedEventsBanner:
if let eventID = state.pinnedEventsState.selectedPinEventID { if let eventID = state.pinnedEventsBannerState.selectedPinEventID {
Task { await focusOnEvent(eventID: eventID) } Task { await focusOnEvent(eventID: eventID) }
} }
state.pinnedEventsState.nextPin() state.pinnedEventsBannerState.nextPin()
case .viewAllPins: case .viewAllPins:
// TODO: Implement // TODO: Implement
break break
@@ -444,27 +451,17 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
return return
} }
// If the subscription has sent a value before the Task has started it might be lost, so before entering the loop we always do an update. // If the subscription has sent a value before the Task has started it might be lost, so before entering the loop we always do an update.
await state.pinnedEventIDs = roomProxy.pinnedEventIDs await updatePinnedEventIDs()
for await _ in roomInfoSubscription.receive(on: DispatchQueue.main).values { for await _ in roomInfoSubscription.receive(on: DispatchQueue.main).values {
guard !Task.isCancelled else { guard !Task.isCancelled else {
return return
} }
await state.pinnedEventIDs = roomProxy.pinnedEventIDs await updatePinnedEventIDs()
} }
} }
.store(in: &cancellables) .store(in: &cancellables)
appSettings.$sharePresence setupAppSettingsSubscriptions()
.weakAssign(to: \.state.showReadReceipts, on: self)
.store(in: &cancellables)
appSettings.$viewSourceEnabled
.weakAssign(to: \.state.isViewSourceEnabled, on: self)
.store(in: &cancellables)
appSettings.$pinningEnabled
.weakAssign(to: \.state.isPinningEnabled, on: self)
.store(in: &cancellables)
roomProxy.membersPublisher roomProxy.membersPublisher
.receive(on: DispatchQueue.main) .receive(on: DispatchQueue.main)
@@ -511,6 +508,56 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
} }
} }
.store(in: &cancellables) .store(in: &cancellables)
networkMonitor.reachabilityPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] networkState in
if networkState == .reachable {
self?.setupPinnedEventsTimelineProviderIfNeeded()
}
}
.store(in: &cancellables)
}
private func setupAppSettingsSubscriptions() {
appSettings.$sharePresence
.weakAssign(to: \.state.showReadReceipts, on: self)
.store(in: &cancellables)
appSettings.$viewSourceEnabled
.weakAssign(to: \.state.isViewSourceEnabled, on: self)
.store(in: &cancellables)
appSettings.$pinningEnabled
.weakAssign(to: \.state.isPinningEnabled, on: self)
.store(in: &cancellables)
}
private func setupPinnedEventsTimelineProviderIfNeeded() {
guard pinnedEventsTimelineProvider == nil,
pinnedEventsTimelineProviderSetupTask == nil else {
return
}
pinnedEventsTimelineProviderSetupTask = Task { [weak self] in
guard let self else { return }
guard let pinnedEventsTimelineProvider = await roomProxy.pinnedEventsTimeline?.timelineProvider else {
pinnedEventsTimelineProviderSetupTask = nil
return
}
self.pinnedEventsTimelineProvider = pinnedEventsTimelineProvider
}
}
private func updatePinnedEventIDs() async {
let pinnedEventIDs = await roomProxy.pinnedEventIDs
// Only update the loading state of the banner
if state.pinnedEventsBannerState.isLoading {
state.pinnedEventsBannerState = .loading(numbersOfEvents: pinnedEventIDs.count)
}
state.pinnedEventIDs = pinnedEventIDs
} }
private func setupDirectRoomSubscriptionsIfNeeded() { private func setupDirectRoomSubscriptionsIfNeeded() {
@@ -676,7 +723,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
private func buildPinnedEventContent(timelineItems: [TimelineItemProxy]) { private func buildPinnedEventContent(timelineItems: [TimelineItemProxy]) {
var pinnedEventContents = OrderedDictionary<String, AttributedString>() var pinnedEventContents = OrderedDictionary<String, AttributedString>()
for item in timelineItems { for item in timelineItems.reversed() {
// Only remote events are pinned // Only remote events are pinned
if case let .event(event) = item, if case let .event(event) = item,
let eventID = event.id.eventID { let eventID = event.id.eventID {
@@ -685,7 +732,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
} }
} }
state.pinnedEventsState.pinnedEventContents = pinnedEventContents state.pinnedEventsBannerState.setPinnedEventContents(pinnedEventContents)
} }
private func buildTimelineViews(timelineItems: [RoomTimelineItemProtocol], isSwitchingTimelines: Bool = false) { private func buildTimelineViews(timelineItems: [RoomTimelineItemProtocol], isSwitchingTimelines: Bool = false) {
@@ -906,6 +953,7 @@ extension RoomScreenViewModel {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -18,7 +18,7 @@ import Compound
import SwiftUI import SwiftUI
struct PinnedItemsBannerView: View { struct PinnedItemsBannerView: View {
let pinnedEventsState: PinnedEventsState let state: PinnedEventsBannerState
let onMainButtonTap: () -> Void let onMainButtonTap: () -> Void
let onViewAllButtonTap: () -> Void let onViewAllButtonTap: () -> Void
@@ -38,7 +38,7 @@ struct PinnedItemsBannerView: View {
Button { onMainButtonTap() } label: { Button { onMainButtonTap() } label: {
HStack(spacing: 0) { HStack(spacing: 0) {
HStack(spacing: 10) { HStack(spacing: 10) {
PinnedItemsIndicatorView(pinIndex: pinnedEventsState.selectedPinIndex, pinsCount: pinnedEventsState.pinnedEventContents.count) PinnedItemsIndicatorView(pinIndex: state.selectedPinIndex, pinsCount: state.count)
.accessibilityHidden(true) .accessibilityHidden(true)
CompoundIcon(\.pinSolid, size: .small, relativeTo: .compound.bodyMD) CompoundIcon(\.pinSolid, size: .small, relativeTo: .compound.bodyMD)
.foregroundColor(Color.compound.iconSecondaryAlpha) .foregroundColor(Color.compound.iconSecondaryAlpha)
@@ -48,26 +48,34 @@ struct PinnedItemsBannerView: View {
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }
} }
.disabled(state.isLoading)
.accessibilityElement(children: .contain) .accessibilityElement(children: .contain)
} }
@ViewBuilder
private var viewAllButton: some View { private var viewAllButton: some View {
Button { onViewAllButtonTap() } label: { switch state {
Text(L10n.screenRoomPinnedBannerViewAllButtonTitle) case .loaded:
.font(.compound.bodyMDSemibold) Button { onViewAllButtonTap() } label: {
.foregroundStyle(Color.compound.textPrimary) Text(L10n.screenRoomPinnedBannerViewAllButtonTitle)
.font(.compound.bodyMDSemibold)
.foregroundStyle(Color.compound.textPrimary)
.padding(.horizontal, 16)
.padding(.vertical, 5)
}
case .loading:
ProgressView()
.padding(.horizontal, 16) .padding(.horizontal, 16)
.padding(.vertical, 5)
} }
} }
private var content: some View { private var content: some View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
Text(pinnedEventsState.bannerIndicatorDescription) Text(state.bannerIndicatorDescription)
.font(.compound.bodySM) .font(.compound.bodySM)
.foregroundColor(.compound.textActionAccent) .foregroundColor(.compound.textActionAccent)
.lineLimit(1) .lineLimit(1)
Text(pinnedEventsState.selectedPinContent) Text(state.displayedMessage)
.font(.compound.bodyMD) .font(.compound.bodyMD)
.foregroundColor(.compound.textPrimary) .foregroundColor(.compound.textPrimary)
.lineLimit(1) .lineLimit(1)
@@ -79,27 +87,30 @@ struct PinnedItemsBannerView_Previews: PreviewProvider, TestablePreview {
static var attributedContent: AttributedString { static var attributedContent: AttributedString {
var boldPart = AttributedString("Image:") var boldPart = AttributedString("Image:")
boldPart.bold() boldPart.bold()
var final = boldPart + " content.png" var finalString = boldPart + " content.png"
// This should be ignored when presented // This should be ignored when presented
final.font = .headline finalString.font = .headline
return final return finalString
} }
static var previews: some View { static var previews: some View {
VStack(spacing: 20) { VStack(spacing: 20) {
PinnedItemsBannerView(pinnedEventsState: .init(pinnedEventContents: ["1": "Content", PinnedItemsBannerView(state: .loaded(state: .init(pinnedEventContents: ["1": "Content",
"2": "2", "2": "2",
"3": "3"], "3": "3"],
selectedPinEventID: "1"), selectedPinEventID: "1")),
onMainButtonTap: { }, onMainButtonTap: { },
onViewAllButtonTap: { }) onViewAllButtonTap: { })
PinnedItemsBannerView(pinnedEventsState: .init(pinnedEventContents: ["1": "Very very very very long content here", PinnedItemsBannerView(state: .loaded(state: .init(pinnedEventContents: ["1": "Very very very very long content here",
"2": "2"], "2": "2"],
selectedPinEventID: "1"), selectedPinEventID: "1")),
onMainButtonTap: { }, onMainButtonTap: { },
onViewAllButtonTap: { }) onViewAllButtonTap: { })
PinnedItemsBannerView(pinnedEventsState: .init(pinnedEventContents: ["1": attributedContent], PinnedItemsBannerView(state: .loaded(state: .init(pinnedEventContents: ["1": attributedContent],
selectedPinEventID: "1"), selectedPinEventID: "1")),
onMainButtonTap: { },
onViewAllButtonTap: { })
PinnedItemsBannerView(state: .loading(numbersOfEvents: 5),
onMainButtonTap: { }, onMainButtonTap: { },
onViewAllButtonTap: { }) onViewAllButtonTap: { })
} }
@@ -58,6 +58,7 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: UserIndicatorControllerMock(), userIndicatorController: UserIndicatorControllerMock(),
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -110,7 +110,7 @@ struct RoomScreen: View {
} }
private var pinnedItemsBanner: some View { private var pinnedItemsBanner: some View {
PinnedItemsBannerView(pinnedEventsState: context.viewState.pinnedEventsState, PinnedItemsBannerView(state: context.viewState.pinnedEventsBannerState,
onMainButtonTap: { context.send(viewAction: .tappedPinnedEventsBanner) }, onMainButtonTap: { context.send(viewAction: .tappedPinnedEventsBanner) },
onViewAllButtonTap: { context.send(viewAction: .viewAllPins) }) onViewAllButtonTap: { context.send(viewAction: .viewAllPins) })
.transition(.move(edge: .top)) .transition(.move(edge: .top))
@@ -213,6 +213,7 @@ struct RoomScreen_Previews: PreviewProvider, TestablePreview {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -96,6 +96,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -101,6 +101,7 @@ struct HighlightedTimelineItemTimeline_Previews: PreviewProvider {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -86,6 +86,7 @@ struct TimelineView_Previews: PreviewProvider, TestablePreview {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -42,6 +42,11 @@ struct RoomEventStringBuilder {
case .redactedMessage: case .redactedMessage:
return prefix(L10n.commonMessageRemoved, with: displayName) return prefix(L10n.commonMessageRemoved, with: displayName)
case .sticker: case .sticker:
if messageEventStringBuilder.prefix == .messageType {
var string = AttributedString(L10n.commonSticker)
string.bold()
return string
}
return prefix(L10n.commonSticker, with: displayName) return prefix(L10n.commonSticker, with: displayName)
case .failedToParseMessageLike, .failedToParseState: case .failedToParseMessageLike, .failedToParseState:
return prefix(L10n.commonUnsupportedEvent, with: displayName) return prefix(L10n.commonUnsupportedEvent, with: displayName)
@@ -70,6 +75,14 @@ struct RoomEventStringBuilder {
memberIsYou: isOutgoing) memberIsYou: isOutgoing)
.map(AttributedString.init) .map(AttributedString.init)
case .poll(let question, _, _, _, _, _, _): case .poll(let question, _, _, _, _, _, _):
if messageEventStringBuilder.prefix == .messageType {
let questionPlaceholder = "{question}"
var finalString = AttributedString(L10n.commonPollSummary(questionPlaceholder))
finalString.bold()
let normalString = AttributedString(question)
finalString.replace(questionPlaceholder, with: normalString)
return finalString
}
return prefix(L10n.commonPollSummary(question), with: displayName) return prefix(L10n.commonPollSummary(question), with: displayName)
case .callInvite: case .callInvite:
return prefix(L10n.commonCallInvite, with: displayName) return prefix(L10n.commonCallInvite, with: displayName)
@@ -95,7 +108,7 @@ struct RoomEventStringBuilder {
RoomEventStringBuilder(stateEventStringBuilder: .init(userID: userID, RoomEventStringBuilder(stateEventStringBuilder: .init(userID: userID,
shouldDisambiguateDisplayNames: false), shouldDisambiguateDisplayNames: false),
messageEventStringBuilder: .init(attributedStringBuilder: AttributedStringBuilder(cacheKey: "pinnedEvents", mentionBuilder: PlainMentionBuilder()), messageEventStringBuilder: .init(attributedStringBuilder: AttributedStringBuilder(cacheKey: "pinnedEvents", mentionBuilder: PlainMentionBuilder()),
prefix: .mediaType), prefix: .messageType),
shouldDisambiguateDisplayNames: false, shouldDisambiguateDisplayNames: false,
shouldPrefixSenderName: false) shouldPrefixSenderName: false)
} }
@@ -20,7 +20,7 @@ import MatrixRustSDK
struct RoomMessageEventStringBuilder { struct RoomMessageEventStringBuilder {
enum Prefix { enum Prefix {
case senderName case senderName
case mediaType case messageType
case none case none
} }
@@ -41,19 +41,19 @@ struct RoomMessageEventStringBuilder {
case .audio(content: let content): case .audio(content: let content):
let isVoiceMessage = content.voice != nil let isVoiceMessage = content.voice != nil
var content = AttributedString(isVoiceMessage ? L10n.commonVoiceMessage : L10n.commonAudio) var content = AttributedString(isVoiceMessage ? L10n.commonVoiceMessage : L10n.commonAudio)
if prefix == .mediaType { if prefix == .messageType {
content.bold() content.bold()
} }
message = content message = content
case .image(let content): case .image(let content):
message = prefix == .mediaType ? prefix(AttributedString(content.body), with: L10n.commonImage) : AttributedString("\(L10n.commonImage) - \(content.body)") message = prefix == .messageType ? prefix(AttributedString(content.body), with: L10n.commonImage) : AttributedString("\(L10n.commonImage) - \(content.body)")
case .video(let content): case .video(let content):
message = prefix == .mediaType ? prefix(AttributedString(content.body), with: L10n.commonVideo) : AttributedString("\(L10n.commonVideo) - \(content.body)") message = prefix == .messageType ? prefix(AttributedString(content.body), with: L10n.commonVideo) : AttributedString("\(L10n.commonVideo) - \(content.body)")
case .file(let content): case .file(let content):
message = prefix == .mediaType ? prefix(AttributedString(content.body), with: L10n.commonFile) : AttributedString("\(L10n.commonFile) - \(content.body)") message = prefix == .messageType ? prefix(AttributedString(content.body), with: L10n.commonFile) : AttributedString("\(L10n.commonFile) - \(content.body)")
case .location: case .location:
var content = AttributedString(L10n.commonSharedLocation) var content = AttributedString(L10n.commonSharedLocation)
if prefix == .mediaType { if prefix == .messageType {
content.bold() content.bold()
} }
message = content message = content
@@ -47,6 +47,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate
AppSettings.resetAllSettings() AppSettings.resetAllSettings()
ServiceLocator.shared.register(appSettings: AppSettings()) ServiceLocator.shared.register(appSettings: AppSettings())
ServiceLocator.shared.register(bugReportService: BugReportServiceMock()) ServiceLocator.shared.register(bugReportService: BugReportServiceMock())
ServiceLocator.shared.register(networkMonitor: NetworkMonitorMock.default)
let analyticsClient = AnalyticsClientMock() let analyticsClient = AnalyticsClientMock()
analyticsClient.isRunning = false analyticsClient.isRunning = false
@@ -27,6 +27,7 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol {
AppSettings.resetAllSettings() AppSettings.resetAllSettings()
ServiceLocator.shared.register(appSettings: AppSettings()) ServiceLocator.shared.register(appSettings: AppSettings())
ServiceLocator.shared.register(bugReportService: BugReportServiceMock()) ServiceLocator.shared.register(bugReportService: BugReportServiceMock())
ServiceLocator.shared.register(networkMonitor: NetworkMonitorMock.default)
let analyticsClient = AnalyticsClientMock() let analyticsClient = AnalyticsClientMock()
analyticsClient.isRunning = false analyticsClient.isRunning = false
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:5eb75e371a78b17fad61215006b871310665bf8061772985d047facbccc5bae7 oid sha256:52a543349c38a46a7abf42d9f5b83aed47b40621e358fe63b98487acff03b461
size 129176 size 147075
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:745d8fdea278dc6ab55f39501384ecc5efc3899db233c52c797a8542f4885adc oid sha256:131dadbb128453abb744bd49c2cd592bbd9f0f5bdee5ba6ea71f541a10ee70ee
size 154132 size 182373
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:82dc33b9de9b497388b91304afe2623e4fa5c9d5aff246a87b68c4d948a63a37 oid sha256:ade81f08af5344aab81fdebbffe27a4b04976ce8e3cc8f397d5328c51998ad09
size 76715 size 91413
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:48df9215b99d69572bf3c4395e4b13d0b34012691b98bba75c73fc35c3b0b6fb oid sha256:919e3df86ce263d06f479c701b6981a66b0d6217e13cf3cff12445b9c6a24d77
size 85989 size 106938
+3
View File
@@ -32,6 +32,7 @@ class PillContextTests: XCTestCase {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -60,6 +61,7 @@ class PillContextTests: XCTestCase {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -81,6 +83,7 @@ class PillContextTests: XCTestCase {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController, userIndicatorController: ServiceLocator.shared.userIndicatorController,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -0,0 +1,133 @@
//
// 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 XCTest
@testable import ElementX
class PinnedEventsBannerStateTests: XCTestCase {
func testEmpty() {
var state = PinnedEventsBannerState.loading(numbersOfEvents: 0)
XCTAssertTrue(state.isEmpty)
state = .loaded(state: .init())
XCTAssertTrue(state.isEmpty)
}
func testLoading() {
let originalState = PinnedEventsBannerState.loading(numbersOfEvents: 5)
var state = originalState
// This should not affect the state when loading
state.nextPin()
XCTAssertEqual(state, originalState)
XCTAssertTrue(state.isLoading)
XCTAssertFalse(state.isEmpty)
XCTAssertNil(state.selectedPinEventID)
XCTAssertEqual(state.displayedMessage.string, L10n.screenRoomPinnedBannerLoadingDescription)
XCTAssertEqual(state.selectedPinIndex, 4)
XCTAssertEqual(state.count, 5)
XCTAssertEqual(state.bannerIndicatorDescription.string, L10n.screenRoomPinnedBannerIndicatorDescription(L10n.screenRoomPinnedBannerIndicator(5, 5)))
}
func testLoadingToLoaded() {
var state = PinnedEventsBannerState.loading(numbersOfEvents: 2)
XCTAssertTrue(state.isLoading)
state.setPinnedEventContents(["1": "test1", "2": "test2"])
XCTAssertEqual(state, .loaded(state: .init(pinnedEventContents: ["1": "test1", "2": "test2"], selectedPinEventID: "2")))
XCTAssertFalse(state.isLoading)
}
func testLoaded() {
let state = PinnedEventsBannerState.loaded(state: .init(pinnedEventContents: ["1": "test1", "2": "test2"], selectedPinEventID: "2"))
XCTAssertFalse(state.isLoading)
XCTAssertFalse(state.isEmpty)
XCTAssertEqual(state.selectedPinEventID, "2")
XCTAssertEqual(state.displayedMessage.string, "test2")
XCTAssertEqual(state.selectedPinIndex, 1)
XCTAssertEqual(state.count, 2)
XCTAssertEqual(state.bannerIndicatorDescription.string, L10n.screenRoomPinnedBannerIndicatorDescription(L10n.screenRoomPinnedBannerIndicator(2, 2)))
}
func testNextPin() {
var state = PinnedEventsBannerState.loaded(state: .init(pinnedEventContents: ["1": "test1", "2": "test2", "3": "test3"], selectedPinEventID: "3"))
XCTAssertEqual(state.selectedPinEventID, "3")
XCTAssertEqual(state.selectedPinIndex, 2)
XCTAssertEqual(state.displayedMessage.string, "test3")
state.nextPin()
XCTAssertEqual(state.selectedPinEventID, "1")
XCTAssertEqual(state.selectedPinIndex, 0)
XCTAssertEqual(state.displayedMessage.string, "test1")
state.nextPin()
XCTAssertEqual(state.selectedPinEventID, "2")
XCTAssertEqual(state.selectedPinIndex, 1)
XCTAssertEqual(state.displayedMessage.string, "test2")
}
func testSetContent() {
var state = PinnedEventsBannerState.loaded(state: .init(pinnedEventContents: ["1": "test1", "2": "test2", "3": "test3", "4": "test4"], selectedPinEventID: "2"))
XCTAssertEqual(state.selectedPinEventID, "2")
XCTAssertEqual(state.selectedPinIndex, 1)
XCTAssertEqual(state.displayedMessage.string, "test2")
XCTAssertEqual(state.count, 4)
XCTAssertFalse(state.isEmpty)
// let's remove the selected item
state.setPinnedEventContents(["1": "test1", "3": "test3", "4": "test4"])
// new selected item is the new latest
XCTAssertEqual(state.selectedPinEventID, "4")
XCTAssertEqual(state.selectedPinIndex, 2)
XCTAssertEqual(state.displayedMessage.string, "test4")
XCTAssertEqual(state.count, 3)
XCTAssertFalse(state.isEmpty)
// let's add a new item at the top
state.setPinnedEventContents(["0": "test0", "1": "test1", "3": "test3", "4": "test4"])
// selected item doesn't change
XCTAssertEqual(state.selectedPinEventID, "4")
// but the index is updated
XCTAssertEqual(state.selectedPinIndex, 3)
XCTAssertEqual(state.displayedMessage.string, "test4")
XCTAssertEqual(state.count, 4)
XCTAssertFalse(state.isEmpty)
// let's add a new item at the bottom
state.setPinnedEventContents(["0": "test0", "1": "test1", "3": "test3", "4": "test4", "5": "test5"])
// selected item doesn't change
XCTAssertEqual(state.selectedPinEventID, "4")
// and index stays the same
XCTAssertEqual(state.selectedPinIndex, 3)
XCTAssertEqual(state.displayedMessage.string, "test4")
XCTAssertEqual(state.count, 5)
XCTAssertFalse(state.isEmpty)
// set to tempty
state.setPinnedEventContents([:])
XCTAssertTrue(state.isEmpty)
XCTAssertNil(state.selectedPinEventID)
// set to one item
state.setPinnedEventContents(["6": "test6", "7": "test7"])
XCTAssertEqual(state.selectedPinEventID, "7")
XCTAssertEqual(state.selectedPinIndex, 1)
XCTAssertEqual(state.displayedMessage.string, "test7")
XCTAssertEqual(state.count, 2)
XCTAssertFalse(state.isEmpty)
}
}
@@ -351,6 +351,7 @@ class RoomScreenViewModelTests: XCTestCase {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock, userIndicatorController: userIndicatorControllerMock,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -375,6 +376,7 @@ class RoomScreenViewModelTests: XCTestCase {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock, userIndicatorController: userIndicatorControllerMock,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
@@ -399,6 +401,7 @@ class RoomScreenViewModelTests: XCTestCase {
mediaPlayerProvider: MediaPlayerProviderMock(), mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(), voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock, userIndicatorController: userIndicatorControllerMock,
networkMonitor: ServiceLocator.shared.networkMonitor,
appMediator: AppMediatorMock.default, appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics) analyticsService: ServiceLocator.shared.analytics)
+1 -1
View File
@@ -60,7 +60,7 @@ packages:
# Element/Matrix dependencies # Element/Matrix dependencies
MatrixRustSDK: MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 1.0.31 exactVersion: 1.0.32
# path: ../matrix-rust-sdk # path: ../matrix-rust-sdk
Compound: Compound:
url: https://github.com/element-hq/compound-ios url: https://github.com/element-hq/compound-ios