mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-06 04:18:31 +00:00
Bump the RustSDK to v1.0.53: adopt latest record based timeline item APIs (#3356)
This commit is contained in:
@@ -137,7 +137,6 @@
|
|||||||
1B8E30B35BF8F541C1318F19 /* SecureBackupScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */; };
|
1B8E30B35BF8F541C1318F19 /* SecureBackupScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */; };
|
||||||
1BA04D05EBC6646958B1BE60 /* PlaceholderScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */; };
|
1BA04D05EBC6646958B1BE60 /* PlaceholderScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */; };
|
||||||
1C409A26A99F0371C47AFA51 /* UserDiscoveryServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F615A00DB223FF3280204D2 /* UserDiscoveryServiceProtocol.swift */; };
|
1C409A26A99F0371C47AFA51 /* UserDiscoveryServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F615A00DB223FF3280204D2 /* UserDiscoveryServiceProtocol.swift */; };
|
||||||
1C815DD79B401DEBA2914773 /* TimelineItemMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4A1003A0F7A1DFB47F4E2D0 /* TimelineItemMock.swift */; };
|
|
||||||
1C8BC70A18060677E295A846 /* ShareToMapsAppActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */; };
|
1C8BC70A18060677E295A846 /* ShareToMapsAppActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */; };
|
||||||
1C9BB74711E5F24C77B7FED0 /* RoomMembersListScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA0B743847CFA5B3C38EE4 /* RoomMembersListScreenCoordinator.swift */; };
|
1C9BB74711E5F24C77B7FED0 /* RoomMembersListScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA0B743847CFA5B3C38EE4 /* RoomMembersListScreenCoordinator.swift */; };
|
||||||
1D5DC685CED904386C89B7DA /* NSRegularExpresion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */; };
|
1D5DC685CED904386C89B7DA /* NSRegularExpresion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */; };
|
||||||
@@ -211,6 +210,7 @@
|
|||||||
2DD9D0FE7CB5CFC80D071451 /* AppLockScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C3E67E09FE5A35D73818C39 /* AppLockScreenModels.swift */; };
|
2DD9D0FE7CB5CFC80D071451 /* AppLockScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C3E67E09FE5A35D73818C39 /* AppLockScreenModels.swift */; };
|
||||||
2E43A3D221BE9587BC19C3F1 /* MatrixEntityRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */; };
|
2E43A3D221BE9587BC19C3F1 /* MatrixEntityRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */; };
|
||||||
2E8C6672D0EE7D5B1BEDB8E2 /* ServerConfirmationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */; };
|
2E8C6672D0EE7D5B1BEDB8E2 /* ServerConfirmationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */; };
|
||||||
|
2F09DF0CB213CAE86A3E3B67 /* EventTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B10423B9102086A2D9BFCBA /* EventTimelineItem.swift */; };
|
||||||
2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 086B997409328F091EBA43CE /* RoomScreenUITests.swift */; };
|
2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 086B997409328F091EBA43CE /* RoomScreenUITests.swift */; };
|
||||||
2F6207CB5C4715FE313B1E95 /* TimelineViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6509708F54FC883604DFDC95 /* TimelineViewModelTests.swift */; };
|
2F6207CB5C4715FE313B1E95 /* TimelineViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6509708F54FC883604DFDC95 /* TimelineViewModelTests.swift */; };
|
||||||
2F623DA1122140A987B34D08 /* NotificationSettingsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7BB497B2F539C17E88F6B7 /* NotificationSettingsEditScreenViewModelProtocol.swift */; };
|
2F623DA1122140A987B34D08 /* NotificationSettingsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7BB497B2F539C17E88F6B7 /* NotificationSettingsEditScreenViewModelProtocol.swift */; };
|
||||||
@@ -407,7 +407,6 @@
|
|||||||
5AE6404C4FD4848ACCFF9EDC /* SecureBackupLogoutConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */; };
|
5AE6404C4FD4848ACCFF9EDC /* SecureBackupLogoutConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1573D28C8A9FB6399D0EEFB /* SecureBackupLogoutConfirmationScreenCoordinator.swift */; };
|
||||||
5B6E5AD224509E6C0B520D6E /* RoomMemberDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDF49CEBC0DFC59C308335F /* RoomMemberDetailsScreenViewModelProtocol.swift */; };
|
5B6E5AD224509E6C0B520D6E /* RoomMemberDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDF49CEBC0DFC59C308335F /* RoomMemberDetailsScreenViewModelProtocol.swift */; };
|
||||||
5B7D24A318AFF75AD611A026 /* RoomDirectorySearchScreenScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6BFF453838CF6C3982C5A3 /* RoomDirectorySearchScreenScreenViewModelTests.swift */; };
|
5B7D24A318AFF75AD611A026 /* RoomDirectorySearchScreenScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6BFF453838CF6C3982C5A3 /* RoomDirectorySearchScreenScreenViewModelTests.swift */; };
|
||||||
5BBDF9926CB645DE2F7BC258 /* EventTimelineItemSDKMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86D447D771CEF6194348F5F /* EventTimelineItemSDKMock.swift */; };
|
|
||||||
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
5BC6C4ADFE7F2A795ECDE130 /* SecureBackupKeyBackupScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */; };
|
||||||
5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
|
5C02841B2A86327B2C377682 /* NotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C830A64609CBD152F06E0457 /* NotificationConstants.swift */; };
|
||||||
5C164551F7D26E24F09083D3 /* StaticLocationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */; };
|
5C164551F7D26E24F09083D3 /* StaticLocationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C616D90B1E2F033CAA325439 /* StaticLocationScreenViewModelProtocol.swift */; };
|
||||||
@@ -1309,6 +1308,7 @@
|
|||||||
1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerStaticMap.swift; sourceTree = "<group>"; };
|
1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerStaticMap.swift; sourceTree = "<group>"; };
|
||||||
1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoURITests.swift; sourceTree = "<group>"; };
|
1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoURITests.swift; sourceTree = "<group>"; };
|
||||||
1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreen.swift; sourceTree = "<group>"; };
|
1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreen.swift; sourceTree = "<group>"; };
|
||||||
|
1B10423B9102086A2D9BFCBA /* EventTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItem.swift; sourceTree = "<group>"; };
|
1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillAttachmentViewProvider.swift; sourceTree = "<group>"; };
|
1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillAttachmentViewProvider.swift; sourceTree = "<group>"; };
|
||||||
1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenModels.swift; sourceTree = "<group>"; };
|
1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenModels.swift; sourceTree = "<group>"; };
|
||||||
@@ -1904,7 +1904,6 @@
|
|||||||
A433BE28B40D418237BE37B5 /* ReportContentScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreen.swift; sourceTree = "<group>"; };
|
A433BE28B40D418237BE37B5 /* ReportContentScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreen.swift; sourceTree = "<group>"; };
|
||||||
A436057DBEA1A23CA8CB1FD7 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = "<group>"; };
|
A436057DBEA1A23CA8CB1FD7 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = "<group>"; };
|
||||||
A443FAE2EE820A5790C35C8D /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = "<group>"; };
|
A443FAE2EE820A5790C35C8D /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
A4A1003A0F7A1DFB47F4E2D0 /* TimelineItemMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMock.swift; sourceTree = "<group>"; };
|
|
||||||
A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineFlowCoordinator.swift; sourceTree = "<group>"; };
|
A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineFlowCoordinator.swift; sourceTree = "<group>"; };
|
||||||
A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiDetectionTests.swift; sourceTree = "<group>"; };
|
A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiDetectionTests.swift; sourceTree = "<group>"; };
|
||||||
A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModel.swift; sourceTree = "<group>"; };
|
A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
@@ -2003,7 +2002,6 @@
|
|||||||
B81B6170DB690013CEB646F4 /* MapLibreModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLibreModels.swift; sourceTree = "<group>"; };
|
B81B6170DB690013CEB646F4 /* MapLibreModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLibreModels.swift; sourceTree = "<group>"; };
|
||||||
B8516302ACCA94A0E680AB3B /* VoiceMessageButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageButton.swift; sourceTree = "<group>"; };
|
B8516302ACCA94A0E680AB3B /* VoiceMessageButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageButton.swift; sourceTree = "<group>"; };
|
||||||
B858A61F2A570DFB8DE570A7 /* AggregratedReaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggregratedReaction.swift; sourceTree = "<group>"; };
|
B858A61F2A570DFB8DE570A7 /* AggregratedReaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggregratedReaction.swift; sourceTree = "<group>"; };
|
||||||
B86D447D771CEF6194348F5F /* EventTimelineItemSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventTimelineItemSDKMock.swift; sourceTree = "<group>"; };
|
|
||||||
B8A3B7637DDBD6AA97AC2545 /* CameraPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPicker.swift; sourceTree = "<group>"; };
|
B8A3B7637DDBD6AA97AC2545 /* CameraPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPicker.swift; sourceTree = "<group>"; };
|
||||||
B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationCoordinators.swift; sourceTree = "<group>"; };
|
B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationCoordinators.swift; sourceTree = "<group>"; };
|
||||||
B902EA6CD3296B0E10EE432B /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; };
|
B902EA6CD3296B0E10EE432B /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; };
|
||||||
@@ -2899,6 +2897,7 @@
|
|||||||
E2F96CCBEAAA7F2185BFA354 /* ClientProxyMock.swift */,
|
E2F96CCBEAAA7F2185BFA354 /* ClientProxyMock.swift */,
|
||||||
4E600B315B920B9687F8EE1B /* ComposerDraftServiceMock.swift */,
|
4E600B315B920B9687F8EE1B /* ComposerDraftServiceMock.swift */,
|
||||||
E321E840DCC63790049984F4 /* ElementCallServiceMock.swift */,
|
E321E840DCC63790049984F4 /* ElementCallServiceMock.swift */,
|
||||||
|
1B10423B9102086A2D9BFCBA /* EventTimelineItem.swift */,
|
||||||
867DC9530C42F7B5176BE465 /* JoinedRoomProxyMock.swift */,
|
867DC9530C42F7B5176BE465 /* JoinedRoomProxyMock.swift */,
|
||||||
8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */,
|
8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */,
|
||||||
382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */,
|
382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */,
|
||||||
@@ -2911,7 +2910,6 @@
|
|||||||
D479DF730528153665E5782E /* RoomTimelineControllerFactoryMock.swift */,
|
D479DF730528153665E5782E /* RoomTimelineControllerFactoryMock.swift */,
|
||||||
F74532E01B317C56C1BE8FA8 /* RoomTimelineProviderMock.swift */,
|
F74532E01B317C56C1BE8FA8 /* RoomTimelineProviderMock.swift */,
|
||||||
248649EBA5BC33DB93698734 /* SessionVerificationControllerProxyMock.swift */,
|
248649EBA5BC33DB93698734 /* SessionVerificationControllerProxyMock.swift */,
|
||||||
A4A1003A0F7A1DFB47F4E2D0 /* TimelineItemMock.swift */,
|
|
||||||
7893780A1FD6E3F38B3E9049 /* UserIndicatorControllerMock.swift */,
|
7893780A1FD6E3F38B3E9049 /* UserIndicatorControllerMock.swift */,
|
||||||
AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */,
|
AAD01F7FC2BBAC7351948595 /* UserProfile+Mock.swift */,
|
||||||
F4469F6AE311BDC439B3A5EC /* UserSessionMock.swift */,
|
F4469F6AE311BDC439B3A5EC /* UserSessionMock.swift */,
|
||||||
@@ -5257,7 +5255,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */,
|
8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */,
|
||||||
B86D447D771CEF6194348F5F /* EventTimelineItemSDKMock.swift */,
|
|
||||||
);
|
);
|
||||||
path = SDK;
|
path = SDK;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -6449,7 +6446,7 @@
|
|||||||
50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */,
|
50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */,
|
||||||
F78BAD28482A467287A9A5A3 /* EventBasedMessageTimelineItemProtocol.swift in Sources */,
|
F78BAD28482A467287A9A5A3 /* EventBasedMessageTimelineItemProtocol.swift in Sources */,
|
||||||
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */,
|
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */,
|
||||||
5BBDF9926CB645DE2F7BC258 /* EventTimelineItemSDKMock.swift in Sources */,
|
2F09DF0CB213CAE86A3E3B67 /* EventTimelineItem.swift in Sources */,
|
||||||
63E46D18B91D08E15FC04125 /* ExpiringTaskRunner.swift in Sources */,
|
63E46D18B91D08E15FC04125 /* ExpiringTaskRunner.swift in Sources */,
|
||||||
5F06AD3C66884CE793AE6119 /* FileManager.swift in Sources */,
|
5F06AD3C66884CE793AE6119 /* FileManager.swift in Sources */,
|
||||||
D33AC79A50DFC26D2498DD28 /* FileRoomTimelineItem.swift in Sources */,
|
D33AC79A50DFC26D2498DD28 /* FileRoomTimelineItem.swift in Sources */,
|
||||||
@@ -6933,7 +6930,6 @@
|
|||||||
6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */,
|
6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */,
|
||||||
AE07F215EBC2B9CBF17AA54B /* TimelineItemMenuAction.swift in Sources */,
|
AE07F215EBC2B9CBF17AA54B /* TimelineItemMenuAction.swift in Sources */,
|
||||||
12CD8B5CC30A05061228BF9E /* TimelineItemMenuActionProvider.swift in Sources */,
|
12CD8B5CC30A05061228BF9E /* TimelineItemMenuActionProvider.swift in Sources */,
|
||||||
1C815DD79B401DEBA2914773 /* TimelineItemMock.swift in Sources */,
|
|
||||||
440123E29E2F9B001A775BBE /* TimelineItemProxy.swift in Sources */,
|
440123E29E2F9B001A775BBE /* TimelineItemProxy.swift in Sources */,
|
||||||
9586E90A447C4896C0CA3A8E /* TimelineItemReplyDetails.swift in Sources */,
|
9586E90A447C4896C0CA3A8E /* TimelineItemReplyDetails.swift in Sources */,
|
||||||
F3ECA377FF77E81A4F1FA062 /* TimelineItemSendInfoLabel.swift in Sources */,
|
F3ECA377FF77E81A4F1FA062 /* TimelineItemSendInfoLabel.swift in Sources */,
|
||||||
@@ -7799,7 +7795,7 @@
|
|||||||
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
|
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = exactVersion;
|
kind = exactVersion;
|
||||||
version = 1.0.52;
|
version = 1.0.53;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
|
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
|
||||||
|
|||||||
@@ -149,8 +149,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
|
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "11c6d99d62035b02f4c448daebff4d63c962da20",
|
"revision" : "83abbdc8485340c20f27148153ff62f690ca210b",
|
||||||
"version" : "1.0.52"
|
"version" : "1.0.53"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ protocol AppMediatorProtocol {
|
|||||||
func requestAuthorizationIfNeeded() async -> Bool
|
func requestAuthorizationIfNeeded() async -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UIApplication.State: CustomStringConvertible {
|
extension UIApplication.State: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .active:
|
case .active:
|
||||||
@@ -44,7 +44,7 @@ extension UIApplication.State: CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UIUserInterfaceActiveAppearance: CustomStringConvertible {
|
extension UIUserInterfaceActiveAppearance: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .active:
|
case .active:
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
// Please see LICENSE in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import LoremSwiftum
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
|
struct EventTimelineItemSDKMockConfiguration {
|
||||||
|
var eventID: String = UUID().uuidString
|
||||||
|
var sender = ""
|
||||||
|
var isOwn = false
|
||||||
|
var content: TimelineItemContent = .redactedMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
extension EventTimelineItem {
|
||||||
|
init(configuration: EventTimelineItemSDKMockConfiguration) {
|
||||||
|
self.init(isLocal: false,
|
||||||
|
isRemote: true,
|
||||||
|
eventOrTransactionId: .eventId(eventId: configuration.eventID),
|
||||||
|
sender: configuration.sender,
|
||||||
|
senderProfile: .pending,
|
||||||
|
isOwn: configuration.isOwn,
|
||||||
|
isEditable: false,
|
||||||
|
content: configuration.content,
|
||||||
|
timestamp: 0,
|
||||||
|
reactions: [],
|
||||||
|
debugInfoProvider: EventTimelineItemDebugInfoProviderSDKMock(),
|
||||||
|
localSendState: nil,
|
||||||
|
readReceipts: [:],
|
||||||
|
origin: nil,
|
||||||
|
canBeRepliedTo: false,
|
||||||
|
shieldsProvider: EventShieldsProviderSDKMock())
|
||||||
|
}
|
||||||
|
|
||||||
|
static var mockMessage: EventTimelineItem {
|
||||||
|
let body = Lorem.sentences(Int.random(in: 1...5))
|
||||||
|
let messageType = MessageType.text(content: .init(body: body, formatted: nil))
|
||||||
|
|
||||||
|
let content = TimelineItemContent.message(content: .init(msgType: messageType,
|
||||||
|
body: body,
|
||||||
|
inReplyTo: nil,
|
||||||
|
threadRoot: nil,
|
||||||
|
isEdited: false,
|
||||||
|
mentions: nil))
|
||||||
|
|
||||||
|
return .init(configuration: .init(content: content))
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mockCallInvite(sender: String) -> EventTimelineItem {
|
||||||
|
.init(configuration: .init(sender: sender, content: .callInvite))
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -82,7 +82,7 @@ extension Poll.Option {
|
|||||||
|
|
||||||
extension PollRoomTimelineItem {
|
extension PollRoomTimelineItem {
|
||||||
static func mock(poll: Poll, isOutgoing: Bool = true, isEditable: Bool = false) -> Self {
|
static func mock(poll: Poll, isOutgoing: Bool = true, isEditable: Bool = false) -> Self {
|
||||||
.init(id: .init(timelineID: UUID().uuidString, eventID: UUID().uuidString),
|
.init(id: .random,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
body: "poll",
|
body: "poll",
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ class AutoUpdatingRoomTimelineProviderMock: RoomTimelineProvider {
|
|||||||
|
|
||||||
let diff = TimelineDiffSDKMock()
|
let diff = TimelineDiffSDKMock()
|
||||||
diff.changeReturnValue = .append
|
diff.changeReturnValue = .append
|
||||||
diff.appendReturnValue = [TimelineItemFixtures.messageTimelineItem]
|
|
||||||
|
let timelineItem = TimelineItemSDKMock()
|
||||||
|
timelineItem.asEventReturnValue = EventTimelineItem.mockMessage
|
||||||
|
timelineItem.uniqueIdReturnValue = UUID().uuidString
|
||||||
|
|
||||||
|
diff.appendReturnValue = [timelineItem]
|
||||||
|
|
||||||
await Self.timelineListener?.onUpdate(diff: [diff])
|
await Self.timelineListener?.onUpdate(diff: [diff])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2024 New Vector Ltd.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
// Please see LICENSE in the repository root for full details.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct EventTimelineItemSDKMockConfiguration {
|
|
||||||
var eventID: String = UUID().uuidString
|
|
||||||
}
|
|
||||||
|
|
||||||
extension EventTimelineItemSDKMock {
|
|
||||||
convenience init(configuration: EventTimelineItemSDKMockConfiguration) {
|
|
||||||
self.init()
|
|
||||||
eventIdReturnValue = configuration.eventID
|
|
||||||
isOwnReturnValue = false
|
|
||||||
timestampReturnValue = 0
|
|
||||||
isEditableReturnValue = false
|
|
||||||
canBeRepliedToReturnValue = false
|
|
||||||
senderReturnValue = ""
|
|
||||||
senderProfileReturnValue = .pending
|
|
||||||
|
|
||||||
let timelineItemContent = TimelineItemContentSDKMock()
|
|
||||||
timelineItemContent.kindReturnValue = .redactedMessage
|
|
||||||
contentReturnValue = timelineItemContent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2024 New Vector Ltd.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
// Please see LICENSE in the repository root for full details.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
import LoremSwiftum
|
|
||||||
import MatrixRustSDK
|
|
||||||
|
|
||||||
enum TimelineItemFixtures {
|
|
||||||
static var callInviteTimelineItem: TimelineItem {
|
|
||||||
let eventTimelineItem = EventTimelineItemSDKMock()
|
|
||||||
eventTimelineItem.isOwnReturnValue = true
|
|
||||||
eventTimelineItem.timestampReturnValue = 0
|
|
||||||
eventTimelineItem.isEditableReturnValue = false
|
|
||||||
eventTimelineItem.canBeRepliedToReturnValue = false
|
|
||||||
eventTimelineItem.senderReturnValue = "@bob:matrix.org"
|
|
||||||
eventTimelineItem.senderProfileReturnValue = .pending
|
|
||||||
|
|
||||||
let timelineItemContent = TimelineItemContentSDKMock()
|
|
||||||
timelineItemContent.kindReturnValue = .callInvite
|
|
||||||
eventTimelineItem.contentReturnValue = timelineItemContent
|
|
||||||
|
|
||||||
let timelineItem = TimelineItemSDKMock()
|
|
||||||
timelineItem.asEventReturnValue = eventTimelineItem
|
|
||||||
|
|
||||||
return timelineItem
|
|
||||||
}
|
|
||||||
|
|
||||||
static var messageTimelineItem: TimelineItem {
|
|
||||||
let eventTimelineItem = EventTimelineItemSDKMock()
|
|
||||||
eventTimelineItem.eventIdReturnValue = UUID().uuidString
|
|
||||||
eventTimelineItem.isOwnReturnValue = true
|
|
||||||
eventTimelineItem.timestampReturnValue = 0
|
|
||||||
eventTimelineItem.isEditableReturnValue = false
|
|
||||||
eventTimelineItem.canBeRepliedToReturnValue = false
|
|
||||||
eventTimelineItem.senderReturnValue = "@bob:matrix.org"
|
|
||||||
eventTimelineItem.senderProfileReturnValue = .pending
|
|
||||||
eventTimelineItem.reactionsReturnValue = []
|
|
||||||
eventTimelineItem.readReceiptsReturnValue = [:]
|
|
||||||
|
|
||||||
let timelineItemContent = TimelineItemContentSDKMock()
|
|
||||||
|
|
||||||
timelineItemContent.kindReturnValue = .message
|
|
||||||
|
|
||||||
let message = MessageSDKMock()
|
|
||||||
|
|
||||||
let textMessageContent = TextMessageContent(body: Lorem.sentences(Int.random(in: 1...5)), formatted: nil)
|
|
||||||
message.msgtypeReturnValue = .text(content: textMessageContent)
|
|
||||||
message.isThreadedReturnValue = false
|
|
||||||
message.isEditedReturnValue = false
|
|
||||||
|
|
||||||
timelineItemContent.asMessageReturnValue = message
|
|
||||||
|
|
||||||
eventTimelineItem.contentReturnValue = timelineItemContent
|
|
||||||
|
|
||||||
let timelineItem = TimelineItemSDKMock()
|
|
||||||
timelineItem.asEventReturnValue = eventTimelineItem
|
|
||||||
timelineItem.uniqueIdReturnValue = UUID().uuidString
|
|
||||||
|
|
||||||
return timelineItem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -61,6 +61,6 @@ extension Array {
|
|||||||
|
|
||||||
extension Array where Element == RoomTimelineItemProtocol {
|
extension Array where Element == RoomTimelineItemProtocol {
|
||||||
func firstUsingStableID(_ id: TimelineItemIdentifier) -> Element? {
|
func firstUsingStableID(_ id: TimelineItemIdentifier) -> Element? {
|
||||||
first { $0.id.timelineID == id.timelineID }
|
first { $0.id.uniqueID == id.uniqueID }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
extension ProposedViewSize: Hashable {
|
extension ProposedViewSize: @retroactive Hashable {
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(width)
|
hasher.combine(width)
|
||||||
hasher.combine(height)
|
hasher.combine(height)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension URL: ExpressibleByStringLiteral {
|
extension URL: @retroactive ExpressibleByStringLiteral {
|
||||||
public init(stringLiteral value: StaticString) {
|
public init(stringLiteral value: StaticString) {
|
||||||
guard let url = URL(string: "\(value)") else {
|
guard let url = URL(string: "\(value)") else {
|
||||||
fatalError("The static string used to create this URL is invalid")
|
fatalError("The static string used to create this URL is invalid")
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ private struct MessageForwardingListRow: View {
|
|||||||
struct MessageForwardingScreen_Previews: PreviewProvider, TestablePreview {
|
struct MessageForwardingScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let summaryProvider = RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))
|
let summaryProvider = RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))
|
||||||
let viewModel = MessageForwardingScreenViewModel(forwardingItem: .init(id: .init(timelineID: ""),
|
let viewModel = MessageForwardingScreenViewModel(forwardingItem: .init(id: .init(uniqueID: ""),
|
||||||
roomID: "",
|
roomID: "",
|
||||||
content: .init(noPointer: .init())),
|
content: .init(noPointer: .init())),
|
||||||
clientProxy: ClientProxyMock(.init()),
|
clientProxy: ClientProxyMock(.init()),
|
||||||
|
|||||||
@@ -258,9 +258,9 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
|||||||
case .newMessage:
|
case .newMessage:
|
||||||
set(mode: .default)
|
set(mode: .default)
|
||||||
case .edit(let eventID):
|
case .edit(let eventID):
|
||||||
set(mode: .edit(originalItemId: .init(timelineID: "", eventID: eventID)))
|
set(mode: .edit(originalItemId: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: eventID))))
|
||||||
case .reply(let eventID):
|
case .reply(let eventID):
|
||||||
set(mode: .reply(itemID: .init(timelineID: "", eventID: eventID), replyDetails: .loading(eventID: eventID), isThread: false))
|
set(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: eventID)), replyDetails: .loading(eventID: eventID), isThread: false))
|
||||||
replyLoadingTask = Task {
|
replyLoadingTask = Task {
|
||||||
let reply = switch await draftService.getReply(eventID: eventID) {
|
let reply = switch await draftService.getReply(eventID: eventID) {
|
||||||
case .success(let reply):
|
case .success(let reply):
|
||||||
@@ -273,7 +273,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set(mode: .reply(itemID: .init(timelineID: "", eventID: eventID), replyDetails: reply.details, isThread: reply.isThreaded))
|
set(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: eventID)), replyDetails: reply.details, isThread: reply.isThreaded))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -415,10 +415,10 @@ extension ComposerToolbar {
|
|||||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||||
analyticsService: ServiceLocator.shared.analytics,
|
analyticsService: ServiceLocator.shared.analytics,
|
||||||
composerDraftService: ComposerDraftServiceMock())
|
composerDraftService: ComposerDraftServiceMock())
|
||||||
model.state.composerMode = isLoading ? .reply(itemID: .init(timelineID: ""),
|
model.state.composerMode = isLoading ? .reply(itemID: .init(uniqueID: ""),
|
||||||
replyDetails: .loading(eventID: ""),
|
replyDetails: .loading(eventID: ""),
|
||||||
isThread: false) :
|
isThread: false) :
|
||||||
.reply(itemID: .init(timelineID: ""),
|
.reply(itemID: .init(uniqueID: ""),
|
||||||
replyDetails: .loaded(sender: .init(id: "",
|
replyDetails: .loaded(sender: .init(id: "",
|
||||||
displayName: "Test"),
|
displayName: "Test"),
|
||||||
eventID: "", eventContent: .message(.text(.init(body: "Hello World!")))), isThread: false)
|
eventID: "", eventContent: .message(.text(.init(body: "Hello World!")))), isThread: false)
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ struct TimelineState {
|
|||||||
|
|
||||||
var itemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
|
var itemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
|
||||||
|
|
||||||
var timelineIDs: [String] {
|
var uniqueIDs: [String] {
|
||||||
itemsDictionary.keys.elements
|
itemsDictionary.keys.elements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -401,8 +401,8 @@ class TimelineTableViewController: UIViewController {
|
|||||||
|
|
||||||
// These are already in reverse order because the table view is flipped
|
// These are already in reverse order because the table view is flipped
|
||||||
for indexPath in visibleIndexPaths {
|
for indexPath in visibleIndexPaths {
|
||||||
if let visibleItemTimelineID = dataSource?.itemIdentifier(for: indexPath),
|
if let visibleItemUniqueID = dataSource?.itemIdentifier(for: indexPath),
|
||||||
let visibleItemID = timelineItemsDictionary[visibleItemTimelineID]?.identifier {
|
let visibleItemID = timelineItemsDictionary[visibleItemUniqueID]?.identifier {
|
||||||
coordinator.send(viewAction: .sendReadReceiptIfNeeded(visibleItemID))
|
coordinator.send(viewAction: .sendReadReceiptIfNeeded(visibleItemID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -488,7 +488,7 @@ extension TimelineTableViewController {
|
|||||||
/// The current layout of the table, based on the newest timeline item.
|
/// The current layout of the table, based on the newest timeline item.
|
||||||
private func snapshotLayout() -> Layout? {
|
private func snapshotLayout() -> Layout? {
|
||||||
guard let newestItemID = newestVisibleItemID(),
|
guard let newestItemID = newestVisibleItemID(),
|
||||||
let newestCellFrame = cellFrame(for: newestItemID.timelineID) else {
|
let newestCellFrame = cellFrame(for: newestItemID.uniqueID) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return Layout(id: newestItemID, frame: newestCellFrame)
|
return Layout(id: newestItemID, frame: newestCellFrame)
|
||||||
@@ -496,12 +496,12 @@ extension TimelineTableViewController {
|
|||||||
|
|
||||||
/// Restores the timeline's layout from an old snapshot.
|
/// Restores the timeline's layout from an old snapshot.
|
||||||
private func restoreLayout(_ layout: Layout) {
|
private func restoreLayout(_ layout: Layout) {
|
||||||
if let indexPath = dataSource?.indexPath(for: layout.id.timelineID) {
|
if let indexPath = dataSource?.indexPath(for: layout.id.uniqueID) {
|
||||||
// Scroll the item into view.
|
// Scroll the item into view.
|
||||||
tableView.scrollToRow(at: indexPath, at: .top, animated: false)
|
tableView.scrollToRow(at: indexPath, at: .top, animated: false)
|
||||||
|
|
||||||
// Remove any unwanted offset that was added by scrollToRow.
|
// Remove any unwanted offset that was added by scrollToRow.
|
||||||
if let frame = cellFrame(for: layout.id.timelineID) {
|
if let frame = cellFrame(for: layout.id.uniqueID) {
|
||||||
let deltaY = frame.maxY - layout.frame.maxY
|
let deltaY = frame.maxY - layout.frame.maxY
|
||||||
if deltaY != 0 {
|
if deltaY != 0 {
|
||||||
tableView.contentOffset.y -= deltaY
|
tableView.contentOffset.y -= deltaY
|
||||||
@@ -511,8 +511,8 @@ extension TimelineTableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the frame of the cell for a particular timeline item.
|
/// Returns the frame of the cell for a particular timeline item.
|
||||||
private func cellFrame(for id: String) -> CGRect? {
|
private func cellFrame(for uniqueID: String) -> CGRect? {
|
||||||
guard let timelineCell = tableView.visibleCells.first(where: { ($0 as? TimelineItemCell)?.item?.id == id }) else {
|
guard let timelineCell = tableView.visibleCells.first(where: { ($0 as? TimelineItemCell)?.item?.identifier.uniqueID == uniqueID }) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -659,19 +659,19 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
if itemGroup.count == 1 {
|
if itemGroup.count == 1 {
|
||||||
if let firstItem = itemGroup.first {
|
if let firstItem = itemGroup.first {
|
||||||
timelineItemsDictionary.updateValue(updateViewState(item: firstItem, groupStyle: .single),
|
timelineItemsDictionary.updateValue(updateViewState(item: firstItem, groupStyle: .single),
|
||||||
forKey: firstItem.id.timelineID)
|
forKey: firstItem.id.uniqueID)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (index, item) in itemGroup.enumerated() {
|
for (index, item) in itemGroup.enumerated() {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
timelineItemsDictionary.updateValue(updateViewState(item: item, groupStyle: state.isPinnedEventsTimeline ? .single : .first),
|
timelineItemsDictionary.updateValue(updateViewState(item: item, groupStyle: state.isPinnedEventsTimeline ? .single : .first),
|
||||||
forKey: item.id.timelineID)
|
forKey: item.id.uniqueID)
|
||||||
} else if index == itemGroup.count - 1 {
|
} else if index == itemGroup.count - 1 {
|
||||||
timelineItemsDictionary.updateValue(updateViewState(item: item, groupStyle: state.isPinnedEventsTimeline ? .single : .last),
|
timelineItemsDictionary.updateValue(updateViewState(item: item, groupStyle: state.isPinnedEventsTimeline ? .single : .last),
|
||||||
forKey: item.id.timelineID)
|
forKey: item.id.uniqueID)
|
||||||
} else {
|
} else {
|
||||||
timelineItemsDictionary.updateValue(updateViewState(item: item, groupStyle: state.isPinnedEventsTimeline ? .single : .middle),
|
timelineItemsDictionary.updateValue(updateViewState(item: item, groupStyle: state.isPinnedEventsTimeline ? .single : .middle),
|
||||||
forKey: item.id.timelineID)
|
forKey: item.id.uniqueID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -685,7 +685,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateViewState(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) -> RoomTimelineItemViewState {
|
private func updateViewState(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) -> RoomTimelineItemViewState {
|
||||||
if let timelineItemViewState = state.timelineViewState.itemsDictionary[item.id.timelineID] {
|
if let timelineItemViewState = state.timelineViewState.itemsDictionary[item.id.uniqueID] {
|
||||||
timelineItemViewState.groupStyle = groupStyle
|
timelineItemViewState.groupStyle = groupStyle
|
||||||
timelineItemViewState.type = .init(item: item)
|
timelineItemViewState.type = .init(item: item)
|
||||||
return timelineItemViewState
|
return timelineItemViewState
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ struct SwipeToReplyView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SwipeToReplyView_Previews: PreviewProvider, TestablePreview {
|
struct SwipeToReplyView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let timelineItem = TextRoomTimelineItem(id: .init(timelineID: ""),
|
static let timelineItem = TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
// These always include a reply
|
// These always include a reply
|
||||||
static var threads: some View {
|
static var threads: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -401,7 +401,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
eventContent: .message(.text(.init(body: "Short"))))),
|
eventContent: .message(.text(.init(body: "Short"))))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
AudioRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
|
AudioRoomTimelineView(timelineItem: .init(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -417,7 +417,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
eventID: "123",
|
eventID: "123",
|
||||||
eventContent: .message(.text(.init(body: "Short"))))))
|
eventContent: .message(.text(.init(body: "Short"))))))
|
||||||
|
|
||||||
FileRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
|
FileRoomTimelineView(timelineItem: .init(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -431,7 +431,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
|
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
|
||||||
eventID: "123",
|
eventID: "123",
|
||||||
eventContent: .message(.text(.init(body: "Short"))))))
|
eventContent: .message(.text(.init(body: "Short"))))))
|
||||||
ImageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
|
ImageRoomTimelineView(timelineItem: .init(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -469,7 +469,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
eventID: "123",
|
eventID: "123",
|
||||||
eventContent: .message(.text(.init(body: "Short"))))))
|
eventContent: .message(.text(.init(body: "Short"))))))
|
||||||
|
|
||||||
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
|
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -505,7 +505,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
static var replies: some View {
|
static var replies: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -518,7 +518,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
eventContent: .message(.text(.init(body: "Short"))))),
|
eventContent: .message(.text(.init(body: "Short"))))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -536,7 +536,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
static var encryptionAuthenticity: some View {
|
static var encryptionAuthenticity: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -547,7 +547,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unsignedDevice(color: .red))),
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unsignedDevice(color: .red))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -559,7 +559,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
encryptionAuthenticity: .unsignedDevice(color: .red))),
|
encryptionAuthenticity: .unsignedDevice(color: .red))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -570,7 +570,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unknownDevice(color: .red))),
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unknownDevice(color: .red))),
|
||||||
groupStyle: .first))
|
groupStyle: .first))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -592,7 +592,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))))
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))))
|
||||||
|
|
||||||
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
|
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(uniqueID: ""),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -615,7 +615,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
static var pinned: some View {
|
static var pinned: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: "", eventID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -626,7 +626,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
replyDetails: nil),
|
replyDetails: nil),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
AudioRoomTimelineView(timelineItem: .init(id: .init(timelineID: "", eventID: ""),
|
AudioRoomTimelineView(timelineItem: .init(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -640,7 +640,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
contentType: nil),
|
contentType: nil),
|
||||||
replyDetails: nil))
|
replyDetails: nil))
|
||||||
|
|
||||||
FileRoomTimelineView(timelineItem: .init(id: .init(timelineID: "", eventID: ""),
|
FileRoomTimelineView(timelineItem: .init(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -652,7 +652,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
thumbnailSource: nil,
|
thumbnailSource: nil,
|
||||||
contentType: nil),
|
contentType: nil),
|
||||||
replyDetails: nil))
|
replyDetails: nil))
|
||||||
ImageRoomTimelineView(timelineItem: .init(id: .init(timelineID: "", eventID: ""),
|
ImageRoomTimelineView(timelineItem: .init(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -661,7 +661,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
sender: .init(id: ""),
|
sender: .init(id: ""),
|
||||||
content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil),
|
content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil),
|
||||||
replyDetails: nil))
|
replyDetails: nil))
|
||||||
LocationRoomTimelineView(timelineItem: .init(id: .init(timelineID: "", eventID: ""),
|
LocationRoomTimelineView(timelineItem: .init(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -673,7 +673,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
longitude: 12.496366),
|
longitude: 12.496366),
|
||||||
description: "Location description description description description description description description description"),
|
description: "Location description description description description description description description description"),
|
||||||
replyDetails: nil))
|
replyDetails: nil))
|
||||||
LocationRoomTimelineView(timelineItem: .init(id: .init(timelineID: "", eventID: ""),
|
LocationRoomTimelineView(timelineItem: .init(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -684,7 +684,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: nil),
|
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: nil),
|
||||||
replyDetails: nil))
|
replyDetails: nil))
|
||||||
|
|
||||||
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(timelineID: "", eventID: ""),
|
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "")),
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
static let sendingLast: TextRoomTimelineItem = {
|
static let sendingLast: TextRoomTimelineItem = {
|
||||||
let id = viewModel.state.timelineViewState.timelineIDs.last ?? UUID().uuidString
|
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
|
||||||
var result = TextRoomTimelineItem(id: .init(timelineID: id),
|
var result = TextRoomTimelineItem(id: .init(uniqueID: id),
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -99,8 +99,8 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
static let sentLast: TextRoomTimelineItem = {
|
static let sentLast: TextRoomTimelineItem = {
|
||||||
let id = viewModel.state.timelineViewState.timelineIDs.last ?? UUID().uuidString
|
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
|
||||||
let result = TextRoomTimelineItem(id: .init(timelineID: id),
|
let result = TextRoomTimelineItem(id: .init(uniqueID: id),
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct TimelineItemStatusView: View {
|
|||||||
@EnvironmentObject private var context: TimelineViewModel.Context
|
@EnvironmentObject private var context: TimelineViewModel.Context
|
||||||
|
|
||||||
private var isLastOutgoingMessage: Bool {
|
private var isLastOutgoingMessage: Bool {
|
||||||
timelineItem.isOutgoing && context.viewState.timelineViewState.timelineIDs.last == timelineItem.id.timelineID
|
timelineItem.isOutgoing && context.viewState.timelineViewState.uniqueIDs.last == timelineItem.id.uniqueID
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|||||||
@@ -196,20 +196,20 @@ struct TimelineReactionViewPreviewsContainer: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(timelineID: "1"),
|
itemID: .init(uniqueID: "1"),
|
||||||
reactions: [AggregatedReaction.mockReactionWithLongText,
|
reactions: [AggregatedReaction.mockReactionWithLongText,
|
||||||
AggregatedReaction.mockReactionWithLongTextRTL])
|
AggregatedReaction.mockReactionWithLongTextRTL])
|
||||||
Divider()
|
Divider()
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(timelineID: "2"),
|
itemID: .init(uniqueID: "2"),
|
||||||
reactions: Array(AggregatedReaction.mockReactions.prefix(3)))
|
reactions: Array(AggregatedReaction.mockReactions.prefix(3)))
|
||||||
Divider()
|
Divider()
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(timelineID: "3"),
|
itemID: .init(uniqueID: "3"),
|
||||||
reactions: AggregatedReaction.mockReactions)
|
reactions: AggregatedReaction.mockReactions)
|
||||||
Divider()
|
Divider()
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(timelineID: "4"),
|
itemID: .init(uniqueID: "4"),
|
||||||
reactions: AggregatedReaction.mockReactions,
|
reactions: AggregatedReaction.mockReactions,
|
||||||
isLayoutRTL: true)
|
isLayoutRTL: true)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -52,8 +52,8 @@ struct CollapsibleRoomTimelineView: View {
|
|||||||
|
|
||||||
struct CollapsibleRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct CollapsibleRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let item = CollapsibleTimelineItem(items: [
|
static let item = CollapsibleTimelineItem(items: [
|
||||||
SeparatorRoomTimelineItem(id: .init(timelineID: "First separator"), text: "This is a separator"),
|
SeparatorRoomTimelineItem(id: .init(uniqueID: "First separator"), text: "This is a separator"),
|
||||||
SeparatorRoomTimelineItem(id: .init(timelineID: "Second separator"), text: "This is another separator")
|
SeparatorRoomTimelineItem(id: .init(uniqueID: "Second separator"), text: "This is another separator")
|
||||||
])
|
])
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
|||||||
+5
-5
@@ -29,12 +29,12 @@ struct ReadMarkerRoomTimelineView: View {
|
|||||||
struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = TimelineViewModel.mock
|
static let viewModel = TimelineViewModel.mock
|
||||||
|
|
||||||
static let item = ReadMarkerRoomTimelineItem(id: .init(timelineID: .init(UUID().uuidString)))
|
static let item = ReadMarkerRoomTimelineItem(id: .init(uniqueID: .init(UUID().uuidString)))
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .init(timelineID: "Separator"), text: "Today")), groupStyle: .single))
|
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .init(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
|
||||||
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .random,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -45,8 +45,8 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
ReadMarkerRoomTimelineView(timelineItem: item)
|
ReadMarkerRoomTimelineView(timelineItem: item)
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .init(timelineID: "Separator"), text: "Today")), groupStyle: .single))
|
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .init(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
|
||||||
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .init(timelineID: ""),
|
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .random,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ struct SeparatorRoomTimelineView: View {
|
|||||||
|
|
||||||
struct SeparatorRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct SeparatorRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let item = SeparatorRoomTimelineItem(id: .init(timelineID: "Separator"), text: "This is a separator")
|
let item = SeparatorRoomTimelineItem(id: .init(uniqueID: "Separator"), text: "This is a separator")
|
||||||
SeparatorRoomTimelineView(timelineItem: item)
|
SeparatorRoomTimelineView(timelineItem: item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ struct OIDCAuthorizationDataProxy: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension OidcAuthorizationData: Equatable {
|
extension OidcAuthorizationData: @retroactive Equatable {
|
||||||
public static func == (lhs: MatrixRustSDK.OidcAuthorizationData, rhs: MatrixRustSDK.OidcAuthorizationData) -> Bool {
|
public static func == (lhs: MatrixRustSDK.OidcAuthorizationData, rhs: MatrixRustSDK.OidcAuthorizationData) -> Bool {
|
||||||
lhs.loginUrl() == rhs.loginUrl()
|
lhs.loginUrl() == rhs.loginUrl()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct RoomEventStringBuilder {
|
|||||||
sender.displayName ?? sender.id
|
sender.displayName ?? sender.id
|
||||||
}
|
}
|
||||||
|
|
||||||
switch eventItemProxy.content.kind() {
|
switch eventItemProxy.content {
|
||||||
case .unableToDecrypt(let encryptedMessage):
|
case .unableToDecrypt(let encryptedMessage):
|
||||||
let errorMessage = switch encryptedMessage {
|
let errorMessage = switch encryptedMessage {
|
||||||
case .megolmV1AesSha2(_, .membership): L10n.commonUnableToDecryptNoAccess
|
case .megolmV1AesSha2(_, .membership): L10n.commonUnableToDecryptNoAccess
|
||||||
@@ -41,13 +41,8 @@ struct RoomEventStringBuilder {
|
|||||||
return prefix(L10n.commonSticker, with: displayName)
|
return prefix(L10n.commonSticker, with: displayName)
|
||||||
case .failedToParseMessageLike, .failedToParseState:
|
case .failedToParseMessageLike, .failedToParseState:
|
||||||
return prefix(L10n.commonUnsupportedEvent, with: displayName)
|
return prefix(L10n.commonUnsupportedEvent, with: displayName)
|
||||||
case .message:
|
case .message(let messageContent):
|
||||||
guard let messageContent = eventItemProxy.content.asMessage() else {
|
return messageEventStringBuilder.buildAttributedString(for: messageContent.msgType, senderDisplayName: displayName)
|
||||||
fatalError("Invalid message timeline item: \(eventItemProxy)")
|
|
||||||
}
|
|
||||||
|
|
||||||
let messageType = messageContent.msgtype()
|
|
||||||
return messageEventStringBuilder.buildAttributedString(for: messageType, senderDisplayName: displayName)
|
|
||||||
case .state(_, let state):
|
case .state(_, let state):
|
||||||
return stateEventStringBuilder
|
return stateEventStringBuilder
|
||||||
.buildString(for: state, sender: sender, isOutgoing: isOutgoing)
|
.buildString(for: state, sender: sender, isOutgoing: isOutgoing)
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
var lastMessageFormattedTimestamp: String?
|
var lastMessageFormattedTimestamp: String?
|
||||||
|
|
||||||
if let latestRoomMessage = roomDetails.latestEvent {
|
if let latestRoomMessage = roomDetails.latestEvent {
|
||||||
let lastMessage = EventTimelineItemProxy(item: latestRoomMessage, id: "0")
|
let lastMessage = EventTimelineItemProxy(item: latestRoomMessage, uniqueID: "0")
|
||||||
lastMessageFormattedTimestamp = lastMessage.timestamp.formattedMinimal()
|
lastMessageFormattedTimestamp = lastMessage.timestamp.formattedMinimal()
|
||||||
attributedLastMessage = eventStringBuilder.buildAttributedString(for: lastMessage)
|
attributedLastMessage = eventStringBuilder.buildAttributedString(for: lastMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class SecureBackupController: SecureBackupControllerProtocol {
|
|||||||
MXLog.info("Enabling recovery")
|
MXLog.info("Enabling recovery")
|
||||||
|
|
||||||
var keyUploadErrored = false
|
var keyUploadErrored = false
|
||||||
let recoveryKey = try await encryption.enableRecovery(waitForBackupsToUpload: false, progressListener: SecureBackupEnableRecoveryProgressListener { [weak self] state in
|
let recoveryKey = try await encryption.enableRecovery(waitForBackupsToUpload: false, passphrase: nil, progressListener: SecureBackupEnableRecoveryProgressListener { [weak self] state in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import Foundation
|
|||||||
enum RoomTimelineItemFixtures {
|
enum RoomTimelineItemFixtures {
|
||||||
/// The default timeline items used in Xcode previews etc.
|
/// The default timeline items used in Xcode previews etc.
|
||||||
static var `default`: [RoomTimelineItemProtocol] = [
|
static var `default`: [RoomTimelineItemProtocol] = [
|
||||||
SeparatorRoomTimelineItem(id: .init(timelineID: "Yesterday"), text: "Yesterday"),
|
SeparatorRoomTimelineItem(id: .init(uniqueID: "Yesterday"), text: "Yesterday"),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: ".RoomTimelineItemFixtures.default.0",
|
TextRoomTimelineItem(id: .init(uniqueID: ".RoomTimelineItemFixtures.default.0",
|
||||||
eventID: "RoomTimelineItemFixtures.default.0"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.0")),
|
||||||
timestamp: "10:10 AM",
|
timestamp: "10:10 AM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -21,8 +21,8 @@ enum RoomTimelineItemFixtures {
|
|||||||
sender: .init(id: "", displayName: "Jacob"),
|
sender: .init(id: "", displayName: "Jacob"),
|
||||||
content: .init(body: "That looks so good!"),
|
content: .init(body: "That looks so good!"),
|
||||||
properties: RoomTimelineItemProperties(isEdited: true)),
|
properties: RoomTimelineItemProperties(isEdited: true)),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "RoomTimelineItemFixtures.default.1",
|
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.1",
|
||||||
eventID: "RoomTimelineItemFixtures.default.1"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.1")),
|
||||||
timestamp: "10:11 AM",
|
timestamp: "10:11 AM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -33,8 +33,8 @@ enum RoomTimelineItemFixtures {
|
|||||||
properties: RoomTimelineItemProperties(reactions: [
|
properties: RoomTimelineItemProperties(reactions: [
|
||||||
AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(id: "me", timestamp: Date())])
|
AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(id: "me", timestamp: Date())])
|
||||||
])),
|
])),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "RoomTimelineItemFixtures.default.2",
|
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.2",
|
||||||
eventID: "RoomTimelineItemFixtures.default.2"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.2")),
|
||||||
timestamp: "10:11 AM",
|
timestamp: "10:11 AM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -52,9 +52,9 @@ enum RoomTimelineItemFixtures {
|
|||||||
ReactionSender(id: "jacob", timestamp: Date())
|
ReactionSender(id: "jacob", timestamp: Date())
|
||||||
])
|
])
|
||||||
])),
|
])),
|
||||||
SeparatorRoomTimelineItem(id: .init(timelineID: "Today"), text: "Today"),
|
SeparatorRoomTimelineItem(id: .init(uniqueID: "Today"), text: "Today"),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "RoomTimelineItemFixtures.default.3",
|
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.3",
|
||||||
eventID: "RoomTimelineItemFixtures.default.3"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.3")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -63,8 +63,8 @@ enum RoomTimelineItemFixtures {
|
|||||||
sender: .init(id: "", displayName: "Helena"),
|
sender: .init(id: "", displayName: "Helena"),
|
||||||
content: .init(body: "Wow, cool. Ok, lets go the usual place tomorrow?! Is that too soon? Here’s the menu, let me know what you want it’s on me!"),
|
content: .init(body: "Wow, cool. Ok, lets go the usual place tomorrow?! Is that too soon? Here’s the menu, let me know what you want it’s on me!"),
|
||||||
properties: RoomTimelineItemProperties(orderedReadReceipts: [ReadReceipt(userID: "alice", formattedTimestamp: nil)])),
|
properties: RoomTimelineItemProperties(orderedReadReceipts: [ReadReceipt(userID: "alice", formattedTimestamp: nil)])),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "RoomTimelineItemFixtures.default.4",
|
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.4",
|
||||||
eventID: "RoomTimelineItemFixtures.default.4"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.4")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -72,8 +72,8 @@ enum RoomTimelineItemFixtures {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
sender: .init(id: "", displayName: "Bob"),
|
sender: .init(id: "", displayName: "Bob"),
|
||||||
content: .init(body: "And John's speech was amazing!")),
|
content: .init(body: "And John's speech was amazing!")),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "RoomTimelineItemFixtures.default.5",
|
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.5",
|
||||||
eventID: "RoomTimelineItemFixtures.default.5"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.5")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -86,8 +86,8 @@ enum RoomTimelineItemFixtures {
|
|||||||
ReadReceipt(userID: "bob", formattedTimestamp: nil),
|
ReadReceipt(userID: "bob", formattedTimestamp: nil),
|
||||||
ReadReceipt(userID: "charlie", formattedTimestamp: nil),
|
ReadReceipt(userID: "charlie", formattedTimestamp: nil),
|
||||||
ReadReceipt(userID: "dan", formattedTimestamp: nil)])),
|
ReadReceipt(userID: "dan", formattedTimestamp: nil)])),
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "RoomTimelineItemFixtures.default.6",
|
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.6",
|
||||||
eventID: "RoomTimelineItemFixtures.default.6"),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.6")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -242,7 +242,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
|
|
||||||
static var permalinkChunk: [RoomTimelineItemProtocol] {
|
static var permalinkChunk: [RoomTimelineItemProtocol] {
|
||||||
(1...20).map { index in
|
(1...20).map { index in
|
||||||
TextRoomTimelineItem(id: .init(timelineID: "\(index)", eventID: "$\(index)"),
|
TextRoomTimelineItem(id: .init(uniqueID: "\(index)", eventOrTransactionID: .eventId(eventId: "$\(index)")),
|
||||||
text: "Message ID \(index)",
|
text: "Message ID \(index)",
|
||||||
senderDisplayName: index > 10 ? "Alice" : "Bob")
|
senderDisplayName: index > 10 ? "Alice" : "Bob")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,38 +184,11 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension TimelineItem {
|
|
||||||
var debugIdentifier: DebugIdentifier {
|
|
||||||
if let virtualTimelineItem = asVirtual() {
|
|
||||||
return .virtual(timelineID: String(uniqueId()), dscription: virtualTimelineItem.description)
|
|
||||||
} else if let eventTimelineItem = asEvent() {
|
|
||||||
return .event(timelineID: String(uniqueId()),
|
|
||||||
eventID: eventTimelineItem.eventId(),
|
|
||||||
transactionID: eventTimelineItem.transactionId())
|
|
||||||
}
|
|
||||||
|
|
||||||
return .unknown(timelineID: String(uniqueId()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension TimelineItemProxy {
|
private extension TimelineItemProxy {
|
||||||
var debugIdentifier: DebugIdentifier {
|
|
||||||
switch self {
|
|
||||||
case .event(let eventTimelineItem):
|
|
||||||
return .event(timelineID: eventTimelineItem.id.timelineID,
|
|
||||||
eventID: eventTimelineItem.id.eventID,
|
|
||||||
transactionID: eventTimelineItem.id.transactionID)
|
|
||||||
case .virtual(let virtualTimelineItem, let timelineID):
|
|
||||||
return .virtual(timelineID: timelineID, dscription: virtualTimelineItem.description)
|
|
||||||
case .unknown(let item):
|
|
||||||
return .unknown(timelineID: String(item.uniqueId()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isMembershipChange: Bool {
|
var isMembershipChange: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case .event(let eventTimelineItemProxy):
|
case .event(let eventTimelineItemProxy):
|
||||||
switch eventTimelineItemProxy.content.kind() {
|
switch eventTimelineItemProxy.content {
|
||||||
case .roomMembership:
|
case .roomMembership:
|
||||||
true
|
true
|
||||||
default:
|
default:
|
||||||
@@ -238,12 +211,6 @@ private extension VirtualTimelineItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DebugIdentifier {
|
|
||||||
case event(timelineID: String, eventID: String?, transactionID: String?)
|
|
||||||
case virtual(timelineID: String, dscription: String)
|
|
||||||
case unknown(timelineID: String)
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class RoomTimelineListener: TimelineListener {
|
private final class RoomTimelineListener: TimelineListener {
|
||||||
private let onUpdateClosure: ([TimelineDiff]) -> Void
|
private let onUpdateClosure: ([TimelineDiff]) -> Void
|
||||||
|
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
MXLog.info("Editing timeline item: \(timelineItemID)")
|
MXLog.info("Editing timeline item: \(timelineItemID)")
|
||||||
|
|
||||||
let editMode: EditMode
|
let editMode: EditMode
|
||||||
if !timelineItemID.timelineID.isEmpty,
|
if !timelineItemID.uniqueID.isEmpty,
|
||||||
let timelineItem = liveTimelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID) {
|
let timelineItem = liveTimelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID) {
|
||||||
editMode = .byEvent(timelineItem)
|
editMode = .byEvent(timelineItem)
|
||||||
} else if let eventID = timelineItemID.eventID {
|
} else if let eventID = timelineItemID.eventID {
|
||||||
@@ -392,15 +392,15 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return timelineItem
|
return timelineItem
|
||||||
case .virtual(let virtualItem, let timelineID):
|
case .virtual(let virtualItem, let uniqueID):
|
||||||
switch virtualItem {
|
switch virtualItem {
|
||||||
case .dayDivider(let timestamp):
|
case .dayDivider(let timestamp):
|
||||||
let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000))
|
let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000))
|
||||||
let dateString = date.formatted(date: .complete, time: .omitted)
|
let dateString = date.formatted(date: .complete, time: .omitted)
|
||||||
|
|
||||||
return SeparatorRoomTimelineItem(id: .init(timelineID: dateString), text: dateString)
|
return SeparatorRoomTimelineItem(id: .init(uniqueID: dateString), text: dateString)
|
||||||
case .readMarker:
|
case .readMarker:
|
||||||
return ReadMarkerRoomTimelineItem(id: .init(timelineID: timelineID))
|
return ReadMarkerRoomTimelineItem(id: .init(uniqueID: uniqueID))
|
||||||
}
|
}
|
||||||
case .unknown:
|
case .unknown:
|
||||||
return nil
|
return nil
|
||||||
@@ -409,7 +409,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
|
|
||||||
private func isItemCollapsible(_ item: TimelineItemProxy) -> Bool {
|
private func isItemCollapsible(_ item: TimelineItemProxy) -> Bool {
|
||||||
if case let .event(eventItem) = item {
|
if case let .event(eventItem) = item {
|
||||||
switch eventItem.content.kind() {
|
switch eventItem.content {
|
||||||
case .profileChange, .roomMembership, .state:
|
case .profileChange, .roomMembership, .state:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
|
|||||||
+7
-7
@@ -9,43 +9,43 @@ import MatrixRustSDK
|
|||||||
|
|
||||||
// MARK: Redact message content from logs
|
// MARK: Redact message content from logs
|
||||||
|
|
||||||
extension EmoteMessageContent: CustomStringConvertible {
|
extension EmoteMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileMessageContent: CustomStringConvertible {
|
extension FileMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ImageMessageContent: CustomStringConvertible {
|
extension ImageMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NoticeMessageContent: CustomStringConvertible {
|
extension NoticeMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextMessageContent: CustomStringConvertible {
|
extension TextMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VideoMessageContent: CustomStringConvertible {
|
extension VideoMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AudioMessageContent: CustomStringConvertible {
|
extension AudioMessageContent: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
String(describing: Self.self)
|
String(describing: Self.self)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,35 +11,48 @@ import MatrixRustSDK
|
|||||||
struct TimelineItemIdentifier: Hashable {
|
struct TimelineItemIdentifier: Hashable {
|
||||||
/// Stable id across state changes of the timeline item, it uniquely identifies an item in a timeline.
|
/// Stable id across state changes of the timeline item, it uniquely identifies an item in a timeline.
|
||||||
/// It's value is consistent only per timeline instance, it should **not** be used to identify an item across timeline instances.
|
/// It's value is consistent only per timeline instance, it should **not** be used to identify an item across timeline instances.
|
||||||
let timelineID: String
|
let uniqueID: String
|
||||||
|
|
||||||
/// Uniquely identifies the timeline item from the server side.
|
/// Contains the 2 possible identifiers of an event, either it has a remote event id or a local transaction id, never both or none.
|
||||||
/// Only available for EventTimelineItem and only when the item is returned by the server.
|
var eventOrTransactionID: EventOrTransactionId?
|
||||||
var eventID: String?
|
|
||||||
|
var eventID: String? {
|
||||||
/// Uniquely identifies the local echo of the timeline item.
|
switch eventOrTransactionID {
|
||||||
/// Only available for sent EventTimelineItem that have not been returned by the server yet.
|
case .eventId(let eventId):
|
||||||
var transactionID: String?
|
return eventId
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var transactionID: String? {
|
||||||
|
switch eventOrTransactionID {
|
||||||
|
case .transactionId(let transactionId):
|
||||||
|
return transactionId
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TimelineItemIdentifier {
|
extension TimelineItemIdentifier {
|
||||||
/// Use only for mocks/tests
|
/// Use only for mocks/tests
|
||||||
static var random: Self {
|
static var random: Self {
|
||||||
.init(timelineID: UUID().uuidString, eventID: UUID().uuidString)
|
.init(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: UUID().uuidString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A light wrapper around timeline items returned from Rust.
|
/// A light wrapper around timeline items returned from Rust.
|
||||||
enum TimelineItemProxy {
|
enum TimelineItemProxy {
|
||||||
case event(EventTimelineItemProxy)
|
case event(EventTimelineItemProxy)
|
||||||
case virtual(MatrixRustSDK.VirtualTimelineItem, timelineID: String)
|
case virtual(MatrixRustSDK.VirtualTimelineItem, uniqueID: String)
|
||||||
case unknown(MatrixRustSDK.TimelineItem)
|
case unknown(MatrixRustSDK.TimelineItem)
|
||||||
|
|
||||||
init(item: MatrixRustSDK.TimelineItem) {
|
init(item: MatrixRustSDK.TimelineItem) {
|
||||||
if let eventItem = item.asEvent() {
|
if let eventItem = item.asEvent() {
|
||||||
self = .event(EventTimelineItemProxy(item: eventItem, id: String(item.uniqueId())))
|
self = .event(EventTimelineItemProxy(item: eventItem, uniqueID: String(item.uniqueId())))
|
||||||
} else if let virtualItem = item.asVirtual() {
|
} else if let virtualItem = item.asVirtual() {
|
||||||
self = .virtual(virtualItem, timelineID: String(item.uniqueId()))
|
self = .virtual(virtualItem, uniqueID: String(item.uniqueId()))
|
||||||
} else {
|
} else {
|
||||||
self = .unknown(item)
|
self = .unknown(item)
|
||||||
}
|
}
|
||||||
@@ -92,13 +105,14 @@ class EventTimelineItemProxy {
|
|||||||
let item: MatrixRustSDK.EventTimelineItem
|
let item: MatrixRustSDK.EventTimelineItem
|
||||||
let id: TimelineItemIdentifier
|
let id: TimelineItemIdentifier
|
||||||
|
|
||||||
init(item: MatrixRustSDK.EventTimelineItem, id: String) {
|
init(item: MatrixRustSDK.EventTimelineItem, uniqueID: String) {
|
||||||
self.item = item
|
self.item = item
|
||||||
self.id = TimelineItemIdentifier(timelineID: id, eventID: item.eventId(), transactionID: item.transactionId())
|
|
||||||
|
id = TimelineItemIdentifier(uniqueID: uniqueID, eventOrTransactionID: item.eventOrTransactionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var deliveryStatus: TimelineItemDeliveryStatus? = {
|
lazy var deliveryStatus: TimelineItemDeliveryStatus? = {
|
||||||
guard let localSendState = item.localSendState() else {
|
guard let localSendState = item.localSendState else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,43 +132,43 @@ class EventTimelineItemProxy {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var canBeRepliedTo = item.canBeRepliedTo()
|
lazy var canBeRepliedTo = item.canBeRepliedTo
|
||||||
|
|
||||||
lazy var content = item.content()
|
lazy var content = item.content
|
||||||
|
|
||||||
lazy var isOwn = item.isOwn()
|
lazy var isOwn = item.isOwn
|
||||||
|
|
||||||
lazy var isEditable = item.isEditable()
|
lazy var isEditable = item.isEditable
|
||||||
|
|
||||||
lazy var sender: TimelineItemSender = {
|
lazy var sender: TimelineItemSender = {
|
||||||
let profile = item.senderProfile()
|
let profile = item.senderProfile
|
||||||
|
|
||||||
switch profile {
|
switch profile {
|
||||||
case let .ready(displayName, isDisplayNameAmbiguous, avatarUrl):
|
case let .ready(displayName, isDisplayNameAmbiguous, avatarUrl):
|
||||||
return .init(id: item.sender(),
|
return .init(id: item.sender,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
isDisplayNameAmbiguous: isDisplayNameAmbiguous,
|
isDisplayNameAmbiguous: isDisplayNameAmbiguous,
|
||||||
avatarURL: avatarUrl.flatMap(URL.init(string:)))
|
avatarURL: avatarUrl.flatMap(URL.init(string:)))
|
||||||
default:
|
default:
|
||||||
return .init(id: item.sender(),
|
return .init(id: item.sender,
|
||||||
displayName: nil,
|
displayName: nil,
|
||||||
isDisplayNameAmbiguous: false,
|
isDisplayNameAmbiguous: false,
|
||||||
avatarURL: nil)
|
avatarURL: nil)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var reactions = item.reactions()
|
lazy var reactions = item.reactions
|
||||||
|
|
||||||
lazy var timestamp = Date(timeIntervalSince1970: TimeInterval(item.timestamp() / 1000))
|
lazy var timestamp = Date(timeIntervalSince1970: TimeInterval(item.timestamp / 1000))
|
||||||
|
|
||||||
lazy var debugInfo: TimelineItemDebugInfo = {
|
lazy var debugInfo: TimelineItemDebugInfo = {
|
||||||
let debugInfo = item.debugInfo()
|
let debugInfo = item.debugInfoProvider.get()
|
||||||
return TimelineItemDebugInfo(model: debugInfo.model, originalJSON: debugInfo.originalJson, latestEditJSON: debugInfo.latestEditJson)
|
return TimelineItemDebugInfo(model: debugInfo.model, originalJSON: debugInfo.originalJson, latestEditJSON: debugInfo.latestEditJson)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var shieldState = item.getShield(strict: false)
|
lazy var shieldState = item.shieldsProvider.getShields(strict: false)
|
||||||
|
|
||||||
lazy var readReceipts = item.readReceipts()
|
lazy var readReceipts = item.readReceipts
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TimelineItemDebugInfo: Identifiable, CustomStringConvertible {
|
struct TimelineItemDebugInfo: Identifiable, CustomStringConvertible {
|
||||||
|
|||||||
+1
-1
@@ -22,6 +22,6 @@ struct PaginationIndicatorRoomTimelineItem: DecorationTimelineItemProtocol, Equa
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(position: Position) {
|
init(position: Position) {
|
||||||
id = TimelineItemIdentifier(timelineID: position.id)
|
id = TimelineItemIdentifier(uniqueID: position.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,6 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
||||||
let id = TimelineItemIdentifier(timelineID: UUID().uuidString)
|
let id = TimelineItemIdentifier(uniqueID: UUID().uuidString)
|
||||||
let name: String?
|
let name: String?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
func buildTimelineItem(for eventItemProxy: EventTimelineItemProxy, isDM: Bool) -> RoomTimelineItemProtocol? {
|
func buildTimelineItem(for eventItemProxy: EventTimelineItemProxy, isDM: Bool) -> RoomTimelineItemProtocol? {
|
||||||
let isOutgoing = eventItemProxy.isOwn
|
let isOutgoing = eventItemProxy.isOwn
|
||||||
|
|
||||||
switch eventItemProxy.content.kind() {
|
switch eventItemProxy.content {
|
||||||
case .unableToDecrypt(let encryptedMessage):
|
case .unableToDecrypt(let encryptedMessage):
|
||||||
return buildEncryptedTimelineItem(eventItemProxy, encryptedMessage, isOutgoing)
|
return buildEncryptedTimelineItem(eventItemProxy, encryptedMessage, isOutgoing)
|
||||||
case .redactedMessage:
|
case .redactedMessage:
|
||||||
@@ -43,8 +43,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
return buildUnsupportedTimelineItem(eventItemProxy, eventType, error, isOutgoing)
|
return buildUnsupportedTimelineItem(eventItemProxy, eventType, error, isOutgoing)
|
||||||
case .failedToParseState(let eventType, _, let error):
|
case .failedToParseState(let eventType, _, let error):
|
||||||
return buildUnsupportedTimelineItem(eventItemProxy, eventType, error, isOutgoing)
|
return buildUnsupportedTimelineItem(eventItemProxy, eventType, error, isOutgoing)
|
||||||
case .message:
|
case .message(let messageContent):
|
||||||
return buildMessageTimelineItem(eventItemProxy, isOutgoing)
|
return buildMessageTimelineItem(eventItemProxy, messageContent, isOutgoing)
|
||||||
case .state(_, let content):
|
case .state(_, let content):
|
||||||
if isDM, content == .roomCreate {
|
if isDM, content == .roomCreate {
|
||||||
return nil
|
return nil
|
||||||
@@ -72,34 +72,29 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Message Events
|
// MARK: - Message Events
|
||||||
|
|
||||||
private func buildMessageTimelineItem(_ eventItemProxy: EventTimelineItemProxy, _ isOutgoing: Bool) -> RoomTimelineItemProtocol? {
|
private func buildMessageTimelineItem(_ eventItemProxy: EventTimelineItemProxy, _ messageContent: MessageContent, _ isOutgoing: Bool) -> RoomTimelineItemProtocol? {
|
||||||
guard let messageTimelineItem = eventItemProxy.content.asMessage() else {
|
switch messageContent.msgType {
|
||||||
fatalError("Invalid message timeline item: \(eventItemProxy)")
|
case .text(content: let textMessageContent):
|
||||||
}
|
return buildTextTimelineItem(for: eventItemProxy, messageContent, textMessageContent, isOutgoing)
|
||||||
|
case .image(content: let imageMessageContent):
|
||||||
let isThreaded = messageTimelineItem.isThreaded()
|
return buildImageTimelineItem(for: eventItemProxy, messageContent, imageMessageContent, isOutgoing)
|
||||||
switch messageTimelineItem.msgtype() {
|
case .video(let videoMessageContent):
|
||||||
case .text(content: let content):
|
return buildVideoTimelineItem(for: eventItemProxy, messageContent, videoMessageContent, isOutgoing)
|
||||||
return buildTextTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
case .file(let fileMessageContent):
|
||||||
case .image(content: let content):
|
return buildFileTimelineItem(for: eventItemProxy, messageContent, fileMessageContent, isOutgoing)
|
||||||
return buildImageTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
case .notice(content: let noticeMessageContent):
|
||||||
case .video(let content):
|
return buildNoticeTimelineItem(for: eventItemProxy, messageContent, noticeMessageContent, isOutgoing)
|
||||||
return buildVideoTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
case .emote(content: let emoteMessageContent):
|
||||||
case .file(let content):
|
return buildEmoteTimelineItem(for: eventItemProxy, messageContent, emoteMessageContent, isOutgoing)
|
||||||
return buildFileTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
case .audio(let audioMessageContent):
|
||||||
case .notice(content: let content):
|
if audioMessageContent.voice != nil {
|
||||||
return buildNoticeTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
return buildVoiceTimelineItem(for: eventItemProxy, messageContent, audioMessageContent, isOutgoing)
|
||||||
case .emote(content: let content):
|
|
||||||
return buildEmoteTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
|
||||||
case .audio(let content):
|
|
||||||
if content.voice != nil {
|
|
||||||
return buildVoiceTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
|
||||||
} else {
|
} else {
|
||||||
return buildAudioTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
return buildAudioTimelineItem(for: eventItemProxy, messageContent, audioMessageContent, isOutgoing)
|
||||||
}
|
}
|
||||||
case .location(let content):
|
case .location(let locationMessageContent):
|
||||||
return buildLocationTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
return buildLocationTimelineItem(for: eventItemProxy, messageContent, locationMessageContent, isOutgoing)
|
||||||
case .other:
|
case .other:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -196,20 +191,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildTextTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildTextTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: TextMessageContent,
|
_ textMessageContent: TextMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
TextRoomTimelineItem(id: eventItemProxy.id,
|
TextRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildTextTimelineItemContent(messageContent),
|
content: buildTextTimelineItemContent(textMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -217,20 +211,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildImageTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildImageTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: ImageMessageContent,
|
_ imageMessageContent: ImageMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
ImageRoomTimelineItem(id: eventItemProxy.id,
|
ImageRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildImageTimelineItemContent(messageContent),
|
content: buildImageTimelineItemContent(imageMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -238,20 +231,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildVideoTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildVideoTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: VideoMessageContent,
|
_ videoMessageContent: VideoMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
VideoRoomTimelineItem(id: eventItemProxy.id,
|
VideoRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildVideoTimelineItemContent(messageContent),
|
content: buildVideoTimelineItemContent(videoMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -259,20 +251,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildAudioTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildAudioTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: AudioMessageContent,
|
_ audioMessageContent: AudioMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
AudioRoomTimelineItem(id: eventItemProxy.id,
|
AudioRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildAudioTimelineItemContent(messageContent),
|
content: buildAudioTimelineItemContent(audioMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -280,20 +271,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildVoiceTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildVoiceTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: AudioMessageContent,
|
_ audioMessageContent: AudioMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
VoiceMessageRoomTimelineItem(id: eventItemProxy.id,
|
VoiceMessageRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildAudioTimelineItemContent(messageContent),
|
content: buildAudioTimelineItemContent(audioMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -301,20 +291,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildFileTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildFileTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: FileMessageContent,
|
_ fileMessageContent: FileMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
FileRoomTimelineItem(id: eventItemProxy.id,
|
FileRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildFileTimelineItemContent(messageContent),
|
content: buildFileTimelineItemContent(fileMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -322,20 +311,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildNoticeTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildNoticeTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: NoticeMessageContent,
|
_ noticeMessageContent: NoticeMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
NoticeRoomTimelineItem(id: eventItemProxy.id,
|
NoticeRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildNoticeTimelineItemContent(messageContent),
|
content: buildNoticeTimelineItemContent(noticeMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -343,20 +331,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildEmoteTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildEmoteTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: EmoteMessageContent,
|
_ emoteMessageContent: EmoteMessageContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
EmoteRoomTimelineItem(id: eventItemProxy.id,
|
EmoteRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildEmoteTimelineItemContent(senderDisplayName: eventItemProxy.sender.displayName, senderID: eventItemProxy.sender.id, messageContent: messageContent),
|
content: buildEmoteTimelineItemContent(senderDisplayName: eventItemProxy.sender.displayName, senderID: eventItemProxy.sender.id, messageContent: emoteMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -364,20 +351,19 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func buildLocationTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
private func buildLocationTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||||
_ messageTimelineItem: Message,
|
_ messageContent: MessageContent,
|
||||||
_ messageContent: LocationContent,
|
_ locationMessageContent: LocationContent,
|
||||||
_ isOutgoing: Bool,
|
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
|
||||||
LocationRoomTimelineItem(id: eventItemProxy.id,
|
LocationRoomTimelineItem(id: eventItemProxy.id,
|
||||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: eventItemProxy.isEditable,
|
isEditable: eventItemProxy.isEditable,
|
||||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||||
isThreaded: isThreaded,
|
isThreaded: messageContent.threadRoot != nil,
|
||||||
sender: eventItemProxy.sender,
|
sender: eventItemProxy.sender,
|
||||||
content: buildLocationTimelineItemContent(messageContent),
|
content: buildLocationTimelineItemContent(locationMessageContent),
|
||||||
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageTimelineItem.inReplyTo()),
|
replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo),
|
||||||
properties: RoomTimelineItemProperties(isEdited: messageTimelineItem.isEdited(),
|
properties: RoomTimelineItemProperties(isEdited: messageContent.isEdited,
|
||||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts),
|
||||||
@@ -652,12 +638,12 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
// MARK: - Reply details
|
// MARK: - Reply details
|
||||||
|
|
||||||
func buildReply(details: InReplyToDetails) -> TimelineItemReply {
|
func buildReply(details: InReplyToDetails) -> TimelineItemReply {
|
||||||
let isThreaded = details.event.isThreaded
|
let isThreaded = details.event().isThreaded
|
||||||
switch details.event {
|
switch details.event() {
|
||||||
case .unavailable:
|
case .unavailable:
|
||||||
return .init(details: .notLoaded(eventID: details.eventId), isThreaded: isThreaded)
|
return .init(details: .notLoaded(eventID: details.eventId()), isThreaded: isThreaded)
|
||||||
case .pending:
|
case .pending:
|
||||||
return .init(details: .loading(eventID: details.eventId), isThreaded: isThreaded)
|
return .init(details: .loading(eventID: details.eventId()), isThreaded: isThreaded)
|
||||||
case let .ready(timelineItem, senderID, senderProfile):
|
case let .ready(timelineItem, senderID, senderProfile):
|
||||||
let sender: TimelineItemSender
|
let sender: TimelineItemSender
|
||||||
switch senderProfile {
|
switch senderProfile {
|
||||||
@@ -675,9 +661,9 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
|
|
||||||
let replyContent: TimelineEventContent
|
let replyContent: TimelineEventContent
|
||||||
|
|
||||||
switch timelineItem.kind() {
|
switch timelineItem {
|
||||||
case .message:
|
case .message(let messageContent):
|
||||||
return .init(details: timelineItemReplyDetails(sender: sender, eventID: details.eventId, messageType: timelineItem.asMessage()?.msgtype()), isThreaded: isThreaded)
|
return .init(details: timelineItemReplyDetails(sender: sender, eventID: details.eventId(), messageType: messageContent.msgType), isThreaded: isThreaded)
|
||||||
case .poll(let question, _, _, _, _, _, _):
|
case .poll(let question, _, _, _, _, _, _):
|
||||||
replyContent = .poll(question: question)
|
replyContent = .poll(question: question)
|
||||||
case .sticker(let body, _, _):
|
case .sticker(let body, _, _):
|
||||||
@@ -688,9 +674,9 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
|||||||
replyContent = .message(.text(.init(body: L10n.commonUnsupportedEvent)))
|
replyContent = .message(.text(.init(body: L10n.commonUnsupportedEvent)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return .init(details: .loaded(sender: sender, eventID: details.eventId, eventContent: replyContent), isThreaded: isThreaded)
|
return .init(details: .loaded(sender: sender, eventID: details.eventId(), eventContent: replyContent), isThreaded: isThreaded)
|
||||||
case let .error(message):
|
case let .error(message):
|
||||||
return .init(details: .error(eventID: details.eventId, message: message), isThreaded: isThreaded)
|
return .init(details: .error(eventID: details.eventId(), message: message), isThreaded: isThreaded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,7 +737,11 @@ private extension RepliedToEventDetails {
|
|||||||
var isThreaded: Bool {
|
var isThreaded: Bool {
|
||||||
switch self {
|
switch self {
|
||||||
case .ready(let content, _, _):
|
case .ready(let content, _, _):
|
||||||
return content.asMessage()?.isThreaded() ?? false
|
guard case let .message(content) = content else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.threadRoot != nil
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,23 +8,14 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class RoomTimelineItemViewState: Identifiable, Equatable, ObservableObject {
|
final class RoomTimelineItemViewState: Identifiable, Equatable, ObservableObject {
|
||||||
static func == (lhs: RoomTimelineItemViewState, rhs: RoomTimelineItemViewState) -> Bool {
|
|
||||||
lhs.type == rhs.type && lhs.groupStyle == rhs.groupStyle
|
|
||||||
}
|
|
||||||
|
|
||||||
@Published var type: RoomTimelineItemType
|
@Published var type: RoomTimelineItemType
|
||||||
@Published var groupStyle: TimelineGroupStyle
|
@Published var groupStyle: TimelineGroupStyle
|
||||||
|
|
||||||
/// Contains all the identification info of the item, `timelineID`, `eventID` and `transactionID`
|
/// Contains all the identification info of the item, `uniqueID`, `eventID` and `transactionID`
|
||||||
var identifier: TimelineItemIdentifier {
|
var identifier: TimelineItemIdentifier {
|
||||||
type.id
|
type.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `timelineID` of the item, used for the timeline view level identification, do not use for any business logic use `identifier` instead
|
|
||||||
var id: String {
|
|
||||||
identifier.timelineID
|
|
||||||
}
|
|
||||||
|
|
||||||
init(type: RoomTimelineItemType, groupStyle: TimelineGroupStyle) {
|
init(type: RoomTimelineItemType, groupStyle: TimelineGroupStyle) {
|
||||||
self.type = type
|
self.type = type
|
||||||
self.groupStyle = groupStyle
|
self.groupStyle = groupStyle
|
||||||
@@ -33,6 +24,19 @@ final class RoomTimelineItemViewState: Identifiable, Equatable, ObservableObject
|
|||||||
convenience init(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) {
|
convenience init(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) {
|
||||||
self.init(type: .init(item: item), groupStyle: groupStyle)
|
self.init(type: .init(item: item), groupStyle: groupStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Equatable
|
||||||
|
|
||||||
|
static func == (lhs: RoomTimelineItemViewState, rhs: RoomTimelineItemViewState) -> Bool {
|
||||||
|
lhs.type == rhs.type && lhs.groupStyle == rhs.groupStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Identifiable
|
||||||
|
|
||||||
|
/// The `timelineID` of the item, used for the timeline view level identification, do not use for any business logic use `identifier` instead
|
||||||
|
var id: String {
|
||||||
|
identifier.uniqueID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RoomTimelineItemType: Equatable {
|
enum RoomTimelineItemType: Equatable {
|
||||||
|
|||||||
@@ -72,7 +72,17 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func messageEventContent(for timelineItemID: TimelineItemIdentifier) async -> RoomMessageEventContentWithoutRelation? {
|
func messageEventContent(for timelineItemID: TimelineItemIdentifier) async -> RoomMessageEventContentWithoutRelation? {
|
||||||
await timelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID)?.content().asMessage()?.content()
|
guard let content = await timelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID)?.content,
|
||||||
|
case let .message(messageContent) = content else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
return try contentWithoutRelationFromMessage(message: messageContent)
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed retrieving message event content for timelineItemID=\(timelineItemID)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func paginateBackwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError> {
|
func paginateBackwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError> {
|
||||||
@@ -156,15 +166,15 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
|
|
||||||
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
||||||
do {
|
do {
|
||||||
guard try await timeline.edit(item: timelineItem, newContent: .roomMessage(content: newContent)) == true else {
|
guard try await timeline.edit(eventOrTransactionId: timelineItem.eventOrTransactionId, newContent: .roomMessage(content: newContent)) == true else {
|
||||||
return .failure(.failedEditing)
|
return .failure(.failedEditing)
|
||||||
}
|
}
|
||||||
|
|
||||||
MXLog.info("Finished editing timeline item: \(timelineItem.eventId() ?? timelineItem.transactionId() ?? "unknown")")
|
MXLog.info("Finished editing timeline item: \(timelineItem.eventOrTransactionId)")
|
||||||
|
|
||||||
return .success(())
|
return .success(())
|
||||||
} catch {
|
} catch {
|
||||||
MXLog.error("Failed editing timeline item: \(timelineItem.eventId() ?? timelineItem.transactionId() ?? "unknown") with error: \(error)")
|
MXLog.error("Failed editing timeline item: \(timelineItem.eventOrTransactionId) with error: \(error)")
|
||||||
return .failure(.sdkError(error))
|
return .failure(.sdkError(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,18 +182,13 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
func redact(_ timelineItemID: TimelineItemIdentifier, reason: String?) async -> Result<Void, TimelineProxyError> {
|
func redact(_ timelineItemID: TimelineItemIdentifier, reason: String?) async -> Result<Void, TimelineProxyError> {
|
||||||
MXLog.info("Redacting timeline item: \(timelineItemID)")
|
MXLog.info("Redacting timeline item: \(timelineItemID)")
|
||||||
|
|
||||||
guard let eventTimelineItem = await timelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID) else {
|
guard let eventOrTransactionID = await timelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID)?.eventOrTransactionId else {
|
||||||
MXLog.error("Unknown timeline item: \(timelineItemID)")
|
MXLog.error("Unknown timeline item: \(timelineItemID)")
|
||||||
return .failure(.failedRedacting)
|
return .failure(.failedRedacting)
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let success = try await timeline.redactEvent(item: eventTimelineItem, reason: reason)
|
try await timeline.redactEvent(eventOrTransactionId: eventOrTransactionID, reason: reason)
|
||||||
|
|
||||||
guard success else {
|
|
||||||
MXLog.error("Failed redacting timeline item: \(timelineItemID)")
|
|
||||||
return .failure(.failedRedacting)
|
|
||||||
}
|
|
||||||
|
|
||||||
MXLog.info("Redacted timeline item: \(timelineItemID)")
|
MXLog.info("Redacted timeline item: \(timelineItemID)")
|
||||||
|
|
||||||
@@ -425,7 +430,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
MXLog.info("Toggling reaction for event: \(itemID)")
|
MXLog.info("Toggling reaction for event: \(itemID)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await timeline.toggleReaction(uniqueId: itemID.timelineID, key: reaction)
|
try await timeline.toggleReaction(uniqueId: itemID.uniqueID, key: reaction)
|
||||||
MXLog.info("Finished toggling reaction for event: \(itemID)")
|
MXLog.info("Finished toggling reaction for event: \(itemID)")
|
||||||
return .success(())
|
return .success(())
|
||||||
} catch {
|
} catch {
|
||||||
@@ -460,7 +465,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
do {
|
do {
|
||||||
let originalEvent = try await timeline.getEventTimelineItemByEventId(eventId: eventID)
|
let originalEvent = try await timeline.getEventTimelineItemByEventId(eventId: eventID)
|
||||||
|
|
||||||
guard try await timeline.edit(item: originalEvent,
|
guard try await timeline.edit(eventOrTransactionId: originalEvent.eventOrTransactionId,
|
||||||
newContent: .pollStart(pollData: .init(question: question,
|
newContent: .pollStart(pollData: .init(question: question,
|
||||||
answers: answers,
|
answers: answers,
|
||||||
maxSelections: 1,
|
maxSelections: 1,
|
||||||
@@ -482,7 +487,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
|
|
||||||
return await Task.dispatch(on: .global()) {
|
return await Task.dispatch(on: .global()) {
|
||||||
do {
|
do {
|
||||||
try self.timeline.endPoll(pollStartId: pollStartID, text: text)
|
try self.timeline.endPoll(pollStartEventId: pollStartID, text: text)
|
||||||
|
|
||||||
MXLog.info("Finished ending poll with eventID: \(pollStartID)")
|
MXLog.info("Finished ending poll with eventID: \(pollStartID)")
|
||||||
|
|
||||||
@@ -498,7 +503,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
MXLog.info("Sending response for poll with eventID: \(pollStartID)")
|
MXLog.info("Sending response for poll with eventID: \(pollStartID)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await timeline.sendPollResponse(pollStartId: pollStartID, answers: answers)
|
try await timeline.sendPollResponse(pollStartEventId: pollStartID, answers: answers)
|
||||||
|
|
||||||
MXLog.info("Finished sending response for poll with eventID: \(pollStartID)")
|
MXLog.info("Finished sending response for poll with eventID: \(pollStartID)")
|
||||||
|
|
||||||
@@ -618,7 +623,7 @@ extension Array where Element == TimelineItemProxy {
|
|||||||
func firstEventTimelineItemUsingStableID(_ id: TimelineItemIdentifier) -> EventTimelineItem? {
|
func firstEventTimelineItemUsingStableID(_ id: TimelineItemIdentifier) -> EventTimelineItem? {
|
||||||
for item in self {
|
for item in self {
|
||||||
if case let .event(eventTimelineItem) = item {
|
if case let .event(eventTimelineItem) = item {
|
||||||
if eventTimelineItem.id.timelineID == id.timelineID {
|
if eventTimelineItem.id.uniqueID == id.uniqueID {
|
||||||
return eventTimelineItem.item
|
return eventTimelineItem.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ class PollFormScreenUITests: XCTestCase {
|
|||||||
func testFilledPoll() async throws {
|
func testFilledPoll() async throws {
|
||||||
let app = Application.launch(.createPoll)
|
let app = Application.launch(.createPoll)
|
||||||
let questionTextField = app.textViews[A11yIdentifiers.pollFormScreen.question]
|
let questionTextField = app.textViews[A11yIdentifiers.pollFormScreen.question]
|
||||||
questionTextField.forceTap()
|
questionTextField.tapCenter()
|
||||||
questionTextField.typeText("Do you like polls?")
|
questionTextField.typeText("Do you like polls?")
|
||||||
|
|
||||||
let option1TextField = app.textViews[A11yIdentifiers.pollFormScreen.optionID(0)]
|
let option1TextField = app.textViews[A11yIdentifiers.pollFormScreen.optionID(0)]
|
||||||
option1TextField.forceTap()
|
option1TextField.tapCenter()
|
||||||
option1TextField.typeText("Yes")
|
option1TextField.typeText("Yes")
|
||||||
|
|
||||||
let option2TextField = app.textViews[A11yIdentifiers.pollFormScreen.optionID(1)]
|
let option2TextField = app.textViews[A11yIdentifiers.pollFormScreen.optionID(1)]
|
||||||
option2TextField.forceTap()
|
option2TextField.tapCenter()
|
||||||
option2TextField.typeText("No")
|
option2TextField.typeText("No")
|
||||||
|
|
||||||
// Dismiss the keyboard
|
// Dismiss the keyboard
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class UserSessionScreenTests: XCTestCase {
|
|||||||
try await Task.sleep(for: .seconds(1))
|
try await Task.sleep(for: .seconds(1))
|
||||||
try await app.assertScreenshot(.userSessionScreen, step: 2)
|
try await app.assertScreenshot(.userSessionScreen, step: 2)
|
||||||
|
|
||||||
app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].forceTap()
|
app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].tapCenter()
|
||||||
try await app.assertScreenshot(.userSessionScreen, step: 3)
|
try await app.assertScreenshot(.userSessionScreen, step: 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testComposerFocus() {
|
func testComposerFocus() {
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: TimelineItemIdentifier(uniqueID: "mock"))))
|
||||||
XCTAssertTrue(viewModel.state.bindings.composerFocused)
|
XCTAssertTrue(viewModel.state.bindings.composerFocused)
|
||||||
viewModel.process(timelineAction: .removeFocus)
|
viewModel.process(timelineAction: .removeFocus)
|
||||||
XCTAssertFalse(viewModel.state.bindings.composerFocused)
|
XCTAssertFalse(viewModel.state.bindings.composerFocused)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testComposerMode() {
|
func testComposerMode() {
|
||||||
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
|
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(uniqueID: "mock"))
|
||||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||||
XCTAssertEqual(viewModel.state.composerMode, mode)
|
XCTAssertEqual(viewModel.state.composerMode, mode)
|
||||||
viewModel.process(timelineAction: .clear)
|
viewModel.process(timelineAction: .clear)
|
||||||
@@ -56,7 +56,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testComposerModeIsPublished() {
|
func testComposerModeIsPublished() {
|
||||||
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
|
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(uniqueID: "mock"))
|
||||||
let expectation = expectation(description: "Composer mode is published")
|
let expectation = expectation(description: "Composer mode is published")
|
||||||
let cancellable = viewModel
|
let cancellable = viewModel
|
||||||
.context
|
.context
|
||||||
@@ -236,7 +236,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: .init(timelineID: "", eventID: "testID"))))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID")))))
|
||||||
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
||||||
viewModel.saveDraft()
|
viewModel.saveDraft()
|
||||||
|
|
||||||
@@ -257,12 +257,11 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(timelineID: "",
|
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID")),
|
||||||
eventID: "testID"),
|
replyDetails: .loaded(sender: .init(id: ""),
|
||||||
replyDetails: .loaded(sender: .init(id: ""),
|
eventID: "testID",
|
||||||
eventID: "testID",
|
eventContent: .message(.text(.init(body: "reply text")))),
|
||||||
eventContent: .message(.text(.init(body: "reply text")))),
|
isThread: false)))
|
||||||
isThread: false)))
|
|
||||||
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
||||||
viewModel.saveDraft()
|
viewModel.saveDraft()
|
||||||
|
|
||||||
@@ -283,12 +282,11 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(timelineID: "",
|
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID")),
|
||||||
eventID: "testID"),
|
replyDetails: .loaded(sender: .init(id: ""),
|
||||||
replyDetails: .loaded(sender: .init(id: ""),
|
eventID: "testID",
|
||||||
eventID: "testID",
|
eventContent: .message(.text(.init(body: "reply text")))),
|
||||||
eventContent: .message(.text(.init(body: "reply text")))),
|
isThread: false)))
|
||||||
isThread: false)))
|
|
||||||
viewModel.saveDraft()
|
viewModel.saveDraft()
|
||||||
|
|
||||||
await fulfillment(of: [expectation], timeout: 10)
|
await fulfillment(of: [expectation], timeout: 10)
|
||||||
@@ -397,7 +395,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
await fulfillment(of: [expectation], timeout: 10)
|
await fulfillment(of: [expectation], timeout: 10)
|
||||||
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .edit(originalItemId: .init(timelineID: "", eventID: "testID")))
|
XCTAssertEqual(viewModel.state.composerMode, .edit(originalItemId: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID"))))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world!"))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,13 +429,13 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
await fulfillment(of: [draftExpectation], timeout: 10)
|
await fulfillment(of: [draftExpectation], timeout: 10)
|
||||||
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
||||||
// Testing the loading state first
|
// Testing the loading state first
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(timelineID: "", eventID: testEventID),
|
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: testEventID)),
|
||||||
replyDetails: .loading(eventID: testEventID),
|
replyDetails: .loading(eventID: testEventID),
|
||||||
isThread: false))
|
isThread: false))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
||||||
|
|
||||||
await fulfillment(of: [loadReplyExpectation], timeout: 10)
|
await fulfillment(of: [loadReplyExpectation], timeout: 10)
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(timelineID: "", eventID: testEventID),
|
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: testEventID)),
|
||||||
replyDetails: loadedReply,
|
replyDetails: loadedReply,
|
||||||
isThread: true))
|
isThread: true))
|
||||||
}
|
}
|
||||||
@@ -445,8 +443,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
func testRestoreReplyAndCancelReplyMode() async {
|
func testRestoreReplyAndCancelReplyMode() async {
|
||||||
let testEventID = "testID"
|
let testEventID = "testID"
|
||||||
let text = "Hello world!"
|
let text = "Hello world!"
|
||||||
let loadedReply = TimelineItemReplyDetails.loaded(sender: .init(id: "userID",
|
let loadedReply = TimelineItemReplyDetails.loaded(sender: .init(id: "userID", displayName: "Username"),
|
||||||
displayName: "Username"),
|
|
||||||
eventID: testEventID,
|
eventID: testEventID,
|
||||||
eventContent: .message(.text(.init(body: "Reply text"))))
|
eventContent: .message(.text(.init(body: "Reply text"))))
|
||||||
|
|
||||||
@@ -472,7 +469,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
await fulfillment(of: [draftExpectation], timeout: 10)
|
await fulfillment(of: [draftExpectation], timeout: 10)
|
||||||
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
||||||
// Testing the loading state first
|
// Testing the loading state first
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(timelineID: "", eventID: testEventID),
|
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: testEventID)),
|
||||||
replyDetails: .loading(eventID: testEventID),
|
replyDetails: .loading(eventID: testEventID),
|
||||||
isThread: false))
|
isThread: false))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ class LoggingTests: XCTestCase {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
sender: .init(id: "sender"),
|
sender: .init(id: "sender"),
|
||||||
content: .init(body: "EmoteString", formattedBody: AttributedString(emoteAttributedString)))
|
content: .init(body: "EmoteString", formattedBody: AttributedString(emoteAttributedString)))
|
||||||
let imageMessage = ImageRoomTimelineItem(id: .init(timelineID: "myimagemessage"),
|
let imageMessage = ImageRoomTimelineItem(id: .init(uniqueID: "myimagemessage"),
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -184,25 +184,25 @@ class LoggingTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let content = try String(contentsOf: logFile)
|
let content = try String(contentsOf: logFile)
|
||||||
XCTAssertTrue(content.contains(textMessage.id.timelineID))
|
XCTAssertTrue(content.contains(textMessage.id.uniqueID))
|
||||||
XCTAssertFalse(content.contains(textMessage.body))
|
XCTAssertFalse(content.contains(textMessage.body))
|
||||||
XCTAssertFalse(content.contains(textAttributedString))
|
XCTAssertFalse(content.contains(textAttributedString))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(noticeMessage.id.timelineID))
|
XCTAssertTrue(content.contains(noticeMessage.id.uniqueID))
|
||||||
XCTAssertFalse(content.contains(noticeMessage.body))
|
XCTAssertFalse(content.contains(noticeMessage.body))
|
||||||
XCTAssertFalse(content.contains(noticeAttributedString))
|
XCTAssertFalse(content.contains(noticeAttributedString))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(emoteMessage.id.timelineID))
|
XCTAssertTrue(content.contains(emoteMessage.id.uniqueID))
|
||||||
XCTAssertFalse(content.contains(emoteMessage.body))
|
XCTAssertFalse(content.contains(emoteMessage.body))
|
||||||
XCTAssertFalse(content.contains(emoteAttributedString))
|
XCTAssertFalse(content.contains(emoteAttributedString))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(imageMessage.id.timelineID))
|
XCTAssertTrue(content.contains(imageMessage.id.uniqueID))
|
||||||
XCTAssertFalse(content.contains(imageMessage.body))
|
XCTAssertFalse(content.contains(imageMessage.body))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(videoMessage.id.timelineID))
|
XCTAssertTrue(content.contains(videoMessage.id.uniqueID))
|
||||||
XCTAssertFalse(content.contains(videoMessage.body))
|
XCTAssertFalse(content.contains(videoMessage.body))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(fileMessage.id.timelineID))
|
XCTAssertTrue(content.contains(fileMessage.id.uniqueID))
|
||||||
XCTAssertFalse(content.contains(fileMessage.body))
|
XCTAssertFalse(content.contains(fileMessage.body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import XCTest
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class MessageForwardingScreenViewModelTests: XCTestCase {
|
class MessageForwardingScreenViewModelTests: XCTestCase {
|
||||||
let forwardingItem = MessageForwardingItem(id: .init(timelineID: "t1", eventID: "t1"),
|
let forwardingItem = MessageForwardingItem(id: .init(uniqueID: "t1", eventOrTransactionID: .eventId(eventId: "t1")),
|
||||||
roomID: "1",
|
roomID: "1",
|
||||||
content: .init(noPointer: .init()))
|
content: .init(noPointer: .init()))
|
||||||
var viewModel: MessageForwardingScreenViewModelProtocol!
|
var viewModel: MessageForwardingScreenViewModelProtocol!
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
@testable import ElementX
|
@testable import ElementX
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
import XCTest
|
import XCTest
|
||||||
@@ -66,8 +67,8 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
let providerUpdateSubject = PassthroughSubject<([TimelineItemProxy], PaginationState), Never>()
|
let providerUpdateSubject = PassthroughSubject<([TimelineItemProxy], PaginationState), Never>()
|
||||||
pinnedTimelineProviderMock.underlyingUpdatePublisher = providerUpdateSubject.eraseToAnyPublisher()
|
pinnedTimelineProviderMock.underlyingUpdatePublisher = providerUpdateSubject.eraseToAnyPublisher()
|
||||||
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
||||||
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test1")), id: "1")),
|
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: "1")),
|
||||||
.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test2")), id: "2"))]
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: "2"))]
|
||||||
|
|
||||||
// check if the banner is now in a loaded state and is showing the counter
|
// check if the banner is now in a loaded state and is showing the counter
|
||||||
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
||||||
@@ -83,9 +84,9 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
||||||
viewState.pinnedEventsBannerState.count == 3
|
viewState.pinnedEventsBannerState.count == 3
|
||||||
}
|
}
|
||||||
providerUpdateSubject.send(([.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test1")), id: "1")),
|
providerUpdateSubject.send(([.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: "1")),
|
||||||
.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test2")), id: "2")),
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: "2")),
|
||||||
.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test3")), id: "3"))], .initial))
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: "3"))], .initial))
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
XCTAssertFalse(viewModel.context.viewState.pinnedEventsBannerState.isLoading)
|
XCTAssertFalse(viewModel.context.viewState.pinnedEventsBannerState.isLoading)
|
||||||
XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner)
|
XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner)
|
||||||
@@ -106,9 +107,9 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
let pinnedTimelineProviderMock = RoomTimelineProviderMock()
|
let pinnedTimelineProviderMock = RoomTimelineProviderMock()
|
||||||
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
||||||
pinnedTimelineProviderMock.underlyingUpdatePublisher = Empty<([TimelineItemProxy], PaginationState), Never>().eraseToAnyPublisher()
|
pinnedTimelineProviderMock.underlyingUpdatePublisher = Empty<([TimelineItemProxy], PaginationState), Never>().eraseToAnyPublisher()
|
||||||
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test1")), id: "1")),
|
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: "1")),
|
||||||
.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test2")), id: "2")),
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: "2")),
|
||||||
.event(.init(item: EventTimelineItemSDKMock(configuration: .init(eventID: "test3")), id: "3"))]
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: "3"))]
|
||||||
roomProxyMock.underlyingPinnedEventsTimeline = pinnedTimelineMock
|
roomProxyMock.underlyingPinnedEventsTimeline = pinnedTimelineMock
|
||||||
let viewModel = RoomScreenViewModel(roomProxy: roomProxyMock,
|
let viewModel = RoomScreenViewModel(roomProxy: roomProxyMock,
|
||||||
initialSelectedPinnedEventID: "test1",
|
initialSelectedPinnedEventID: "test1",
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
@testable import ElementX
|
@testable import ElementX
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
@@ -18,19 +20,9 @@ class TimelineItemFactoryTests: XCTestCase {
|
|||||||
attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()),
|
attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()),
|
||||||
stateEventStringBuilder: RoomStateEventStringBuilder(userID: ownUserID))
|
stateEventStringBuilder: RoomStateEventStringBuilder(userID: ownUserID))
|
||||||
|
|
||||||
let eventTimelineItem = EventTimelineItemSDKMock()
|
let eventTimelineItem = EventTimelineItem.mockCallInvite(sender: senderUserID)
|
||||||
eventTimelineItem.isOwnReturnValue = true
|
|
||||||
eventTimelineItem.timestampReturnValue = 0
|
|
||||||
eventTimelineItem.isEditableReturnValue = false
|
|
||||||
eventTimelineItem.canBeRepliedToReturnValue = false
|
|
||||||
eventTimelineItem.senderReturnValue = senderUserID
|
|
||||||
eventTimelineItem.senderProfileReturnValue = .pending
|
|
||||||
|
|
||||||
let timelineItemContent = TimelineItemContentSDKMock()
|
let eventTimelineItemProxy = EventTimelineItemProxy(item: eventTimelineItem, uniqueID: "0")
|
||||||
timelineItemContent.kindReturnValue = .callInvite
|
|
||||||
eventTimelineItem.contentReturnValue = timelineItemContent
|
|
||||||
|
|
||||||
let eventTimelineItemProxy = EventTimelineItemProxy(item: eventTimelineItem, id: "0")
|
|
||||||
|
|
||||||
let item = factory.buildTimelineItem(for: eventTimelineItemProxy, isDM: false)
|
let item = factory.buildTimelineItem(for: eventTimelineItemProxy, isDM: false)
|
||||||
|
|
||||||
|
|||||||
@@ -258,9 +258,9 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
func testSendReadReceiptWithoutEvents() async throws {
|
func testSendReadReceiptWithoutEvents() async throws {
|
||||||
// Given a room with only virtual items.
|
// Given a room with only virtual items.
|
||||||
let items = [SeparatorRoomTimelineItem(timelineID: "v1"),
|
let items = [SeparatorRoomTimelineItem(uniqueID: "v1"),
|
||||||
SeparatorRoomTimelineItem(timelineID: "v2"),
|
SeparatorRoomTimelineItem(uniqueID: "v2"),
|
||||||
SeparatorRoomTimelineItem(timelineID: "v3")]
|
SeparatorRoomTimelineItem(uniqueID: "v3")]
|
||||||
let (viewModel, _, timelineProxy, _) = readReceiptsConfiguration(with: items)
|
let (viewModel, _, timelineProxy, _) = readReceiptsConfiguration(with: items)
|
||||||
|
|
||||||
// When sending a read receipt for the last item.
|
// When sending a read receipt for the last item.
|
||||||
@@ -275,7 +275,7 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
// Given a room where the last event is a virtual item.
|
// Given a room where the last event is a virtual item.
|
||||||
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
|
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
|
||||||
TextRoomTimelineItem(eventID: "t2"),
|
TextRoomTimelineItem(eventID: "t2"),
|
||||||
SeparatorRoomTimelineItem(timelineID: "v3")]
|
SeparatorRoomTimelineItem(uniqueID: "v3")]
|
||||||
let (viewModel, _, _, _) = readReceiptsConfiguration(with: items)
|
let (viewModel, _, _, _) = readReceiptsConfiguration(with: items)
|
||||||
|
|
||||||
// When sending a read receipt for the last item.
|
// When sending a read receipt for the last item.
|
||||||
@@ -436,14 +436,14 @@ private extension TextRoomTimelineItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private extension SeparatorRoomTimelineItem {
|
private extension SeparatorRoomTimelineItem {
|
||||||
init(timelineID: String) {
|
init(uniqueID: String) {
|
||||||
self.init(id: .init(timelineID: timelineID), text: "")
|
self.init(id: .init(uniqueID: uniqueID), text: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension TextRoomTimelineItem {
|
private extension TextRoomTimelineItem {
|
||||||
init(eventID: String) {
|
init(eventID: String) {
|
||||||
self.init(id: .init(timelineID: UUID().uuidString, eventID: eventID),
|
self.init(id: .init(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: eventID)),
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ packages:
|
|||||||
# Element/Matrix dependencies
|
# Element/Matrix dependencies
|
||||||
MatrixRustSDK:
|
MatrixRustSDK:
|
||||||
url: https://github.com/element-hq/matrix-rust-components-swift
|
url: https://github.com/element-hq/matrix-rust-components-swift
|
||||||
exactVersion: 1.0.52
|
exactVersion: 1.0.53
|
||||||
# path: ../matrix-rust-sdk
|
# path: ../matrix-rust-sdk
|
||||||
Compound:
|
Compound:
|
||||||
url: https://github.com/element-hq/compound-ios
|
url: https://github.com/element-hq/compound-ios
|
||||||
|
|||||||
Reference in New Issue
Block a user