MediaTimelinePreviewDetails can now be opened by long pressing in the media timeline (#4474)

* presenting media actions from the media timeline

* implemented view in timeline and fixed an issue that made dark mode being when trying to delete the file

* pr suggestions
This commit is contained in:
Mauro
2025-09-05 15:30:36 +02:00
committed by GitHub
parent 3d85f3de8c
commit 18eb226b64
12 changed files with 148 additions and 48 deletions

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 77;
objectVersion = 63;
objects = {
/* Begin PBXAggregateTarget section */
@@ -933,6 +933,7 @@
A6FFC4C5154C446BAD6B40D8 /* TimelineItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8520AFD6680CBAD388F6D927 /* TimelineItemProvider.swift */; };
A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; };
A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; };
A7A95DFE2E6AF86600B4BB22 /* AccessibleLongPress.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7A95DFD2E6AF85D00B4BB22 /* AccessibleLongPress.swift */; };
A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; };
A808DC3F72D15C6C5A52317E /* TimelineItemDebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDA016D05107DED3B9495CB /* TimelineItemDebugView.swift */; };
A816F7087C495D85048AC50E /* RoomMemberDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */; };
@@ -1498,7 +1499,7 @@
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>"; };
046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = "<group>"; };
048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = "<group>"; };
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>"; };
@@ -1575,7 +1576,7 @@
128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = "<group>"; };
12B09A94C519227264A41208 /* RoomMembershipDetailsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembershipDetailsProxy.swift; sourceTree = "<group>"; };
12FD5280AF55AB7F50F8E47D /* preview_avatar_room.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_avatar_room.jpg; sourceTree = "<group>"; };
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
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>"; };
@@ -1685,7 +1686,7 @@
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>"; };
260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = "<group>"; };
267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = "<group>"; };
267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = "<group>"; };
26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = "<group>"; };
26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = "<group>"; };
2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = "<group>"; };
@@ -1767,7 +1768,7 @@
355C8C46DA9C0B45F1B7FC4F /* SpaceRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceRoomProxy.swift; sourceTree = "<group>"; };
35A057BA9BE0F079784CD061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; };
37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModel.swift; sourceTree = "<group>"; };
37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringTests.swift; sourceTree = "<group>"; };
@@ -2200,7 +2201,7 @@
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>"; };
8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitorMock.swift; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; };
8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = "<group>"; };
8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSDKMock.swift; sourceTree = "<group>"; };
8F062DD2CCD95DC33528A16F /* KnockRequestProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KnockRequestProxy.swift; sourceTree = "<group>"; };
@@ -2324,6 +2325,7 @@
A768CA51A59B8A5D8C8FD599 /* AuthenticationStartScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreen.swift; sourceTree = "<group>"; };
A7978C9EFBDD7DE39BD86726 /* RestorationTokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationTokenTests.swift; sourceTree = "<group>"; };
A7A1B80FE6E3BA72F9C748AD /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = "<group>"; };
A7A95DFD2E6AF85D00B4BB22 /* AccessibleLongPress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibleLongPress.swift; sourceTree = "<group>"; };
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = "<group>"; };
@@ -2344,7 +2346,7 @@
AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = "<group>"; };
AB07F03461023BC39C730922 /* PhishingDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingDetector.swift; sourceTree = "<group>"; };
AB26D5444A4A7E095222DE8B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; path = AccessibilityTests.xctestplan; sourceTree = "<group>"; };
AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = AccessibilityTests.xctestplan; 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>"; };
AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageCache.swift; sourceTree = "<group>"; };
@@ -2411,7 +2413,7 @@
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>"; };
B5D829FD8958376614504B18 /* TargetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetConfiguration.swift; sourceTree = "<group>"; };
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; };
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; };
B65DDCF8E41759890355ACBC /* AuthenticationStartScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModelProtocol.swift; sourceTree = "<group>"; };
B68B31232312AFC844440BFE /* DeclineAndBlockScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenModels.swift; sourceTree = "<group>"; };
@@ -2438,7 +2440,7 @@
BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = "<group>"; };
BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = "<group>"; };
BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionProtocol.swift; sourceTree = "<group>"; };
BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; path = test_apple_image.heic; sourceTree = "<group>"; };
BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_apple_image.heic; sourceTree = "<group>"; };
BB5B00A014307CE37B2812CD /* TimelineViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModelProtocol.swift; sourceTree = "<group>"; };
BB6ED50FE104992419310EEB /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = "<group>"; };
BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = "<group>"; };
@@ -2539,7 +2541,7 @@
CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; };
CDE3F3911FF7CC639BDE5844 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
CFFA5E881D281810AB428EA3 /* RoomPowerLevelsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPowerLevelsProxy.swift; sourceTree = "<group>"; };
D01FD1171FF40E34D707FD00 /* BigIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigIcon.swift; sourceTree = "<group>"; };
D03D7ECAC68C2FFB8CF01BCB /* DeactivateAccountScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeactivateAccountScreen.swift; sourceTree = "<group>"; };
@@ -2603,7 +2605,7 @@
DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotification+Creator.swift"; sourceTree = "<group>"; };
DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelProtocol.swift; sourceTree = "<group>"; };
DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandler.swift; sourceTree = "<group>"; };
DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; path = test_voice_message.m4a; sourceTree = "<group>"; };
DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = "<group>"; };
DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModels.swift; sourceTree = "<group>"; };
DCDAB580109C09A6AA97AF7E /* PollFormScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenTests.swift; sourceTree = "<group>"; };
DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = "<group>"; };
@@ -2650,7 +2652,7 @@
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; };
E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = "<group>"; };
E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; };
E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = "<group>"; };
E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = "<group>"; };
E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = "<group>"; };
E5F2B6443D1ED8602F328539 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
E5FDFAA04174CC99FB66391C /* EditRoomAddressScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenViewModel.swift; sourceTree = "<group>"; };
@@ -2696,7 +2698,7 @@
ED0CBEAB5F796BEFBAF7BB6A /* VideoRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineView.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>"; };
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; };
ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = "<group>"; };
ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = "<group>"; };
EDDE826EAB1BAB80C1104980 /* SpaceFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceFlowCoordinator.swift; sourceTree = "<group>"; };
@@ -3429,6 +3431,7 @@
308FE2283B9803DBBB05602C /* Style */ = {
isa = PBXGroup;
children = (
A7A95DFD2E6AF85D00B4BB22 /* AccessibleLongPress.swift */,
1D9F148717D74F73BE724434 /* LongPressWithFeedback.swift */,
0B0E0B55E2EE75AF67029924 /* SwipeToReplyView.swift */,
2DA4F09CB613C54FDC73AE6A /* ThreadDecorator.swift */,
@@ -6840,7 +6843,6 @@
EC6D0C817B1C21D9D096505A /* XCRemoteSwiftPackageReference "Version" */,
EE40B0E16A55BD23ECBFFD22 /* XCRemoteSwiftPackageReference "matrix-rich-text-editor-swift" */,
);
preferredProjectObjectVersion = 77;
projectDirPath = "";
projectRoot = "";
targets = (
@@ -8142,6 +8144,7 @@
762DB0973865293F0C3D3D7B /* SessionVerificationScreenViewModelProtocol.swift in Sources */,
755395927DDD6EBDDA5E217A /* SettingsFlowCoordinator.swift in Sources */,
34F1261CEF6D6A00D559B520 /* SettingsScreen.swift in Sources */,
A7A95DFE2E6AF86600B4BB22 /* AccessibleLongPress.swift in Sources */,
AF8BFA37791E1756EE243E08 /* SettingsScreenCoordinator.swift in Sources */,
B93D7CE520088AD53FA6D53C /* SettingsScreenModels.swift in Sources */,
E0B6A569AC3E81D233B43D60 /* SettingsScreenViewModel.swift in Sources */,
@@ -8628,9 +8631,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_SWIFT_FLAGS = (
"-DRELEASE",
);
OTHER_SWIFT_FLAGS = "-DRELEASE";
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests";
PRODUCT_NAME = AccessibilityTests;
SDKROOT = iphoneos;
@@ -8649,9 +8650,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_SWIFT_FLAGS = (
"-DDEBUG",
);
OTHER_SWIFT_FLAGS = "-DDEBUG";
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests";
PRODUCT_NAME = AccessibilityTests;
SDKROOT = iphoneos;
@@ -8673,9 +8672,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = (
"-DIS_NSE",
);
OTHER_SWIFT_FLAGS = "-DIS_NSE";
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse";
PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
PRODUCT_NAME = NSE;
@@ -8724,9 +8721,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = (
"-DIS_MAIN_APP",
);
OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP";
PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills";
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(APP_NAME)";
@@ -8752,9 +8747,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = (
"-DIS_MAIN_APP",
);
OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP";
PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills";
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)";
PRODUCT_NAME = "$(APP_NAME)";
@@ -8979,9 +8972,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_SWIFT_FLAGS = (
"-DDEBUG",
);
OTHER_SWIFT_FLAGS = "-DDEBUG";
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests";
PRODUCT_NAME = UITests;
SDKROOT = iphoneos;
@@ -9000,9 +8991,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_SWIFT_FLAGS = (
"-DRELEASE",
);
OTHER_SWIFT_FLAGS = "-DRELEASE";
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.ui.tests";
PRODUCT_NAME = UITests;
SDKROOT = iphoneos;
@@ -9024,9 +9013,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "$(MARKETING_VERSION)";
OTHER_SWIFT_FLAGS = (
"-DIS_NSE",
);
OTHER_SWIFT_FLAGS = "-DIS_NSE";
PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse";
PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
PRODUCT_NAME = NSE;

View File

@@ -11,11 +11,21 @@ import SwiftUI
struct TimelineMediaPreviewDetailsView: View {
let item: TimelineMediaPreviewItem.Media
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
var preferredColorScheme: ColorScheme? = .dark
@Binding var sheetHeight: CGFloat
private let topPadding: CGFloat = 19
var body: some View {
if let preferredColorScheme {
mainContent
.preferredColorScheme(preferredColorScheme)
} else {
mainContent
}
}
private var mainContent: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
details
@@ -29,9 +39,10 @@ struct TimelineMediaPreviewDetailsView: View {
.presentationDetents([.height(sheetHeight + topPadding)])
.presentationDragIndicator(.visible)
.presentationBackground(.compound.bgCanvasDefault)
.preferredColorScheme(.dark)
.sheet(item: $context.redactConfirmationItem) { item in
TimelineMediaPreviewRedactConfirmationView(item: item, context: context)
TimelineMediaPreviewRedactConfirmationView(item: item,
context: context,
preferredColorScheme: preferredColorScheme)
}
}

View File

@@ -13,11 +13,21 @@ struct TimelineMediaPreviewRedactConfirmationView: View {
let item: TimelineMediaPreviewItem.Media
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
var preferredColorScheme: ColorScheme? = .dark
@State private var sheetHeight: CGFloat = .zero
private let topPadding: CGFloat = 19
var body: some View {
if let preferredColorScheme {
mainContent
.preferredColorScheme(preferredColorScheme)
} else {
mainContent
}
}
private var mainContent: some View {
ScrollView {
VStack(spacing: 0) {
header
@@ -31,7 +41,6 @@ struct TimelineMediaPreviewRedactConfirmationView: View {
.presentationDetents([.height(sheetHeight + topPadding)])
.presentationDragIndicator(.visible)
.presentationBackground(.compound.bgCanvasDefault)
.preferredColorScheme(.dark)
}
private var header: some View {

View File

@@ -36,6 +36,7 @@ struct MediaEventsTimelineScreenViewState: BindableState {
struct MediaEventsTimelineScreenViewStateBindings {
var screenMode: MediaEventsTimelineScreenMode
var mediaPreviewViewModel: TimelineMediaPreviewViewModel?
var mediaPreviewSheetViewModel: TimelineMediaPreviewViewModel?
}
enum MediaEventsTimelineScreenViewAction {
@@ -43,4 +44,5 @@ enum MediaEventsTimelineScreenViewAction {
case oldestItemDidAppear
case oldestItemDidDisappear
case tappedItem(item: RoomTimelineItemViewState)
case longPressedItem(item: RoomTimelineItemViewState)
}

View File

@@ -75,9 +75,12 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
.store(in: &cancellables)
mediaTimelineViewModel.actions.sink { [weak self] action in
guard let self else { return }
switch action {
case .displayMediaPreview(let mediaPreviewViewModel):
self?.displayMediaPreview(mediaPreviewViewModel)
displayMediaPreview(mediaPreviewViewModel)
case .displayMediaDetails(item: let item):
displayMediaPreviewSheet(for: item)
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker,
.displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen,
.displaySenderDetails, .displayMessageForwarding, .displayLocation, .displayResolveSendFailure,
@@ -97,9 +100,12 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
.store(in: &cancellables)
filesTimelineViewModel.actions.sink { [weak self] action in
guard let self else { return }
switch action {
case .displayMediaPreview(let mediaPreviewViewModel):
self?.displayMediaPreview(mediaPreviewViewModel)
displayMediaPreview(mediaPreviewViewModel)
case .displayMediaDetails(item: let item):
displayMediaPreviewSheet(for: item)
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker,
.displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen,
.displaySenderDetails, .displayMessageForwarding, .displayLocation, .displayResolveSendFailure,
@@ -127,6 +133,8 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
isOldestItemVisible = false
case .tappedItem(let item):
activeTimelineViewModel.context.send(viewAction: .mediaTapped(itemID: item.identifier))
case .longPressedItem(let item):
activeTimelineViewModel.context.send(viewAction: .displayTimelineItemMenu(itemID: item.identifier))
}
}
@@ -137,6 +145,29 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
// MARK: - Private
private func displayMediaPreviewSheet(for item: EventBasedMessageTimelineItemProtocol) {
let sheetModel = TimelineMediaPreviewViewModel(initialItem: item,
timelineViewModel: activeTimelineViewModel,
mediaProvider: mediaProvider,
photoLibraryManager: PhotoLibraryManager(),
userIndicatorController: userIndicatorController,
appMediator: appMediator)
sheetModel.actions.sink { [weak self] action in
guard let self else { return }
switch action {
case .viewInRoomTimeline(let itemID):
actionsSubject.send(.viewInRoomTimeline(itemID))
case .dismiss:
state.bindings.mediaPreviewSheetViewModel = nil
}
}
.store(in: &cancellables)
// Triggers a download of the item so that can be shared/saved
sheetModel.context.send(viewAction: .updateCurrentItem(sheetModel.state.currentItem))
state.bindings.mediaPreviewSheetViewModel = sheetModel
}
private func updateWithTimelineViewState(_ timelineViewState: TimelineViewState) {
var newGroups = [MediaEventsTimelineGroup]()
var currentItems = [RoomTimelineItemViewState]()

View File

@@ -10,6 +10,7 @@ import SwiftUI
struct MediaEventsTimelineScreen: View {
@ObservedObject var context: MediaEventsTimelineScreenViewModel.Context
@State private var sheetHeight = CGFloat.zero
var body: some View {
mainContent
@@ -24,6 +25,15 @@ struct MediaEventsTimelineScreen: View {
context.send(viewAction: .changedScreenMode)
}
.timelineMediaPreview(viewModel: $context.mediaPreviewViewModel)
.sheet(item: $context.mediaPreviewSheetViewModel) { sheet in
if case let .media(media) = sheet.state.currentItem {
TimelineMediaPreviewDetailsView(item: media,
context: sheet.context,
preferredColorScheme: nil,
sheetHeight: $sheetHeight)
.presentationDetents([.height(sheetHeight)])
}
}
}
// The scale effects do the following:
@@ -66,6 +76,9 @@ struct MediaEventsTimelineScreen: View {
viewForTimelineItem(item)
.scaleEffect(CGSize(width: -1, height: -1))
}
.accessibleLongPress(named: L10n.actionOpenContextMenu) {
context.send(viewAction: .longPressedItem(item: item))
}
}
} footer: {
// Use a footer as the header because the scrollView is flipped
@@ -96,6 +109,9 @@ struct MediaEventsTimelineScreen: View {
.accessibilityRepresentation {
viewForTimelineItem(item)
}
.accessibleLongPress(named: L10n.actionOpenContextMenu) {
context.send(viewAction: .longPressedItem(item: item))
}
}
.accessibilityElement(children: .combine)
.padding(.horizontal, 16)
@@ -230,6 +246,10 @@ struct MediaEventsTimelineScreen: View {
}
}
extension TimelineMediaPreviewViewModel: Identifiable {
var id: UUID { instanceID }
}
// MARK: - Previews
struct MediaEventsTimelineScreen_Previews: PreviewProvider, TestablePreview {

View File

@@ -90,7 +90,7 @@ final class PinnedEventsTimelineScreenCoordinator: CoordinatorProtocol {
// These other actions will not be handled in this view
case .displayEmojiPicker, .displayReportContent, .displayCameraPicker, .displayMediaPicker,
.displayDocumentPicker, .displayLocationPicker, .displayPollForm, .displayMediaUploadPreviewScreen,
.displayResolveSendFailure, .displayThread, .composer, .hasScrolled, .displayRoom:
.displayResolveSendFailure, .displayThread, .composer, .hasScrolled, .displayRoom, .displayMediaDetails:
// These actions are not handled in this coordinator
break
}

View File

@@ -147,7 +147,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
roomViewModel.timelineHasScrolled(direction: direction)
case .displayRoom(let roomID, let via):
actionsSubject.send(.presentRoom(roomID: roomID, via: via))
case .viewInRoomTimeline:
case .viewInRoomTimeline, .displayMediaDetails:
fatalError("The action: \(action) should not be sent to this coordinator")
}
}

View File

@@ -118,7 +118,7 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol {
case .displayResolveSendFailure(let failure, let sendHandle):
actionsSubject.send(.presentResolveSendFailure(failure: failure,
sendHandle: sendHandle))
case .hasScrolled, .displayRoom:
case .hasScrolled, .displayRoom, .displayMediaDetails:
break
case .composer(let action):
composerViewModel.process(timelineAction: action)

View File

@@ -29,6 +29,7 @@ enum TimelineViewModelAction {
case hasScrolled(direction: ScrollDirection)
case viewInRoomTimeline(eventID: String)
case displayRoom(roomID: String, via: [String])
case displayMediaDetails(item: EventBasedMessageTimelineItemProtocol)
}
enum TimelineViewPollAction {

View File

@@ -476,7 +476,12 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
case .displayMediaUploadPreviewScreen(let mediaURLs):
actionsSubject.send(.displayMediaUploadPreviewScreen(mediaURLs: mediaURLs))
case .showActionMenu(let actionMenuInfo):
self.state.bindings.actionMenuInfo = actionMenuInfo
if case .media(.mediaFilesScreen) = timelineController.timelineKind,
let item = actionMenuInfo.item as? EventBasedMessageTimelineItemProtocol {
actionsSubject.send(.displayMediaDetails(item: item))
} else {
self.state.bindings.actionMenuInfo = actionMenuInfo
}
case .showDebugInfo(let debugInfo):
state.bindings.debugInfo = debugInfo
case .viewInRoomTimeline(let eventID):

View File

@@ -0,0 +1,34 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import SwiftUI
extension View {
func accessibleLongPress(named name: String, action: @escaping () -> Void) -> some View {
modifier(AccessibleLongPress(name: name, action: action))
}
}
struct AccessibleLongPress: ViewModifier {
@Environment(\.accessibilityVoiceOverEnabled) private var isVoiceOverEnabled
let name: String
let action: () -> Void
func body(content: Content) -> some View {
if isVoiceOverEnabled {
content
.accessibilityAction(named: name) {
action()
}
} else {
content
.longPressWithFeedback {
action()
}
}
}
}