Fixes #2808 - Switch the message sending failure options from a dialog to an alert

* Fixes #2808 - Switch the message sending failure options from a dialog to an alert
- this prevents it from showing up as a popup on the room list on an iPad
- it used to be set on the timeline and not on the timeline item because of our use of a UITableView
* Cleanup room screen action names
This commit is contained in:
Stefan Ceriu
2024-05-09 14:35:47 +03:00
committed by GitHub
parent d97f912df7
commit 905b21e0a8
16 changed files with 180 additions and 245 deletions
+42 -16
View File
@@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 56; objectVersion = 54;
objects = { objects = {
/* Begin PBXAggregateTarget section */ /* Begin PBXAggregateTarget section */
@@ -1140,12 +1140,12 @@
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; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = "<group>"; }; 0392E3FDE372C9B56FEEED8B /* test_voice_message.m4a */ = {isa = PBXFileReference; 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>"; };
048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; 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>"; };
@@ -1177,6 +1177,7 @@
0BD116096CAA9139B95EEA9C /* UserProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenViewModel.swift; sourceTree = "<group>"; }; 0BD116096CAA9139B95EEA9C /* UserProfileScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileScreenViewModel.swift; sourceTree = "<group>"; };
0C34667458773B02AB5FB0B2 /* LegalInformationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenViewModel.swift; sourceTree = "<group>"; }; 0C34667458773B02AB5FB0B2 /* LegalInformationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenViewModel.swift; sourceTree = "<group>"; };
0C62E07C1164F5120727A2A8 /* AppLockSetupBiometricsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenCoordinator.swift; sourceTree = "<group>"; }; 0C62E07C1164F5120727A2A8 /* AppLockSetupBiometricsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenCoordinator.swift; sourceTree = "<group>"; };
0CB569EAA5017B5B23970655 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = "<group>"; };
0CCC6C31102E1D8B9106DEDE /* AppLockSetupBiometricsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 0CCC6C31102E1D8B9106DEDE /* AppLockSetupBiometricsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
0D0B159AFFBBD8ECFD0E37FA /* LoginScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenModels.swift; sourceTree = "<group>"; }; 0D0B159AFFBBD8ECFD0E37FA /* LoginScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenModels.swift; sourceTree = "<group>"; };
0D879FC4E881E748BB9B34DC /* RoomChangePermissionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenCoordinator.swift; sourceTree = "<group>"; }; 0D879FC4E881E748BB9B34DC /* RoomChangePermissionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenCoordinator.swift; sourceTree = "<group>"; };
@@ -1203,7 +1204,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; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; }; 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; 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>"; };
@@ -1292,7 +1293,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; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = "<group>"; }; 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; 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>"; };
@@ -1304,6 +1305,7 @@
27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenModels.swift; sourceTree = "<group>"; }; 27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenModels.swift; sourceTree = "<group>"; };
28146817C61423CACCF942F5 /* CallScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenModels.swift; sourceTree = "<group>"; }; 28146817C61423CACCF942F5 /* CallScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenModels.swift; sourceTree = "<group>"; };
283974987DA7EC61D2AB57D9 /* VoiceMessageCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageCacheTests.swift; sourceTree = "<group>"; }; 283974987DA7EC61D2AB57D9 /* VoiceMessageCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageCacheTests.swift; sourceTree = "<group>"; };
284FEEB0789B8894E52A7F34 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
287FC98AF2664EAD79C0D902 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; }; 287FC98AF2664EAD79C0D902 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItemContent.swift; sourceTree = "<group>"; }; 28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItemContent.swift; sourceTree = "<group>"; };
295E28C3B9EAADF519BF2F44 /* AuthenticationFlowCoordinatorUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationFlowCoordinatorUITests.swift; sourceTree = "<group>"; }; 295E28C3B9EAADF519BF2F44 /* AuthenticationFlowCoordinatorUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationFlowCoordinatorUITests.swift; sourceTree = "<group>"; };
@@ -1349,7 +1351,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; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; 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>"; };
@@ -1364,6 +1366,7 @@
398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadableFrameModifier.swift; sourceTree = "<group>"; }; 398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadableFrameModifier.swift; sourceTree = "<group>"; };
39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerMock.swift; sourceTree = "<group>"; }; 39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerMock.swift; sourceTree = "<group>"; };
3A12D3D8138F1B71AFA7C858 /* CompletionSuggestionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionService.swift; sourceTree = "<group>"; }; 3A12D3D8138F1B71AFA7C858 /* CompletionSuggestionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionService.swift; sourceTree = "<group>"; };
3AD253E7EFF88F308D644272 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/SAS.strings"; sourceTree = "<group>"; };
3B5E97E9615A158C76B2AB77 /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = "<group>"; }; 3B5E97E9615A158C76B2AB77 /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = "<group>"; };
3BAC027034248429A438886B /* AppMediatorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediatorMock.swift; sourceTree = "<group>"; }; 3BAC027034248429A438886B /* AppMediatorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediatorMock.swift; sourceTree = "<group>"; };
3BC1B7CB061C9865B2B91B56 /* QRCodeLoginScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenViewModel.swift; sourceTree = "<group>"; }; 3BC1B7CB061C9865B2B91B56 /* QRCodeLoginScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreenViewModel.swift; sourceTree = "<group>"; };
@@ -1442,7 +1445,7 @@
4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; }; 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = "<group>"; };
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; }; 4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; }; 4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ElementX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = ElementX.app; sourceTree = BUILT_PRODUCTS_DIR; };
4CDDDDD9FE1A699D23A5E096 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = "<group>"; }; 4CDDDDD9FE1A699D23A5E096 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = "<group>"; };
4D3A7375AB22721C436EB056 /* ComposerToolbarModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarModels.swift; sourceTree = "<group>"; }; 4D3A7375AB22721C436EB056 /* ComposerToolbarModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarModels.swift; sourceTree = "<group>"; };
4E2245243369B99216C7D84E /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; }; 4E2245243369B99216C7D84E /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
@@ -1630,6 +1633,7 @@
80A07343F18BB8EAC17B07B7 /* QRCodeLoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginController.swift; sourceTree = "<group>"; }; 80A07343F18BB8EAC17B07B7 /* QRCodeLoginController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginController.swift; sourceTree = "<group>"; };
80C4927D09099497233E9980 /* WaitlistScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreen.swift; sourceTree = "<group>"; }; 80C4927D09099497233E9980 /* WaitlistScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreen.swift; sourceTree = "<group>"; };
80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageEventStringBuilder.swift; sourceTree = "<group>"; }; 80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageEventStringBuilder.swift; sourceTree = "<group>"; };
8166F121C79C7B62BF01D508 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = pt; path = pt.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
818695BED971753243FEF897 /* StickerRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerRoomTimelineItem.swift; sourceTree = "<group>"; }; 818695BED971753243FEF897 /* StickerRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerRoomTimelineItem.swift; sourceTree = "<group>"; };
81A9B5225D0881CEFA2CF7C9 /* RoomNotificationSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModel.swift; sourceTree = "<group>"; }; 81A9B5225D0881CEFA2CF7C9 /* RoomNotificationSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModel.swift; sourceTree = "<group>"; };
81B17B1F29448D1B9049B11C /* ReportContentScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenViewModel.swift; sourceTree = "<group>"; }; 81B17B1F29448D1B9049B11C /* ReportContentScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenViewModel.swift; sourceTree = "<group>"; };
@@ -1682,7 +1686,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; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; }; 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.swift; sourceTree = "<group>"; }; 8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.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>"; };
8F61A0DD8243B395499C99A2 /* InvitesScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenUITests.swift; sourceTree = "<group>"; }; 8F61A0DD8243B395499C99A2 /* InvitesScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenUITests.swift; sourceTree = "<group>"; };
@@ -1778,6 +1782,7 @@
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>"; };
A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenCoordinator.swift; sourceTree = "<group>"; }; A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenCoordinator.swift; sourceTree = "<group>"; };
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; }; A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
A8DF55467ED4CE76B7AE9A33 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/InfoPlist.strings; sourceTree = "<group>"; };
A9B069D7772DDF6513E0F1B8 /* AuthenticationFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationFlowCoordinator.swift; sourceTree = "<group>"; }; A9B069D7772DDF6513E0F1B8 /* AuthenticationFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationFlowCoordinator.swift; sourceTree = "<group>"; };
A9FAFE1C2149E6AC8156ED2B /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; }; A9FAFE1C2149E6AC8156ED2B /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; };
AA19C32BD97F45847724E09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Untranslated.strings; sourceTree = "<group>"; }; AA19C32BD97F45847724E09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Untranslated.strings; sourceTree = "<group>"; };
@@ -1785,6 +1790,7 @@
AACE9B8E1A4AE79A7E2914F6 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; AACE9B8E1A4AE79A7E2914F6 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserProfile+Mock.swift"; sourceTree = "<group>"; }; AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserProfile+Mock.swift"; sourceTree = "<group>"; };
AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = "<group>"; }; AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = "<group>"; };
AB26D5444A4A7E095222DE8B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; }; ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModelTests.swift; sourceTree = "<group>"; }; AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModelTests.swift; sourceTree = "<group>"; };
AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageCache.swift; sourceTree = "<group>"; }; AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageCache.swift; sourceTree = "<group>"; };
@@ -1838,7 +1844,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; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; }; B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; 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>"; };
@@ -1874,6 +1880,7 @@
BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenViewModel.swift; sourceTree = "<group>"; }; BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenViewModel.swift; sourceTree = "<group>"; };
BEA38B9851CFCC4D67F5587D /* EmojiPickerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenCoordinator.swift; sourceTree = "<group>"; }; BEA38B9851CFCC4D67F5587D /* EmojiPickerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenCoordinator.swift; sourceTree = "<group>"; };
BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStoreProtocol.swift; sourceTree = "<group>"; }; BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStoreProtocol.swift; sourceTree = "<group>"; };
BEE365C5A4E90ACBE398EFFE /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/SAS.strings; sourceTree = "<group>"; };
BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderScreenCoordinator.swift; sourceTree = "<group>"; }; BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderScreenCoordinator.swift; sourceTree = "<group>"; };
BFA9EA59D5C0DA1BFC7B3621 /* QRCodeLoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreen.swift; sourceTree = "<group>"; }; BFA9EA59D5C0DA1BFC7B3621 /* QRCodeLoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginScreen.swift; sourceTree = "<group>"; };
BFDCAC6CAAD65A2C24EA9C4B /* Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; }; BFDCAC6CAAD65A2C24EA9C4B /* Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
@@ -1950,7 +1957,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; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; }; CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = "<group>"; }; CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; 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>"; };
@@ -2071,7 +2078,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; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; }; ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; 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>"; };
@@ -2094,7 +2101,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; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = "<group>"; }; F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; 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>"; };
@@ -2138,6 +2145,7 @@
FDF73F49E6B6683F7E2D26F0 /* SecureBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenCoordinator.swift; sourceTree = "<group>"; }; FDF73F49E6B6683F7E2D26F0 /* SecureBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenCoordinator.swift; sourceTree = "<group>"; };
FE1E6FAA3719E9B7A2D5510B /* FormattingToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattingToolbar.swift; sourceTree = "<group>"; }; FE1E6FAA3719E9B7A2D5510B /* FormattingToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattingToolbar.swift; sourceTree = "<group>"; };
FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerProtocol.swift; sourceTree = "<group>"; }; FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerProtocol.swift; sourceTree = "<group>"; };
FF720BA68256297680980481 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
FFECCE59967018204876D0A5 /* LocationMarkerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationMarkerView.swift; sourceTree = "<group>"; }; FFECCE59967018204876D0A5 /* LocationMarkerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationMarkerView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -5415,11 +5423,13 @@
hu, hu,
id, id,
it, it,
pt,
ro, ro,
ru, ru,
sk, sk,
sv, sv,
uk, uk,
"zh-Hans",
"zh-Hant-TW", "zh-Hant-TW",
); );
mainGroup = 405B00F139AEE3994601B36A; mainGroup = 405B00F139AEE3994601B36A;
@@ -6689,10 +6699,12 @@
D196116D2DD3F2757D45FCB7 /* hu */, D196116D2DD3F2757D45FCB7 /* hu */,
330AF4D121C3396F7A14B21D /* id */, 330AF4D121C3396F7A14B21D /* id */,
61B33F23681660E940BA57F4 /* it */, 61B33F23681660E940BA57F4 /* it */,
BEE365C5A4E90ACBE398EFFE /* pt */,
105429F29096729EDD3152CF /* ru */, 105429F29096729EDD3152CF /* ru */,
A02D1A490944BF01A37586E1 /* sk */, A02D1A490944BF01A37586E1 /* sk */,
7509AB72755DCC4B4E721B36 /* sv */, 7509AB72755DCC4B4E721B36 /* sv */,
AFEF489B8E2450E2BA1A314E /* uk */, AFEF489B8E2450E2BA1A314E /* uk */,
3AD253E7EFF88F308D644272 /* zh-Hans */,
); );
name = SAS.strings; name = SAS.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -6710,11 +6722,13 @@
C95ADE8D9527523572532219 /* hu */, C95ADE8D9527523572532219 /* hu */,
475D47D0BFE961B02BAC5D49 /* id */, 475D47D0BFE961B02BAC5D49 /* id */,
6FC5015B9634698BDB8701AF /* it */, 6FC5015B9634698BDB8701AF /* it */,
8166F121C79C7B62BF01D508 /* pt */,
E9D059BFE329BE09B6D96A9F /* ro */, E9D059BFE329BE09B6D96A9F /* ro */,
E5F2B6443D1ED8602F328539 /* ru */, E5F2B6443D1ED8602F328539 /* ru */,
667DD3A9D932D7D9EB380CAA /* sk */, 667DD3A9D932D7D9EB380CAA /* sk */,
0EE9EAF0309A2A1D67D8FAF5 /* sv */, 0EE9EAF0309A2A1D67D8FAF5 /* sv */,
5F12E996BFBEB43815189ABF /* uk */, 5F12E996BFBEB43815189ABF /* uk */,
AB26D5444A4A7E095222DE8B /* zh-Hans */,
49E6066092ED45E36BB306F7 /* zh-Hant-TW */, 49E6066092ED45E36BB306F7 /* zh-Hant-TW */,
); );
name = Localizable.stringsdict; name = Localizable.stringsdict;
@@ -6733,11 +6747,13 @@
624244C398804ADC885239AA /* hu */, 624244C398804ADC885239AA /* hu */,
EF98A02DED04075F7CF0C721 /* id */, EF98A02DED04075F7CF0C721 /* id */,
7B04BD3874D736127A8156B8 /* it */, 7B04BD3874D736127A8156B8 /* it */,
0CB569EAA5017B5B23970655 /* pt */,
33E49C5C6F802B4D94CA78D1 /* ro */, 33E49C5C6F802B4D94CA78D1 /* ro */,
E8294DB9E95C0C0630418466 /* ru */, E8294DB9E95C0C0630418466 /* ru */,
AD378D580A41E42560C60E9C /* sk */, AD378D580A41E42560C60E9C /* sk */,
ACA11F7F50A4A3887A18CA5A /* sv */, ACA11F7F50A4A3887A18CA5A /* sv */,
ADCB8A232D3A8FB3E16A7303 /* uk */, ADCB8A232D3A8FB3E16A7303 /* uk */,
284FEEB0789B8894E52A7F34 /* zh-Hans */,
91CF6F7D08228D16BA69B63B /* zh-Hant-TW */, 91CF6F7D08228D16BA69B63B /* zh-Hant-TW */,
); );
name = Localizable.strings; name = Localizable.strings;
@@ -6756,11 +6772,13 @@
1D652E78832289CD9EB64488 /* hu */, 1D652E78832289CD9EB64488 /* hu */,
7199693797B66245EF97BCF5 /* id */, 7199693797B66245EF97BCF5 /* id */,
44C314C00533E2C297796B60 /* it */, 44C314C00533E2C297796B60 /* it */,
A8DF55467ED4CE76B7AE9A33 /* pt */,
86C8CE2630F54D5FE1591786 /* ro */, 86C8CE2630F54D5FE1591786 /* ro */,
9B7D8D3638864B7482E148CC /* ru */, 9B7D8D3638864B7482E148CC /* ru */,
7D39AF1F659923D77778511E /* sk */, 7D39AF1F659923D77778511E /* sk */,
969694F67E844FCA51F7E051 /* sv */, 969694F67E844FCA51F7E051 /* sv */,
D66B5D86A9AB95E0E01BED82 /* uk */, D66B5D86A9AB95E0E01BED82 /* uk */,
FF720BA68256297680980481 /* zh-Hans */,
); );
name = InfoPlist.strings; name = InfoPlist.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -6797,7 +6815,9 @@
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = "-DIS_NSE"; OTHER_SWIFT_FLAGS = (
"-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;
@@ -6846,7 +6866,9 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; OTHER_SWIFT_FLAGS = (
"-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)";
@@ -6872,7 +6894,9 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; OTHER_SWIFT_FLAGS = (
"-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)";
@@ -7117,7 +7141,9 @@
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = "$(MARKETING_VERSION)"; MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = "-DIS_NSE"; OTHER_SWIFT_FLAGS = (
"-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;
@@ -19,16 +19,19 @@ import UIKit
enum RoomScreenInteractionHandlerAction { enum RoomScreenInteractionHandlerAction {
case composer(action: RoomScreenComposerAction) case composer(action: RoomScreenComposerAction)
case displayError(RoomScreenErrorType)
case displayEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>) case displayEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case displayReportContent(itemID: TimelineItemIdentifier, senderID: String) case displayReportContent(itemID: TimelineItemIdentifier, senderID: String)
case displayMessageForwarding(itemID: TimelineItemIdentifier) case displayMessageForwarding(itemID: TimelineItemIdentifier)
case displayMediaUploadPreviewScreen(url: URL) case displayMediaUploadPreviewScreen(url: URL)
case displayPollForm(mode: PollFormMode) case displayPollForm(mode: PollFormMode)
case displayRoomMemberDetails(userID: String) case displayRoomMemberDetails(userID: String)
case showActionMenu(TimelineItemActionMenuInfo) case showActionMenu(TimelineItemActionMenuInfo)
case showDebugInfo(TimelineItemDebugInfo) case showDebugInfo(TimelineItemDebugInfo)
case showConfirmationAlert(AlertInfo<UUID>)
case displayAudioRecorderPermissionError
case displayErrorToast(String)
} }
@MainActor @MainActor
@@ -85,7 +88,7 @@ class RoomScreenInteractionHandler {
// MARK: Timeline Item Action Menu // MARK: Timeline Item Action Menu
func showTimelineItemActionMenu(for itemID: TimelineItemIdentifier) { func displayTimelineItemActionMenu(for itemID: TimelineItemIdentifier) {
Task { Task {
if case let .success(value) = await roomProxy.canUserRedactOther(userID: roomProxy.ownUserID) { if case let .success(value) = await roomProxy.canUserRedactOther(userID: roomProxy.ownUserID) {
canCurrentUserRedactOthers = value canCurrentUserRedactOthers = value
@@ -186,7 +189,7 @@ class RoomScreenInteractionHandler {
return .init(actions: actions, debugActions: debugActions) return .init(actions: actions, debugActions: debugActions)
} }
func processTimelineItemMenuAction(_ action: TimelineItemMenuAction, itemID: TimelineItemIdentifier) { func handleTimelineItemMenuAction(_ action: TimelineItemMenuAction, itemID: TimelineItemIdentifier) {
guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID),
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
return return
@@ -214,13 +217,13 @@ class RoomScreenInteractionHandler {
} }
case .copyPermalink: case .copyPermalink:
guard let eventID = eventTimelineItem.id.eventID else { guard let eventID = eventTimelineItem.id.eventID else {
actionsSubject.send(.displayError(.alert(L10n.errorFailedCreatingThePermalink))) actionsSubject.send(.displayErrorToast(L10n.errorFailedCreatingThePermalink))
return return
} }
Task { Task {
guard case let .success(permalinkURL) = await roomProxy.matrixToEventPermalink(eventID) else { guard case let .success(permalinkURL) = await roomProxy.matrixToEventPermalink(eventID) else {
actionsSubject.send(.displayError(.alert(L10n.errorFailedCreatingThePermalink))) actionsSubject.send(.displayErrorToast(L10n.errorFailedCreatingThePermalink))
return return
} }
@@ -256,7 +259,7 @@ class RoomScreenInteractionHandler {
case .report: case .report:
actionsSubject.send(.displayReportContent(itemID: itemID, senderID: eventTimelineItem.sender.id)) actionsSubject.send(.displayReportContent(itemID: itemID, senderID: eventTimelineItem.sender.id))
case .react: case .react:
showEmojiPicker(for: itemID) displayEmojiPicker(for: itemID)
case .toggleReaction(let key): case .toggleReaction(let key):
guard let eventID = itemID.eventID else { return } guard let eventID = itemID.eventID else { return }
Task { await roomProxy.timeline.toggleReaction(key, to: eventID) } Task { await roomProxy.timeline.toggleReaction(key, to: eventID) }
@@ -294,7 +297,7 @@ class RoomScreenInteractionHandler {
case .success: case .success:
break break
case .failure: case .failure:
actionsSubject.send(.displayError(.toast(L10n.errorUnknown))) actionsSubject.send(.displayErrorToast(L10n.errorUnknown))
} }
} }
} }
@@ -307,7 +310,7 @@ class RoomScreenInteractionHandler {
case .success: case .success:
break break
case .failure: case .failure:
actionsSubject.send(.displayError(.toast(L10n.errorUnknown))) actionsSubject.send(.displayErrorToast(L10n.errorUnknown))
} }
} }
} }
@@ -318,7 +321,7 @@ class RoomScreenInteractionHandler {
guard let contentType = provider.preferredContentType, guard let contentType = provider.preferredContentType,
let preferredExtension = contentType.preferredFilenameExtension else { let preferredExtension = contentType.preferredFilenameExtension else {
MXLog.error("Invalid NSItemProvider: \(provider)") MXLog.error("Invalid NSItemProvider: \(provider)")
actionsSubject.send(.displayError(.toast(L10n.screenRoomErrorFailedProcessingMedia))) actionsSubject.send(.displayErrorToast(L10n.screenRoomErrorFailedProcessingMedia))
return return
} }
@@ -334,13 +337,13 @@ class RoomScreenInteractionHandler {
} }
if let error { if let error {
self.actionsSubject.send(.displayError(.toast(L10n.screenRoomErrorFailedProcessingMedia))) self.actionsSubject.send(.displayErrorToast(L10n.screenRoomErrorFailedProcessingMedia))
MXLog.error("Failed processing NSItemProvider: \(providerDescription) with error: \(error)") MXLog.error("Failed processing NSItemProvider: \(providerDescription) with error: \(error)")
return return
} }
guard let data else { guard let data else {
self.actionsSubject.send(.displayError(.toast(L10n.screenRoomErrorFailedProcessingMedia))) self.actionsSubject.send(.displayErrorToast(L10n.screenRoomErrorFailedProcessingMedia))
MXLog.error("Invalid NSItemProvider data: \(providerDescription)") MXLog.error("Invalid NSItemProvider data: \(providerDescription)")
return return
} }
@@ -359,7 +362,7 @@ class RoomScreenInteractionHandler {
self.actionsSubject.send(.displayMediaUploadPreviewScreen(url: url)) self.actionsSubject.send(.displayMediaUploadPreviewScreen(url: url))
} catch { } catch {
self.actionsSubject.send(.displayError(.toast(L10n.screenRoomErrorFailedProcessingMedia))) self.actionsSubject.send(.displayErrorToast(L10n.screenRoomErrorFailedProcessingMedia))
MXLog.error("Failed storing NSItemProvider data \(providerDescription) with error: \(error)") MXLog.error("Failed storing NSItemProvider data \(providerDescription) with error: \(error)")
} }
} }
@@ -381,11 +384,7 @@ class RoomScreenInteractionHandler {
switch error { switch error {
case .audioRecorderError(.recordPermissionNotGranted): case .audioRecorderError(.recordPermissionNotGranted):
MXLog.info("permission to record audio has not been granted.") MXLog.info("permission to record audio has not been granted.")
actionsSubject.send(.showConfirmationAlert(.init(id: .init(), actionsSubject.send(.displayAudioRecorderPermissionError)
title: L10n.dialogPermissionMicrophoneTitleIos(InfoPlistReader.main.bundleDisplayName),
message: L10n.dialogPermissionMicrophoneDescriptionIos,
primaryButton: .init(title: L10n.commonSettings, action: { [weak self] in self?.openSystemSettings() }),
secondaryButton: .init(title: L10n.actionNotNow, role: .cancel, action: nil))))
default: default:
MXLog.error("failed to start voice message recording. \(error)") MXLog.error("failed to start voice message recording. \(error)")
actionsSubject.send(.composer(action: .setMode(mode: .default))) actionsSubject.send(.composer(action: .setMode(mode: .default)))
@@ -427,7 +426,7 @@ class RoomScreenInteractionHandler {
func sendCurrentVoiceMessage() async { func sendCurrentVoiceMessage() async {
guard let audioPlayerState = voiceMessageRecorder.previewAudioPlayerState, let recordingURL = voiceMessageRecorder.recordingURL else { guard let audioPlayerState = voiceMessageRecorder.previewAudioPlayerState, let recordingURL = voiceMessageRecorder.recordingURL else {
actionsSubject.send(.displayError(.alert(L10n.errorFailedUploadingVoiceMessage))) actionsSubject.send(.displayErrorToast(L10n.errorFailedUploadingVoiceMessage))
return return
} }
@@ -445,7 +444,7 @@ class RoomScreenInteractionHandler {
case .failure(let error): case .failure(let error):
MXLog.error("failed to send the voice message. \(error)") MXLog.error("failed to send the voice message. \(error)")
actionsSubject.send(.composer(action: .setMode(mode: .previewVoiceMessage(state: audioPlayerState, waveform: .url(recordingURL), isUploading: false)))) actionsSubject.send(.composer(action: .setMode(mode: .previewVoiceMessage(state: audioPlayerState, waveform: .url(recordingURL), isUploading: false))))
actionsSubject.send(.displayError(.alert(L10n.errorFailedUploadingVoiceMessage))) actionsSubject.send(.displayErrorToast(L10n.errorFailedUploadingVoiceMessage))
} }
} }
@@ -578,7 +577,7 @@ class RoomScreenInteractionHandler {
// MARK: Other // MARK: Other
func showEmojiPicker(for itemID: TimelineItemIdentifier) { func displayEmojiPicker(for itemID: TimelineItemIdentifier) {
guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID),
timelineItem.isReactable, timelineItem.isReactable,
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
@@ -588,7 +587,7 @@ class RoomScreenInteractionHandler {
actionsSubject.send(.displayEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis)) actionsSubject.send(.displayEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis))
} }
func handleTappedUser(userID: String) async { func displayRoomMemberDetails(userID: String) async {
actionsSubject.send(.displayRoomMemberDetails(userID: userID)) actionsSubject.send(.displayRoomMemberDetails(userID: userID))
} }
@@ -623,10 +622,6 @@ class RoomScreenInteractionHandler {
} }
} }
private func openSystemSettings() {
appMediator.openAppSettings()
}
private func displayMediaActionIfPossible(timelineItem: RoomTimelineItemProtocol) async -> RoomTimelineControllerAction { private func displayMediaActionIfPossible(timelineItem: RoomTimelineItemProtocol) async -> RoomTimelineControllerAction {
var source: MediaSourceProxy? var source: MediaSourceProxy?
var body: String var body: String
@@ -68,14 +68,12 @@ enum RoomScreenViewPollAction {
case edit(pollStartID: String, poll: Poll) case edit(pollStartID: String, poll: Poll)
} }
enum RoomScreenViewAudioAction { enum RoomScreenAudioPlayerAction {
case playPause(itemID: TimelineItemIdentifier) case playPause(itemID: TimelineItemIdentifier)
case seek(itemID: TimelineItemIdentifier, progress: Double) case seek(itemID: TimelineItemIdentifier, progress: Double)
} }
enum RoomScreenViewAction { enum RoomScreenViewAction {
case displayRoomDetails
case itemAppeared(itemID: TimelineItemIdentifier) case itemAppeared(itemID: TimelineItemIdentifier)
case itemDisappeared(itemID: TimelineItemIdentifier) case itemDisappeared(itemID: TimelineItemIdentifier)
@@ -86,27 +84,20 @@ enum RoomScreenViewAction {
case paginateForwards case paginateForwards
case scrollToBottom case scrollToBottom
case timelineItemMenu(itemID: TimelineItemIdentifier) case displayTimelineItemMenu(itemID: TimelineItemIdentifier)
case timelineItemMenuAction(itemID: TimelineItemIdentifier, action: TimelineItemMenuAction) case handleTimelineItemMenuAction(itemID: TimelineItemIdentifier, action: TimelineItemMenuAction)
case displayRoomDetails
case displayRoomMemberDetails(userID: String)
case displayReactionSummary(itemID: TimelineItemIdentifier, key: String)
case displayEmojiPicker(itemID: TimelineItemIdentifier) case displayEmojiPicker(itemID: TimelineItemIdentifier)
case displayMessageSendingFailureAlert(itemID: TimelineItemIdentifier)
case displayReadReceipts(itemID: TimelineItemIdentifier)
case displayCall
case handlePasteOrDrop(provider: NSItemProvider) case handlePasteOrDrop(provider: NSItemProvider)
case handlePollAction(RoomScreenViewPollAction)
case tappedOnUser(userID: String) case handleAudioPlayerAction(RoomScreenAudioPlayerAction)
case reactionSummary(itemID: TimelineItemIdentifier, key: String)
case retrySend(itemID: TimelineItemIdentifier)
case cancelSend(itemID: TimelineItemIdentifier)
case showReadReceipts(itemID: TimelineItemIdentifier)
case poll(RoomScreenViewPollAction)
case audio(RoomScreenViewAudioAction)
case presentCall
/// Focus the timeline onto the specified event ID (switching to a detached timeline if needed). /// Focus the timeline onto the specified event ID (switching to a detached timeline if needed).
case focusOnEventID(String) case focusOnEventID(String)
@@ -161,18 +152,12 @@ struct RoomScreenViewStateBindings {
/// A media item that will be previewed with QuickLook. /// A media item that will be previewed with QuickLook.
var mediaPreviewItem: MediaPreviewItem? var mediaPreviewItem: MediaPreviewItem?
/// Information describing the currently displayed alert. var alertInfo: AlertInfo<RoomScreenAlertInfoType>?
var alertInfo: AlertInfo<RoomScreenErrorType>?
/// An alert info for confirmation actions (e.g. ending a poll)
var confirmationAlertInfo: AlertInfo<UUID>?
var debugInfo: TimelineItemDebugInfo? var debugInfo: TimelineItemDebugInfo?
var actionMenuInfo: TimelineItemActionMenuInfo? var actionMenuInfo: TimelineItemActionMenuInfo?
var sendFailedConfirmationDialogInfo: SendFailedConfirmationDialogInfo?
var reactionSummaryInfo: ReactionSummaryInfo? var reactionSummaryInfo: ReactionSummaryInfo?
var readReceiptsSummaryInfo: ReadReceiptSummaryInfo? var readReceiptsSummaryInfo: ReadReceiptSummaryInfo?
@@ -190,9 +175,7 @@ struct TimelineItemActionMenuInfo: Equatable, Identifiable {
} }
} }
struct SendFailedConfirmationDialogInfo: ConfirmationDialogProtocol { struct MessageSendingFailureInfo: Hashable {
let title = L10n.screenRoomRetrySendMenuTitle
let itemID: TimelineItemIdentifier let itemID: TimelineItemIdentifier
} }
@@ -210,11 +193,10 @@ struct ReadReceiptSummaryInfo: Identifiable {
let id: TimelineItemIdentifier let id: TimelineItemIdentifier
} }
enum RoomScreenErrorType: Hashable { enum RoomScreenAlertInfoType: Hashable {
/// A specific error message shown in an alert. case audioRecodingPermissionError
case alert(String) case pollEndConfirmation(String)
/// A specific error message shown in a toast. case messageSendingFailure(TimelineItemIdentifier)
case toast(String)
} }
struct RoomMemberState { struct RoomMemberState {
@@ -143,48 +143,51 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
override func process(viewAction: RoomScreenViewAction) { override func process(viewAction: RoomScreenViewAction) {
switch viewAction { switch viewAction {
case .displayRoomDetails:
actionsSubject.send(.displayRoomDetails)
case .itemAppeared(let id): case .itemAppeared(let id):
Task { await timelineController.processItemAppearance(id) } Task { await timelineController.processItemAppearance(id) }
case .itemDisappeared(let id): case .itemDisappeared(let id):
Task { await timelineController.processItemDisappearance(id) } Task { await timelineController.processItemDisappearance(id) }
case .itemTapped(let id): case .itemTapped(let id):
Task { await handleItemTapped(with: id) } Task { await handleItemTapped(with: id) }
case .toggleReaction(let emoji, let itemId): case .toggleReaction(let emoji, let itemId):
Task { await timelineController.toggleReaction(emoji, to: itemId) } Task { await timelineController.toggleReaction(emoji, to: itemId) }
case .sendReadReceiptIfNeeded(let lastVisibleItemID): case .sendReadReceiptIfNeeded(let lastVisibleItemID):
Task { await sendReadReceiptIfNeeded(for: lastVisibleItemID) } Task { await sendReadReceiptIfNeeded(for: lastVisibleItemID) }
case .timelineItemMenu(let itemID):
roomScreenInteractionHandler.showTimelineItemActionMenu(for: itemID)
case .timelineItemMenuAction(let itemID, let action):
roomScreenInteractionHandler.processTimelineItemMenuAction(action, itemID: itemID)
case .handlePasteOrDrop(let provider):
roomScreenInteractionHandler.handlePasteOrDrop(provider)
case .tappedOnUser(userID: let userID):
Task { await roomScreenInteractionHandler.handleTappedUser(userID: userID) }
case .displayEmojiPicker(let itemID):
roomScreenInteractionHandler.showEmojiPicker(for: itemID)
case .reactionSummary(let itemID, let key):
showReactionSummary(for: itemID, selectedKey: key)
case .retrySend(let itemID):
Task { await timelineController.retrySending(itemID: itemID) }
case .cancelSend(let itemID):
Task { await timelineController.cancelSending(itemID: itemID) }
case .paginateBackwards: case .paginateBackwards:
paginateBackwards() paginateBackwards()
case .paginateForwards: case .paginateForwards:
paginateForwards() paginateForwards()
case .scrollToBottom: case .scrollToBottom:
scrollToBottom() scrollToBottom()
case .poll(let pollAction):
processPollAction(pollAction) case .displayTimelineItemMenu(let itemID):
case .audio(let audioAction): roomScreenInteractionHandler.displayTimelineItemActionMenu(for: itemID)
processAudioAction(audioAction) case .handleTimelineItemMenuAction(let itemID, let action):
case .presentCall: roomScreenInteractionHandler.handleTimelineItemMenuAction(action, itemID: itemID)
case .displayRoomDetails:
actionsSubject.send(.displayRoomDetails)
case .displayRoomMemberDetails(userID: let userID):
Task { await roomScreenInteractionHandler.displayRoomMemberDetails(userID: userID) }
case .displayEmojiPicker(let itemID):
roomScreenInteractionHandler.displayEmojiPicker(for: itemID)
case .displayReactionSummary(let itemID, let key):
displayReactionSummary(for: itemID, selectedKey: key)
case .displayMessageSendingFailureAlert(let itemID):
displayAlert(.messageSendingFailure(itemID))
case .displayReadReceipts(itemID: let itemID):
displayReadReceipts(for: itemID)
case .displayCall:
actionsSubject.send(.displayCallScreen) actionsSubject.send(.displayCallScreen)
case .showReadReceipts(itemID: let itemID):
showReadReceipts(for: itemID) case .handlePasteOrDrop(let provider):
roomScreenInteractionHandler.handlePasteOrDrop(provider)
case .handlePollAction(let pollAction):
handlePollAction(pollAction)
case .handleAudioPlayerAction(let audioPlayerAction):
handleAudioPlayerAction(audioPlayerAction)
case .focusOnEventID(let eventID): case .focusOnEventID(let eventID):
Task { await focusOnEvent(eventID: eventID) } Task { await focusOnEvent(eventID: eventID) }
case .focusLive: case .focusLive:
@@ -245,9 +248,9 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
MXLog.error("Failed to focus on event \(eventID)") MXLog.error("Failed to focus on event \(eventID)")
if case .eventNotFound = error { if case .eventNotFound = error {
displayError(.toast(L10n.errorMessageNotFound)) displayErrorToast(L10n.errorMessageNotFound)
} else { } else {
displayError(.toast(L10n.commonFailed)) displayErrorToast(L10n.commonFailed)
} }
} }
} }
@@ -277,7 +280,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
return return
} }
roomScreenInteractionHandler.processTimelineItemMenuAction(.edit, itemID: item.id) roomScreenInteractionHandler.handleTimelineItemMenuAction(.edit, itemID: item.id)
} }
private func attach(_ attachment: ComposerAttachmentType) { private func attach(_ attachment: ComposerAttachmentType) {
@@ -295,22 +298,18 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
} }
} }
private func processPollAction(_ action: RoomScreenViewPollAction) { private func handlePollAction(_ action: RoomScreenViewPollAction) {
switch action { switch action {
case let .selectOption(pollStartID, optionID): case let .selectOption(pollStartID, optionID):
roomScreenInteractionHandler.sendPollResponse(pollStartID: pollStartID, optionID: optionID) roomScreenInteractionHandler.sendPollResponse(pollStartID: pollStartID, optionID: optionID)
case let .end(pollStartID): case let .end(pollStartID):
state.bindings.confirmationAlertInfo = .init(id: .init(), displayAlert(.pollEndConfirmation(pollStartID))
title: L10n.actionEndPoll,
message: L10n.commonPollEndConfirmation,
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
secondaryButton: .init(title: L10n.actionOk, action: { self.roomScreenInteractionHandler.endPoll(pollStartID: pollStartID) }))
case .edit(let pollStartID, let poll): case .edit(let pollStartID, let poll):
actionsSubject.send(.displayPollForm(mode: .edit(eventID: pollStartID, poll: poll))) actionsSubject.send(.displayPollForm(mode: .edit(eventID: pollStartID, poll: poll)))
} }
} }
private func processAudioAction(_ action: RoomScreenViewAudioAction) { private func handleAudioPlayerAction(_ action: RoomScreenAudioPlayerAction) {
switch action { switch action {
case .playPause(let itemID): case .playPause(let itemID):
Task { await roomScreenInteractionHandler.playPauseAudio(for: itemID) } Task { await roomScreenInteractionHandler.playPauseAudio(for: itemID) }
@@ -424,8 +423,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
switch action { switch action {
case .composer(let action): case .composer(let action):
actionsSubject.send(.composer(action: action)) actionsSubject.send(.composer(action: action))
case .displayError(let type): case .displayAudioRecorderPermissionError:
displayError(type) displayAlert(.audioRecodingPermissionError)
case .displayErrorToast(let title):
displayErrorToast(title)
case .displayEmojiPicker(let itemID, let selectedEmojis): case .displayEmojiPicker(let itemID, let selectedEmojis):
actionsSubject.send(.displayEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis)) actionsSubject.send(.displayEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis))
case .displayMessageForwarding(let itemID): case .displayMessageForwarding(let itemID):
@@ -442,8 +443,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
state.bindings.actionMenuInfo = actionMenuInfo state.bindings.actionMenuInfo = actionMenuInfo
case .showDebugInfo(let debugInfo): case .showDebugInfo(let debugInfo):
state.bindings.debugInfo = debugInfo state.bindings.debugInfo = debugInfo
case .showConfirmationAlert(let alertInfo):
state.bindings.confirmationAlertInfo = alertInfo
} }
} }
.store(in: &cancellables) .store(in: &cancellables)
@@ -483,7 +482,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
switch await timelineController.paginateBackwards(requestSize: Constants.paginationEventLimit) { switch await timelineController.paginateBackwards(requestSize: Constants.paginationEventLimit) {
case .failure: case .failure:
displayError(.toast(L10n.errorFailedLoadingMessages)) displayErrorToast(L10n.errorFailedLoadingMessages)
default: default:
break break
} }
@@ -503,7 +502,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
switch await timelineController.paginateForwards(requestSize: Constants.paginationEventLimit) { switch await timelineController.paginateForwards(requestSize: Constants.paginationEventLimit) {
case .failure: case .failure:
displayError(.toast(L10n.errorFailedLoadingMessages)) displayErrorToast(L10n.errorFailedLoadingMessages)
default: default:
break break
} }
@@ -718,7 +717,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: - Reactions // MARK: - Reactions
private func showReactionSummary(for itemID: TimelineItemIdentifier, selectedKey: String) { private func displayReactionSummary(for itemID: TimelineItemIdentifier, selectedKey: String) {
guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID),
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
return return
@@ -729,7 +728,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: - Read Receipts // MARK: - Read Receipts
private func showReadReceipts(for itemID: TimelineItemIdentifier) { private func displayReadReceipts(for itemID: TimelineItemIdentifier) {
guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID),
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
return return
@@ -737,7 +736,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
state.bindings.readReceiptsSummaryInfo = .init(orderedReceipts: eventTimelineItem.properties.orderedReadReceipts, id: eventTimelineItem.id) state.bindings.readReceiptsSummaryInfo = .init(orderedReceipts: eventTimelineItem.properties.orderedReadReceipts, id: eventTimelineItem.id)
} }
// MARK: - Message forwarding // MARK: - Message forwarding
private func forwardMessage(itemID: TimelineItemIdentifier) async { private func forwardMessage(itemID: TimelineItemIdentifier) async {
@@ -758,19 +757,38 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
userIndicatorController.retractIndicatorWithId(Constants.focusTimelineToastIndicatorID) userIndicatorController.retractIndicatorWithId(Constants.focusTimelineToastIndicatorID)
} }
private func displayError(_ type: RoomScreenErrorType) { private func displayAlert(_ type: RoomScreenAlertInfoType) {
switch type { switch type {
case .alert(let message): case .audioRecodingPermissionError:
state.bindings.alertInfo = AlertInfo(id: type, state.bindings.alertInfo = .init(id: type,
title: L10n.commonError, title: L10n.dialogPermissionMicrophoneTitleIos(InfoPlistReader.main.bundleDisplayName),
message: message) message: L10n.dialogPermissionMicrophoneDescriptionIos,
case .toast(let message): primaryButton: .init(title: L10n.commonSettings, action: { [weak self] in self?.appMediator.openAppSettings() }),
userIndicatorController.submitIndicator(UserIndicator(id: Constants.toastErrorID, secondaryButton: .init(title: L10n.actionNotNow, role: .cancel, action: nil))
type: .toast, case .pollEndConfirmation(let pollStartID):
title: message, state.bindings.alertInfo = .init(id: type,
iconName: "xmark")) title: L10n.actionEndPoll,
message: L10n.commonPollEndConfirmation,
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
secondaryButton: .init(title: L10n.actionOk, action: { self.roomScreenInteractionHandler.endPoll(pollStartID: pollStartID) }))
case .messageSendingFailure(let itemID):
state.bindings.alertInfo = .init(id: type,
title: L10n.screenRoomRetrySendMenuTitle,
primaryButton: .init(title: L10n.screenRoomRetrySendMenuSendAgainAction) {
Task { await self.timelineController.retrySending(itemID: itemID) }
},
secondaryButton: .init(title: L10n.actionRemove, role: .destructive) {
Task { await self.timelineController.cancelSending(itemID: itemID) }
})
} }
} }
private func displayErrorToast(_ title: String) {
userIndicatorController.submitIndicator(UserIndicator(id: Constants.toastErrorID,
type: .toast,
title: title,
iconName: "xmark"))
}
} }
private extension RoomProxyProtocol { private extension RoomProxyProtocol {
@@ -55,7 +55,6 @@ struct RoomScreen: View {
.toolbarBackground(.visible, for: .navigationBar) // Fix the toolbar's background. .toolbarBackground(.visible, for: .navigationBar) // Fix the toolbar's background.
.overlay { loadingIndicator } .overlay { loadingIndicator }
.alert(item: $context.alertInfo) .alert(item: $context.alertInfo)
.alert(item: $context.confirmationAlertInfo)
.sheet(item: $context.debugInfo) { TimelineItemDebugView(info: $0) } .sheet(item: $context.debugInfo) { TimelineItemDebugView(info: $0) }
.sheet(item: $context.actionMenuInfo) { info in .sheet(item: $context.actionMenuInfo) { info in
context.viewState.timelineItemMenuActionProvider?(info.item.id).map { actions in context.viewState.timelineItemMenuActionProvider?(info.item.id).map { actions in
@@ -82,14 +81,6 @@ struct RoomScreen: View {
context.send(viewAction: .handlePasteOrDrop(provider: provider)) context.send(viewAction: .handlePasteOrDrop(provider: provider))
return true return true
} }
.confirmationDialog(item: $context.sendFailedConfirmationDialogInfo, titleVisibility: .visible) { info in
Button(L10n.screenRoomRetrySendMenuSendAgainAction) {
context.send(viewAction: .retrySend(itemID: info.itemID))
}
Button(L10n.actionRemove, role: .destructive) {
context.send(viewAction: .cancelSend(itemID: info.itemID))
}
}
} }
private var timeline: some View { private var timeline: some View {
@@ -168,7 +159,7 @@ struct RoomScreen: View {
private var callButton: some View { private var callButton: some View {
if context.viewState.hasOngoingCall { if context.viewState.hasOngoingCall {
Button { Button {
context.send(viewAction: .presentCall) context.send(viewAction: .displayCall)
} label: { } label: {
Label(L10n.actionJoin, icon: \.videoCallSolid) Label(L10n.actionJoin, icon: \.videoCallSolid)
.labelStyle(.titleAndIcon) .labelStyle(.titleAndIcon)
@@ -177,7 +168,7 @@ struct RoomScreen: View {
.accessibilityIdentifier(A11yIdentifiers.roomScreen.joinCall) .accessibilityIdentifier(A11yIdentifiers.roomScreen.joinCall)
} else { } else {
Button { Button {
context.send(viewAction: .presentCall) context.send(viewAction: .displayCall)
} label: { } label: {
CompoundIcon(\.videoCallSolid) CompoundIcon(\.videoCallSolid)
} }
@@ -99,7 +99,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
// sender info are read inside the `TimelineAccessibilityModifier` // sender info are read inside the `TimelineAccessibilityModifier`
.accessibilityHidden(true) .accessibilityHidden(true)
.onTapGesture { .onTapGesture {
context.send(viewAction: .tappedOnUser(userID: timelineItem.sender.id)) context.send(viewAction: .displayRoomMemberDetails(userID: timelineItem.sender.id))
} }
.padding(.top, 8) .padding(.top, 8)
} }
@@ -111,9 +111,9 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
messageBubble messageBubble
.timelineItemAccessibility(timelineItem) { .timelineItemAccessibility(timelineItem) {
if adjustedDeliveryStatus == .sendingFailed { if adjustedDeliveryStatus == .sendingFailed {
context.sendFailedConfirmationDialogInfo = .init(itemID: timelineItem.id) context.send(viewAction: .displayMessageSendingFailureAlert(itemID: timelineItem.id))
} else { } else {
context.send(viewAction: .timelineItemMenu(itemID: timelineItem.id)) context.send(viewAction: .displayTimelineItemMenu(itemID: timelineItem.id))
} }
} }
@@ -139,7 +139,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
// We need a tap gesture before this long one so that it doesn't // We need a tap gesture before this long one so that it doesn't
// steal away the gestures from the scroll view // steal away the gestures from the scroll view
.longPressWithFeedback { .longPressWithFeedback {
context.send(viewAction: .timelineItemMenu(itemID: timelineItem.id)) context.send(viewAction: .displayTimelineItemMenu(itemID: timelineItem.id))
} }
.swipeRightAction { .swipeRightAction {
SwipeToReplyView(timelineItem: timelineItem) SwipeToReplyView(timelineItem: timelineItem)
@@ -147,12 +147,12 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
context.viewState.timelineItemMenuActionProvider?(timelineItem.id)?.canReply ?? false context.viewState.timelineItemMenuActionProvider?(timelineItem.id)?.canReply ?? false
} action: { } action: {
let isThread = (timelineItem as? EventBasedMessageTimelineItemProtocol)?.isThreaded ?? false let isThread = (timelineItem as? EventBasedMessageTimelineItemProtocol)?.isThreaded ?? false
context.send(viewAction: .timelineItemMenuAction(itemID: timelineItem.id, action: .reply(isThread: isThread))) context.send(viewAction: .handleTimelineItemMenuAction(itemID: timelineItem.id, action: .reply(isThread: isThread)))
} }
.contextMenu { .contextMenu {
TimelineItemMacContextMenu(item: timelineItem, TimelineItemMacContextMenu(item: timelineItem,
actionProvider: context.viewState.timelineItemMenuActionProvider) { action in actionProvider: context.viewState.timelineItemMenuActionProvider) { action in
context.send(viewAction: .timelineItemMenuAction(itemID: timelineItem.id, action: action)) context.send(viewAction: .handleTimelineItemMenuAction(itemID: timelineItem.id, action: action))
} }
} }
.padding(.top, messageBubbleTopPadding) .padding(.top, messageBubbleTopPadding)
@@ -180,7 +180,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
if adjustedDeliveryStatus == .sendingFailed { if adjustedDeliveryStatus == .sendingFailed {
layoutedLocalizedSendInfo layoutedLocalizedSendInfo
.onTapGesture { .onTapGesture {
context.sendFailedConfirmationDialogInfo = .init(itemID: timelineItem.id) context.send(viewAction: .displayMessageSendingFailureAlert(itemID: timelineItem.id))
} }
} else { } else {
layoutedLocalizedSendInfo layoutedLocalizedSendInfo
@@ -69,7 +69,7 @@ struct TimelineItemPlainStylerView<Content: View>: View {
content() content()
.layoutPriority(1) .layoutPriority(1)
.timelineItemAccessibility(timelineItem) { .timelineItemAccessibility(timelineItem) {
context.send(viewAction: .timelineItemMenu(itemID: timelineItem.id)) context.send(viewAction: .displayTimelineItemMenu(itemID: timelineItem.id))
} }
} }
.onTapGesture(count: 2) { .onTapGesture(count: 2) {
@@ -81,7 +81,7 @@ struct TimelineItemPlainStylerView<Content: View>: View {
// We need a tap gesture before this long one so that it doesn't // We need a tap gesture before this long one so that it doesn't
// steal away the gestures from the scroll view // steal away the gestures from the scroll view
.longPressWithFeedback { .longPressWithFeedback {
context.send(viewAction: .timelineItemMenu(itemID: timelineItem.id)) context.send(viewAction: .displayTimelineItemMenu(itemID: timelineItem.id))
} }
.swipeRightAction { .swipeRightAction {
SwipeToReplyView(timelineItem: timelineItem) SwipeToReplyView(timelineItem: timelineItem)
@@ -89,12 +89,12 @@ struct TimelineItemPlainStylerView<Content: View>: View {
context.viewState.timelineItemMenuActionProvider?(timelineItem.id)?.canReply ?? false context.viewState.timelineItemMenuActionProvider?(timelineItem.id)?.canReply ?? false
} action: { } action: {
let isThread = (timelineItem as? EventBasedMessageTimelineItemProtocol)?.isThreaded ?? false let isThread = (timelineItem as? EventBasedMessageTimelineItemProtocol)?.isThreaded ?? false
context.send(viewAction: .timelineItemMenuAction(itemID: timelineItem.id, action: .reply(isThread: isThread))) context.send(viewAction: .handleTimelineItemMenuAction(itemID: timelineItem.id, action: .reply(isThread: isThread)))
} }
.contextMenu { .contextMenu {
TimelineItemMacContextMenu(item: timelineItem, TimelineItemMacContextMenu(item: timelineItem,
actionProvider: context.viewState.timelineItemMenuActionProvider) { action in actionProvider: context.viewState.timelineItemMenuActionProvider) { action in
context.send(viewAction: .timelineItemMenuAction(itemID: timelineItem.id, action: action)) context.send(viewAction: .handleTimelineItemMenuAction(itemID: timelineItem.id, action: action))
} }
} }
} }
@@ -111,7 +111,7 @@ struct TimelineItemPlainStylerView<Content: View>: View {
.lineLimit(1) .lineLimit(1)
} }
.onTapGesture { .onTapGesture {
context.send(viewAction: .tappedOnUser(userID: timelineItem.sender.id)) context.send(viewAction: .displayRoomMemberDetails(userID: timelineItem.sender.id))
} }
Spacer() Spacer()
Text(timelineItem.timestamp) Text(timelineItem.timestamp)
@@ -56,7 +56,7 @@ struct TimelineItemStatusView: View {
CompoundIcon(\.error, size: .xSmall, relativeTo: .compound.bodyMD) CompoundIcon(\.error, size: .xSmall, relativeTo: .compound.bodyMD)
.foregroundColor(.compound.iconCriticalPrimary) .foregroundColor(.compound.iconCriticalPrimary)
.onTapGesture { .onTapGesture {
context.sendFailedConfirmationDialogInfo = .init(itemID: timelineItem.id) context.send(viewAction: .displayMessageSendingFailureAlert(itemID: timelineItem.id))
} }
.accessibilityLabel(L10n.commonSendingFailed) .accessibilityLabel(L10n.commonSendingFailed)
.accessibilityHint(L10n.actionTapForOptions) .accessibilityHint(L10n.actionTapForOptions)
@@ -57,7 +57,7 @@ struct TimelineReactionsView: View {
feedbackGenerator.impactOccurred() feedbackGenerator.impactOccurred()
context.send(viewAction: .toggleReaction(key: key, itemID: itemID)) context.send(viewAction: .toggleReaction(key: key, itemID: itemID))
} showReactionSummary: { key in } showReactionSummary: { key in
context.send(viewAction: .reactionSummary(itemID: itemID, key: key)) context.send(viewAction: .displayReactionSummary(itemID: itemID, key: key))
} }
.reactionLayoutItem(.reaction) .reactionLayoutItem(.reaction)
.environment(\.layoutDirection, layoutDirection) .environment(\.layoutDirection, layoutDirection)
@@ -46,7 +46,7 @@ struct TimelineReadReceiptsView: View {
} }
} }
.onTapGesture { .onTapGesture {
context.send(viewAction: .showReadReceipts(itemID: timelineItem.id)) context.send(viewAction: .displayReadReceipts(itemID: timelineItem.id))
} }
.accessibilityElement(children: .ignore) .accessibilityElement(children: .ignore)
.accessibilityLabel(accessibilityLabel) .accessibilityLabel(accessibilityLabel)
@@ -26,13 +26,13 @@ struct PollRoomTimelineView: View {
switch action { switch action {
case .selectOption(let optionID): case .selectOption(let optionID):
guard let eventID, let option = poll.options.first(where: { $0.id == optionID }), !option.isSelected else { return } guard let eventID, let option = poll.options.first(where: { $0.id == optionID }), !option.isSelected else { return }
context.send(viewAction: .poll(.selectOption(pollStartID: eventID, optionID: option.id))) context.send(viewAction: .handlePollAction(.selectOption(pollStartID: eventID, optionID: option.id)))
case .edit: case .edit:
guard let eventID else { return } guard let eventID else { return }
context.send(viewAction: .poll(.edit(pollStartID: eventID, poll: poll))) context.send(viewAction: .handlePollAction(.edit(pollStartID: eventID, poll: poll)))
case .end: case .end:
guard let eventID else { return } guard let eventID else { return }
context.send(viewAction: .poll(.end(pollStartID: eventID))) context.send(viewAction: .handlePollAction(.end(pollStartID: eventID)))
} }
} }
} }
@@ -298,7 +298,7 @@ struct TimelineItemMenu: View {
dismiss() dismiss()
// Otherwise we might get errors that a sheet is already presented // Otherwise we might get errors that a sheet is already presented
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
context.send(viewAction: .timelineItemMenuAction(itemID: item.id, action: action)) context.send(viewAction: .handleTimelineItemMenuAction(itemID: item.id, action: action))
} }
} }
} }
@@ -40,22 +40,22 @@ struct VoiceMessageRoomTimelineView: View {
} }
private func onPlaybackPlayPause() { private func onPlaybackPlayPause() {
context.send(viewAction: .audio(.playPause(itemID: timelineItem.id))) context.send(viewAction: .handleAudioPlayerAction(.playPause(itemID: timelineItem.id)))
} }
private func onPlaybackSeek(_ progress: Double) { private func onPlaybackSeek(_ progress: Double) {
context.send(viewAction: .audio(.seek(itemID: timelineItem.id, progress: progress))) context.send(viewAction: .handleAudioPlayerAction(.seek(itemID: timelineItem.id, progress: progress)))
} }
private func onPlaybackScrubbing(_ dragging: Bool) { private func onPlaybackScrubbing(_ dragging: Bool) {
if dragging { if dragging {
if playerState.playbackState == .playing { if playerState.playbackState == .playing {
resumePlaybackAfterScrubbing = true resumePlaybackAfterScrubbing = true
context.send(viewAction: .audio(.playPause(itemID: timelineItem.id))) context.send(viewAction: .handleAudioPlayerAction(.playPause(itemID: timelineItem.id)))
} }
} else { } else {
if resumePlaybackAfterScrubbing { if resumePlaybackAfterScrubbing {
context.send(viewAction: .audio(.playPause(itemID: timelineItem.id))) context.send(viewAction: .handleAudioPlayerAction(.playPause(itemID: timelineItem.id)))
resumePlaybackAfterScrubbing = false resumePlaybackAfterScrubbing = false
} }
} }
@@ -112,7 +112,7 @@ class RoomPollsHistoryScreenViewModelTests: XCTestCase {
} }
func testEndPoll() async throws { func testEndPoll() async throws {
let deferred = deferFulfillment(interactionHandler.publisher) { _ in true } let deferred = deferFulfillment(interactionHandler.publisher.delay(for: 0.1, scheduler: DispatchQueue.main)) { _ in true }
interactionHandler.endPollPollStartIDReturnValue = .success(()) interactionHandler.endPollPollStartIDReturnValue = .success(())
viewModel.context.send(viewAction: .end(pollStartID: "somePollID")) viewModel.context.send(viewAction: .end(pollStartID: "somePollID"))
@@ -244,84 +244,6 @@ class RoomScreenViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.context.viewState.timelineViewState.focussedEvent, .init(eventID: "t10", appearance: .immediate)) XCTAssertEqual(viewModel.context.viewState.timelineViewState.focussedEvent, .init(eventID: "t10", appearance: .immediate))
} }
// MARK: - Sending
func testRetrySend() async throws {
let timelineController = MockRoomTimelineController()
let roomProxy = RoomProxyMock(with: .init(name: ""))
let timelineProxy = TimelineProxyMock()
timelineProxy.underlyingActions = Empty(completeImmediately: false).eraseToAnyPublisher()
roomProxy.underlyingTimeline = timelineProxy
timelineController.roomProxy = roomProxy
let viewModel = makeViewModel(roomProxy: roomProxy, timelineController: timelineController)
viewModel.context.send(viewAction: .retrySend(itemID: .init(timelineID: UUID().uuidString, transactionID: "test retry send id")))
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(timelineProxy.retrySendTransactionIDCallsCount == 1)
XCTAssert(timelineProxy.retrySendTransactionIDReceivedInvocations == ["test retry send id"])
}
func testRetrySendNoTransactionID() async {
let timelineController = MockRoomTimelineController()
let roomProxy = RoomProxyMock(with: .init(name: ""))
let timelineProxy = TimelineProxyMock()
timelineProxy.underlyingActions = Empty(completeImmediately: false).eraseToAnyPublisher()
roomProxy.underlyingTimeline = timelineProxy
let viewModel = makeViewModel(roomProxy: roomProxy, timelineController: timelineController)
viewModel.context.send(viewAction: .retrySend(itemID: .random))
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(timelineProxy.retrySendTransactionIDCallsCount == 0)
}
func testCancelSend() async {
let timelineController = MockRoomTimelineController()
let roomProxy = RoomProxyMock(with: .init(name: ""))
let timelineProxy = TimelineProxyMock()
timelineProxy.underlyingActions = Empty(completeImmediately: false).eraseToAnyPublisher()
roomProxy.underlyingTimeline = timelineProxy
timelineController.roomProxy = roomProxy
let viewModel = makeViewModel(roomProxy: roomProxy, timelineController: timelineController)
viewModel.context.send(viewAction: .cancelSend(itemID: .init(timelineID: UUID().uuidString, transactionID: "test cancel send id")))
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(timelineProxy.cancelSendTransactionIDCallsCount == 1)
XCTAssert(timelineProxy.cancelSendTransactionIDReceivedInvocations == ["test cancel send id"])
}
func testCancelSendNoTransactionID() async {
let timelineController = MockRoomTimelineController()
let roomProxy = RoomProxyMock(with: .init(name: ""))
let timelineProxy = TimelineProxyMock()
timelineProxy.underlyingActions = Empty(completeImmediately: false).eraseToAnyPublisher()
roomProxy.underlyingTimeline = timelineProxy
let viewModel = makeViewModel(roomProxy: roomProxy, timelineController: timelineController)
viewModel.context.send(viewAction: .cancelSend(itemID: .random))
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(timelineProxy.cancelSendTransactionIDCallsCount == 0)
}
// MARK: - Read Receipts // MARK: - Read Receipts
// swiftlint:disable force_unwrapping // swiftlint:disable force_unwrapping
@@ -465,7 +387,7 @@ class RoomScreenViewModelTests: XCTestCase {
value.bindings.readReceiptsSummaryInfo?.orderedReceipts == receipts value.bindings.readReceiptsSummaryInfo?.orderedReceipts == receipts
} }
viewModel.context.send(viewAction: .showReadReceipts(itemID: id)) viewModel.context.send(viewAction: .displayReadReceipts(itemID: id))
try await deferred.fulfill() try await deferred.fulfill()
} }
+1
View File
@@ -0,0 +1 @@
Prevent the message sending failure options from showing up as a popup on the room list on iPads