Add room's update publisher (#952)

* Add room update publisher

* Cleanup

* Update room’s title

* Add refresh logic in RoomDetailsScreenViewModel

* Fix UTs

* Add UT

* Update timeline listener in RoomProxy

* Fix caching in LoadableAvatarImage

* Cleanup

* Update RoomProxy api

* Inject room proxy in RoomScreenViewModel

* Cleanup

* Fix UTs
This commit is contained in:
Alfonso Grillo 2023-05-25 12:42:58 +02:00 committed by GitHub
parent c59921103d
commit bf2102e5d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 169 additions and 105 deletions

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
@ -100,6 +100,7 @@
281BED345D59A9A6A99E9D98 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; };
282A5F3375DDC774AE09B0C3 /* TracingConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */; };
2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7310D8DFE01AF45F0689C3AA /* Publisher.swift */; };
28A94A7DF684F2A29C4ADFE9 /* TimelineReceiptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A5457B0320D028A676C248F /* TimelineReceiptView.swift */; };
290FDB0FFDC2F1DDF660343E /* TestMeasurementParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */; };
292827744227DF61C930BDDB /* CreateRoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB0D6CB491777E7FC6B5BA12 /* CreateRoomScreen.swift */; };
2955F4C160CFD7794D819C64 /* EffectsScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F7398C5FC12586FB10E9D /* EffectsScene.swift */; };
@ -138,6 +139,7 @@
39929D29B265C3F6606047DE /* AlignedScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8872E9C5E91E9F2BFC4EBCCA /* AlignedScrollView.swift */; };
3A08584ECDD4A4541DBF21F8 /* EmojiLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 201305507D7DFD16E544563A /* EmojiLoaderProtocol.swift */; };
3A64A93A651A3CB8774ADE8E /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = BA93CD75CCE486660C9040BD /* Collections */; };
3A7DD0D13B0FB8876D69D829 /* TextBasedRoomTimelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */; };
3B0F9B57D25B07E66F15762A /* MediaUploadPreviewScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E7C987AE5DC9087BB19F7D /* MediaUploadPreviewScreenModels.swift */; };
3B28408450BCAED911283AA2 /* UserPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35FA991289149D31F4286747 /* UserPreference.swift */; };
3C549A0BF39F8A854D45D9FD /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 020597E28A4BC8E1BE8EDF6E /* KeychainAccess */; };
@ -302,6 +304,7 @@
8285FF4B2C2331758C437FF7 /* ReportContentScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713B48DBF65DE4B0DD445D66 /* ReportContentScreenViewModelProtocol.swift */; };
828EA5009557C2B9DCD4CA0F /* UserDiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */; };
829062DD3C3F7016FE1A6476 /* RoomDetailsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BFDAF6918BB096C44788FC9 /* RoomDetailsScreenUITests.swift */; };
8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9227F7495DA43324050A863 /* TextBasedRoomTimelineItem.swift */; };
83E05DB56BBD6C151602881E /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E0ADE4FAA5A4DB91CB07737 /* SettingsScreen.swift */; };
84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A8E19C4645D3F5F9FB02355 /* UnitTestsAppCoordinator.swift */; };
84C0CF78BCE085C08CB94D86 /* TimelineEventProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00B62EE933FC3D5651AF4607 /* TimelineEventProxy.swift */; };
@ -333,6 +336,7 @@
8BC8EF6705A78946C1F22891 /* SoftLogoutScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71A7D4DDEEE5D2CA0C8D63CD /* SoftLogoutScreen.swift */; };
8C454500B8073E1201F801A9 /* MXLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = A34A814CBD56230BC74FFCF4 /* MXLogger.swift */; };
8CC12086CBF91A7E10CDC205 /* HomeScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */; };
8D0C5BC670D514760CC84E2A /* TextBasedRoomTimelineViewMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A542BC40D6EC2E66BC5659B /* TextBasedRoomTimelineViewMock.swift */; };
8D3E1FADD78E72504DE0E402 /* UserAgentBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */; };
8D605456793F243649EC96AA /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = CD6B0C4639E066915B5E6463 /* target.yml */; };
8D71E5E53F372202379BECCE /* BugReportScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 303FCADE77DF1F3670C086ED /* BugReportScreenViewModel.swift */; };
@ -394,6 +398,7 @@
A216C83ADCF32BA5EF8A6FBC /* InviteUsersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */; };
A23B8B27A1436A1049EEF68E /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
A2434D4DFB49A68E5CD0F53C /* MediaLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */; };
A2A5AB2E8B3F5CA769E531FA /* TextBasedRoomTimelineViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E47F18A9A077E351CEA10D4 /* TextBasedRoomTimelineViewProtocol.swift */; };
A33784831AD880A670CAA9F9 /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */; };
A371629728E597C5FCA3C2B2 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73FC861755C6388F62B9280A /* Analytics.swift */; };
A37EED79941AD3B7140B3822 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287FC98AF2664EAD79C0D902 /* UIDevice.swift */; };
@ -408,11 +413,6 @@
A5D551E5691749066E0E0C44 /* RoomDetailsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837B440C4705E4B899BCB899 /* RoomDetailsScreenViewModel.swift */; };
A6DEC1ADEC8FEEC206A0FA37 /* AttributedStringBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F37B5DA798C9AE436F2C2C /* AttributedStringBuilderProtocol.swift */; };
A6F713461DB62AC06293E7B7 /* FilePreviewScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820637A0F9C2F562FF40CBC8 /* FilePreviewScreenModels.swift */; };
A733C86A2A1D17590055ECD6 /* TimelineReceiptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A733C8692A1D17590055ECD6 /* TimelineReceiptView.swift */; };
A733C86C2A1E149E0055ECD6 /* TextBasedRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A733C86B2A1E149E0055ECD6 /* TextBasedRoomTimelineItem.swift */; };
A733C86E2A1E1C190055ECD6 /* TextBasedRoomTimelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A733C86D2A1E1C190055ECD6 /* TextBasedRoomTimelineTests.swift */; };
A7C152962A1F4E4C0089FF9D /* TextBasedRoomTimelineViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C152952A1F4E4C0089FF9D /* TextBasedRoomTimelineViewProtocol.swift */; };
A7C152982A1F4E710089FF9D /* TextBasedRoomTimelineViewMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C152972A1F4E710089FF9D /* TextBasedRoomTimelineViewMock.swift */; };
A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; };
A7FD7B992E6EE6E5A8429197 /* RoomSummaryDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142808B69851451AC32A2CEA /* RoomSummaryDetails.swift */; };
A816F7087C495D85048AC50E /* RoomMemberDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */; };
@ -726,7 +726,7 @@
1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = "<group>"; };
127A57D053CE8C87B5EFB089 /* Consumable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Consumable.swift; sourceTree = "<group>"; };
127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = "<group>"; };
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = "<group>"; };
130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = "<group>"; };
13673F95EBA78D40C09CCE35 /* MockUserIndicatorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserIndicatorController.swift; sourceTree = "<group>"; };
13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@ -774,6 +774,7 @@
28D116D4633E177BE1AC0E71 /* AnalyticsSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModel.swift; sourceTree = "<group>"; };
2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
2A96A67AD0E32C48941EFBB3 /* SessionVerificationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenCoordinator.swift; sourceTree = "<group>"; };
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
2AFEF3AC64B1358083F76B8B /* List.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = List.swift; sourceTree = "<group>"; };
2BB385E148DE55C85C0A02D6 /* SoftLogoutScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenModels.swift; sourceTree = "<group>"; };
2C0197EAE9D45A662B8847B6 /* RoomTimelineControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerProtocol.swift; sourceTree = "<group>"; };
@ -806,6 +807,7 @@
3948D16F021DFDB2CD26EAA8 /* MockBackgroundTaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBackgroundTaskService.swift; sourceTree = "<group>"; };
398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadableFrameModifier.swift; sourceTree = "<group>"; };
39B6C8690AEA1E49FF1BAF95 /* MediaUploadPreviewScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenUITests.swift; sourceTree = "<group>"; };
3A5457B0320D028A676C248F /* TimelineReceiptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReceiptView.swift; sourceTree = "<group>"; };
3B5E97E9615A158C76B2AB77 /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = "<group>"; };
3BFDAF6918BB096C44788FC9 /* RoomDetailsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenUITests.swift; sourceTree = "<group>"; };
3C1A3D524D63815B28FA4D62 /* EmojiCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiCategory.swift; sourceTree = "<group>"; };
@ -837,7 +839,7 @@
46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = "<group>"; };
471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = "<group>"; };
478BE8591BD13E908EF70C0C /* DesignKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DesignKit; sourceTree = SOURCE_ROOT; };
478BE8591BD13E908EF70C0C /* DesignKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = DesignKit; path = DesignKit; sourceTree = SOURCE_ROOT; };
4798B3B7A1E8AE3901CEE8C6 /* FramePreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramePreferenceKey.swift; sourceTree = "<group>"; };
47E6DD75A81D07CD91997D8C /* SettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
47EBB5D698CE9A25BB553A2D /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
@ -845,6 +847,7 @@
4959CECEC984B3995616F427 /* DataProtectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProtectionManager.swift; sourceTree = "<group>"; };
49D2C8E66E83EA578A7F318A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotificationRequest.swift; sourceTree = "<group>"; };
4A542BC40D6EC2E66BC5659B /* TextBasedRoomTimelineViewMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineViewMock.swift; sourceTree = "<group>"; };
4AB7D7DAAAF662DED9D02379 /* MockMediaLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaLoader.swift; sourceTree = "<group>"; };
4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = "<group>"; };
4B5046BB295AEAFA6FB81655 /* SessionVerificationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenModels.swift; sourceTree = "<group>"; };
@ -852,6 +855,7 @@
4CDDDDD9FE1A699D23A5E096 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = "<group>"; };
4D6E4C37E9F0E53D3DF951AC /* HomeScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenUITests.swift; sourceTree = "<group>"; };
4E2245243369B99216C7D84E /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
4E47F18A9A077E351CEA10D4 /* TextBasedRoomTimelineViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineViewProtocol.swift; sourceTree = "<group>"; };
4F0CB536D1C3CC15AA740CC6 /* AuthenticationServiceProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxyProtocol.swift; sourceTree = "<group>"; };
4F1DFE6E746539F33042D3A9 /* FormSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormSection.swift; sourceTree = "<group>"; };
4FD6E621CC5E6D4830D96D2D /* MockMediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaProvider.swift; sourceTree = "<group>"; };
@ -978,7 +982,7 @@
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
8D6094DEAAEB388E1AE118C6 /* MockRoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineProvider.swift; sourceTree = "<group>"; };
8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.swift; sourceTree = "<group>"; };
8EC57A32ABC80D774CC663DB /* SettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenUITests.swift; sourceTree = "<group>"; };
8F61A0DD8243B395499C99A2 /* InvitesScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenUITests.swift; sourceTree = "<group>"; };
@ -1036,12 +1040,7 @@
A65F140F9FE5E8D4DAEFF354 /* RoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxy.swift; sourceTree = "<group>"; };
A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = "<group>"; };
A6F5CDE754D53A9A403EDBA9 /* DeveloperOptionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
A733C8692A1D17590055ECD6 /* TimelineReceiptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReceiptView.swift; sourceTree = "<group>"; };
A733C86B2A1E149E0055ECD6 /* TextBasedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineItem.swift; sourceTree = "<group>"; };
A733C86D2A1E1C190055ECD6 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = "<group>"; };
A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; };
A7C152952A1F4E4C0089FF9D /* TextBasedRoomTimelineViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineViewProtocol.swift; sourceTree = "<group>"; };
A7C152972A1F4E710089FF9D /* TextBasedRoomTimelineViewMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineViewMock.swift; sourceTree = "<group>"; };
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
A8903A9F615BBD0E6D7CD133 /* ApplicationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationProtocol.swift; sourceTree = "<group>"; };
@ -1077,7 +1076,7 @@
B43AF03660F5FD4FFFA7F1CE /* TimelineItemContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemContextMenu.swift; sourceTree = "<group>"; };
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = "<group>"; };
B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = "<group>"; };
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = "<group>"; };
B6E89E530A8E92EC44301CA1 /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
B7DBA101D643B31E813F3AC1 /* AnalyticsSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreen.swift; sourceTree = "<group>"; };
@ -1087,6 +1086,7 @@
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>"; };
B902EA6CD3296B0E10EE432B /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; };
B9227F7495DA43324050A863 /* TextBasedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineItem.swift; sourceTree = "<group>"; };
B99E13633862847D8B7E2815 /* StartChatScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenModels.swift; sourceTree = "<group>"; };
BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferenceTests.swift; sourceTree = "<group>"; };
BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = "<group>"; };
@ -1141,7 +1141,7 @@
CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = "<group>"; };
CECF45B5E8E795666B8C5013 /* SettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenModels.swift; sourceTree = "<group>"; };
CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = "<group>"; };
D06A27D9C70E0DCC1E199163 /* OnboardingBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackgroundView.swift; sourceTree = "<group>"; };
D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; };
@ -1203,7 +1203,7 @@
ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModel.swift; sourceTree = "<group>"; };
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = "<group>"; };
ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = "<group>"; };
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = "<group>"; };
ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = "<group>"; };
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = "<group>"; };
EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = "<group>"; };
EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = "<group>"; };
@ -2188,6 +2188,7 @@
32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */,
6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */,
2CEBCB9676FCD1D0F13188DD /* StringTests.swift */,
2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */,
1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */,
EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */,
0DE6C5C756E1393202BA95CD /* UserNotificationControllerTests.swift */,
@ -2197,7 +2198,6 @@
7583EAC171059A86B767209F /* MediaProvider */,
7DBC911559934065993A5FF4 /* NotificationManager */,
1C62F5382CC9D9F7DCEC344A /* UserDiscoveryService */,
A733C86D2A1E1C190055ECD6 /* TextBasedRoomTimelineTests.swift */,
);
path = Sources;
sourceTree = "<group>";
@ -2717,13 +2717,13 @@
6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */,
ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */,
612EF972F2A1800682D32C5E /* StickerRoomTimelineView.swift */,
B9227F7495DA43324050A863 /* TextBasedRoomTimelineItem.swift */,
4A542BC40D6EC2E66BC5659B /* TextBasedRoomTimelineViewMock.swift */,
4E47F18A9A077E351CEA10D4 /* TextBasedRoomTimelineViewProtocol.swift */,
F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */,
F9ED8E731E21055F728E5FED /* TimelineStartRoomTimelineView.swift */,
A2AC3C656E960E15B5905E05 /* UnsupportedRoomTimelineView.swift */,
1941C8817E6B6971BA4415F5 /* VideoRoomTimelineView.swift */,
A733C86B2A1E149E0055ECD6 /* TextBasedRoomTimelineItem.swift */,
A7C152952A1F4E4C0089FF9D /* TextBasedRoomTimelineViewProtocol.swift */,
A7C152972A1F4E710089FF9D /* TextBasedRoomTimelineViewMock.swift */,
);
path = Timeline;
sourceTree = "<group>";
@ -2834,7 +2834,7 @@
children = (
D5AC06FC11B6638F7BF1670E /* TimelineDeliveryStatusView.swift */,
351E89CE2ED9B73C5CC47955 /* TimelineReactionsView.swift */,
A733C8692A1D17590055ECD6 /* TimelineReceiptView.swift */,
3A5457B0320D028A676C248F /* TimelineReceiptView.swift */,
);
path = Supplementary;
sourceTree = "<group>";
@ -3531,7 +3531,6 @@
864C69CF951BF36D25BE0C03 /* DeveloperOptionsScreenViewModelTests.swift in Sources */,
9C45CE85325CD591DADBC4CA /* ElementXTests.swift in Sources */,
501304F26B52DF7024011B6C /* EmojiMartJSONLoaderTests.swift in Sources */,
A733C86E2A1E1C190055ECD6 /* TextBasedRoomTimelineTests.swift in Sources */,
25618589E0DE0F1E95FC7B5C /* EmojiProviderTests.swift in Sources */,
71B62C48B8079D49F3FBC845 /* ExpiringTaskRunnerTests.swift in Sources */,
CA45758F08DF42D41D8A4B29 /* FilePreviewViewModelTests.swift in Sources */,
@ -3573,6 +3572,7 @@
6189B4ABD535CE526FA1107B /* StartChatViewModelTests.swift in Sources */,
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */,
E75CE800B3E64D0F7F8E228D /* TemplateScreenViewModelTests.swift in Sources */,
3A7DD0D13B0FB8876D69D829 /* TextBasedRoomTimelineTests.swift in Sources */,
282A5F3375DDC774AE09B0C3 /* TracingConfigurationTests.swift in Sources */,
8E650379587C31D7912ED67B /* UNNotification+Creator.swift in Sources */,
AF33B9044498211C3D82F1E1 /* UNTextInputNotificationResponse+Creator.swift in Sources */,
@ -3652,7 +3652,6 @@
B98A20A093A4FB785BFCCA53 /* BugReportScreenCoordinator.swift in Sources */,
4FFDC274824F7CC0BBDF581E /* BugReportScreenModels.swift in Sources */,
8D71E5E53F372202379BECCE /* BugReportScreenViewModel.swift in Sources */,
A733C86C2A1E149E0055ECD6 /* TextBasedRoomTimelineItem.swift in Sources */,
B4A0C69370E6008A971463E7 /* BugReportScreenViewModelProtocol.swift in Sources */,
3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */,
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */,
@ -3889,7 +3888,6 @@
77D7DAA41AAB36800C1F2E2D /* RoomTimelineProviderProtocol.swift in Sources */,
CF82143AA4A4F7BD11D22946 /* RoomTimelineViewProvider.swift in Sources */,
B2F8E01ABA1BA30265B4ECBE /* RoundedCornerShape.swift in Sources */,
A7C152962A1F4E4C0089FF9D /* TextBasedRoomTimelineViewProtocol.swift in Sources */,
50C90117FE25390BFBD40173 /* RustTracing.swift in Sources */,
0437765FF480249486893CC7 /* ScreenTrackerViewModifier.swift in Sources */,
0BFA67AFD757EE2BA569836A /* ScrollViewAdapter.swift in Sources */,
@ -3945,6 +3943,9 @@
275EDE8849A2AC1D9309ED7C /* TemplateScreenViewModel.swift in Sources */,
2C4C750D0039AFABDF24236C /* TemplateScreenViewModelProtocol.swift in Sources */,
D85D4FA590305180B4A41795 /* Tests.swift in Sources */,
8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */,
8D0C5BC670D514760CC84E2A /* TextBasedRoomTimelineViewMock.swift in Sources */,
A2A5AB2E8B3F5CA769E531FA /* TextBasedRoomTimelineViewProtocol.swift in Sources */,
BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */,
53F1196F9C69512306A2693F /* TextRoomTimelineItemContent.swift in Sources */,
5E0F2E612718BB4397A6D40A /* TextRoomTimelineView.swift in Sources */,
@ -3954,13 +3955,12 @@
157E5FDDF419C0B2CA7E2C28 /* TimelineItemBubbledStylerView.swift in Sources */,
01CB8ACFA5E143E89C168CA8 /* TimelineItemContextMenu.swift in Sources */,
FBCCF1EA25A071324FCD8544 /* TimelineItemDebugView.swift in Sources */,
A733C86A2A1D17590055ECD6 /* TimelineReceiptView.swift in Sources */,
A7C152982A1F4E710089FF9D /* TextBasedRoomTimelineViewMock.swift in Sources */,
F508683B76EF7B23BB2CBD6D /* TimelineItemPlainStylerView.swift in Sources */,
440123E29E2F9B001A775BBE /* TimelineItemProxy.swift in Sources */,
9586E90A447C4896C0CA3A8E /* TimelineItemReplyDetails.swift in Sources */,
1B88BB631F7FC45A213BB554 /* TimelineItemSender.swift in Sources */,
9B582B3EEFEA615D4A6FBF1A /* TimelineReactionsView.swift in Sources */,
28A94A7DF684F2A29C4ADFE9 /* TimelineReceiptView.swift in Sources */,
2A90DD14DE5C891BFA433950 /* TimelineReplyView.swift in Sources */,
ABF3FAB234AD3565B214309B /* TimelineSenderAvatarView.swift in Sources */,
C4FE0E11A907C8999F92D5A8 /* TimelineStartRoomTimelineItem.swift in Sources */,

View File

@ -419,6 +419,11 @@ class RoomProxyMock: RoomProxyProtocol {
set(value) { underlyingMembersPublisher = value }
}
var underlyingMembersPublisher: AnyPublisher<[RoomMemberProxyProtocol], Never>!
var updatesPublisher: AnyPublisher<TimelineDiff, Never> {
get { return underlyingUpdatesPublisher }
set(value) { underlyingUpdatesPublisher = value }
}
var underlyingUpdatesPublisher: AnyPublisher<TimelineDiff, Never>!
var invitedMembersCount: UInt {
get { return underlyingInvitedMembersCount }
set(value) { underlyingInvitedMembersCount = value }
@ -477,39 +482,23 @@ class RoomProxyMock: RoomProxyProtocol {
return loadDisplayNameForUserIdReturnValue
}
}
//MARK: - addTimelineListener
//MARK: - registerTimelineListenerIfNeeded
var addTimelineListenerListenerCallsCount = 0
var addTimelineListenerListenerCalled: Bool {
return addTimelineListenerListenerCallsCount > 0
var registerTimelineListenerIfNeededCallsCount = 0
var registerTimelineListenerIfNeededCalled: Bool {
return registerTimelineListenerIfNeededCallsCount > 0
}
var addTimelineListenerListenerReceivedListener: TimelineListener?
var addTimelineListenerListenerReceivedInvocations: [TimelineListener] = []
var addTimelineListenerListenerReturnValue: Result<[TimelineItem], RoomProxyError>!
var addTimelineListenerListenerClosure: ((TimelineListener) -> Result<[TimelineItem], RoomProxyError>)?
var registerTimelineListenerIfNeededReturnValue: Result<[TimelineItem], RoomProxyError>!
var registerTimelineListenerIfNeededClosure: (() -> Result<[TimelineItem], RoomProxyError>)?
func addTimelineListener(listener: TimelineListener) -> Result<[TimelineItem], RoomProxyError> {
addTimelineListenerListenerCallsCount += 1
addTimelineListenerListenerReceivedListener = listener
addTimelineListenerListenerReceivedInvocations.append(listener)
if let addTimelineListenerListenerClosure = addTimelineListenerListenerClosure {
return addTimelineListenerListenerClosure(listener)
func registerTimelineListenerIfNeeded() -> Result<[TimelineItem], RoomProxyError> {
registerTimelineListenerIfNeededCallsCount += 1
if let registerTimelineListenerIfNeededClosure = registerTimelineListenerIfNeededClosure {
return registerTimelineListenerIfNeededClosure()
} else {
return addTimelineListenerListenerReturnValue
return registerTimelineListenerIfNeededReturnValue
}
}
//MARK: - removeTimelineListener
var removeTimelineListenerCallsCount = 0
var removeTimelineListenerCalled: Bool {
return removeTimelineListenerCallsCount > 0
}
var removeTimelineListenerClosure: (() -> Void)?
func removeTimelineListener() {
removeTimelineListenerCallsCount += 1
removeTimelineListenerClosure?()
}
//MARK: - paginateBackwards
var paginateBackwardsRequestSizeUntilNumberOfItemsCallsCount = 0

View File

@ -73,5 +73,7 @@ extension RoomProxyMock {
updateMembersClosure = { }
acceptInvitationClosure = { .success(()) }
registerTimelineListenerIfNeededClosure = { .success([]) }
underlyingUpdatesPublisher = Empty(completeImmediately: false).eraseToAnyPublisher()
}
}

View File

@ -53,6 +53,9 @@ struct LoadableAvatarImage: View {
} placeholder: {
PlaceholderAvatarImage(name: name, contentID: contentID)
}
// Binds the lifecycle of the LoadableImage to the associated URL.
// This fixes the problem of the cache returning old values after a change in the URL.
.id(url)
} else {
PlaceholderAvatarImage(name: name, contentID: contentID)
}

View File

@ -36,7 +36,7 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
canonicalAlias: roomProxy.canonicalAlias,
isEncrypted: roomProxy.isEncrypted,
isDirect: roomProxy.isDirect,
title: roomProxy.displayName ?? roomProxy.name ?? "Unknown Room",
title: roomProxy.roomTitle,
topic: roomProxy.topic,
avatarURL: roomProxy.avatarURL,
permalink: roomProxy.permalink,
@ -81,6 +81,13 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
// MARK: - Private
private func setupSubscriptions() {
switch roomProxy.registerTimelineListenerIfNeeded() {
case .success, .failure(.roomListenerAlreadyRegistered):
break
case .failure:
MXLog.error("Failed to register a room listener in room's details for the room \(roomProxy.id)")
}
roomProxy.membersPublisher
.sink { [weak self] members in
guard let self else { return }
@ -102,6 +109,16 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
}
}
.store(in: &cancellables)
roomProxy.updatesPublisher
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
.sink { [weak self] _ in
guard let self else { return }
self.state.title = self.roomProxy.roomTitle
self.state.topic = self.roomProxy.topic
self.state.avatarURL = self.roomProxy.avatarURL
}
.store(in: &cancellables)
}
private func buildMembersDetails(members: [RoomMemberProxyProtocol]) async -> RoomMembersDetails {

View File

@ -44,8 +44,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
viewModel = RoomScreenViewModel(timelineController: parameters.timelineController,
mediaProvider: parameters.mediaProvider,
roomName: parameters.roomProxy.displayName ?? parameters.roomProxy.name,
roomAvatarUrl: parameters.roomProxy.avatarURL)
roomProxy: parameters.roomProxy)
}
// MARK: - Public
@ -76,7 +75,6 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
}
func stop() {
parameters.roomProxy.removeTimelineListener()
viewModel.context.send(viewAction: .markRoomAsRead)
}

View File

@ -27,17 +27,18 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
static let toastErrorID = "RoomScreenToastError"
}
private let roomProxy: RoomProxyProtocol
private let timelineController: RoomTimelineControllerProtocol
init(timelineController: RoomTimelineControllerProtocol,
mediaProvider: MediaProviderProtocol,
roomName: String?,
roomAvatarUrl: URL? = nil) {
roomProxy: RoomProxyProtocol) {
self.roomProxy = roomProxy
self.timelineController = timelineController
super.init(initialViewState: RoomScreenViewState(roomId: timelineController.roomID,
roomTitle: roomName ?? "Unknown room 💥",
roomAvatarURL: roomAvatarUrl,
roomTitle: roomProxy.roomTitle,
roomAvatarURL: roomProxy.avatarURL,
timelineStyle: ServiceLocator.shared.settings.timelineStyle,
bindings: .init(composerText: "", composerFocused: false)),
imageProvider: mediaProvider)
@ -70,6 +71,16 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
return self.contextMenuActionsForItemId(itemId)
}
roomProxy
.updatesPublisher
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
.sink { [weak self] _ in
guard let self else { return }
self.state.roomTitle = roomProxy.roomTitle
self.state.roomAvatarURL = roomProxy.avatarURL
}
.store(in: &cancellables)
ServiceLocator.shared.settings.$timelineStyle
.weakAssign(to: \.state.timelineStyle, on: self)
.store(in: &cancellables)
@ -406,5 +417,5 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
extension RoomScreenViewModel {
static let mock = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Preview room")
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")))
}

View File

@ -59,8 +59,7 @@ struct RoomHeaderView_Previews: PreviewProvider {
static var bodyPlain: some View {
let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Some Room name",
roomAvatarUrl: URL.picturesDirectory)
roomProxy: RoomProxyMock(with: .init(displayName: "Some Room name", avatarURL: URL.picturesDirectory)))
RoomHeaderView(context: viewModel.context)
.previewLayout(.sizeThatFits)
@ -71,8 +70,7 @@ struct RoomHeaderView_Previews: PreviewProvider {
static var bodyEncrypted: some View {
let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Some Room name",
roomAvatarUrl: nil)
roomProxy: RoomProxyMock(with: .init(displayName: "Some Room name")))
RoomHeaderView(context: viewModel.context)
.previewLayout(.sizeThatFits)

View File

@ -133,7 +133,7 @@ struct RoomScreen: View {
struct RoomScreen_Previews: PreviewProvider {
static let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Preview room")
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")))
static var previews: some View {
NavigationStack {

View File

@ -84,7 +84,7 @@ struct TimelineView: UIViewControllerRepresentable {
struct TimelineTableView_Previews: PreviewProvider {
static let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Preview room")
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")))
static var previews: some View {
NavigationStack {

View File

@ -41,7 +41,29 @@ class RoomProxy: RoomProxyProtocol {
var membersPublisher: AnyPublisher<[RoomMemberProxyProtocol], Never> {
membersSubject.eraseToAnyPublisher()
}
private var timelineListener: RoomTimelineListener?
private let updatesSubject = PassthroughSubject<TimelineDiff, Never>()
var updatesPublisher: AnyPublisher<TimelineDiff, Never> {
updatesSubject.eraseToAnyPublisher()
}
deinit {
Task { @MainActor [roomTimelineObservationToken, slidingSyncRoom] in
roomTimelineObservationToken?.cancel()
let task = ExpiringTaskRunner {
let unsubscribeTask = slidingSyncRoom.unsubscribeFromRoom()
while !unsubscribeTask.isFinished() {
try await Task.sleep(for: .seconds(2))
}
}
try? await task.run(timeout: .seconds(30))
}
}
init(slidingSyncRoom: SlidingSyncRoomProtocol,
room: RoomProtocol,
backgroundTaskService: BackgroundTaskServiceProtocol) {
@ -139,15 +161,27 @@ class RoomProxy: RoomProxyProtocol {
}
}
func addTimelineListener(listener: TimelineListener) -> Result<[TimelineItem], RoomProxyError> {
let settings = RoomSubscription(requiredState: [RequiredState(key: "m.room.topic", value: ""),
func registerTimelineListenerIfNeeded() -> Result<[TimelineItem], RoomProxyError> {
guard timelineListener == nil else {
return .failure(.roomListenerAlreadyRegistered)
}
let settings = RoomSubscription(requiredState: [RequiredState(key: "m.room.name", value: ""),
RequiredState(key: "m.room.topic", value: ""),
RequiredState(key: "m.room.avatar", value: ""),
RequiredState(key: "m.room.canonical_alias", value: ""),
RequiredState(key: "m.room.join_rules", value: "")],
timelineLimit: UInt32(SlidingSyncConstants.timelinePrecachingTimelineLimit))
roomSubscriptionObservationToken = slidingSyncRoom.subscribeToRoom(settings: settings)
let listener = RoomTimelineListener { [weak self] timelineDiff in
self?.updatesSubject.send(timelineDiff)
}
if let result = try? slidingSyncRoom.addTimelineListener(listener: listener) {
roomTimelineObservationToken = result.taskHandle
timelineListener = listener
Task {
await fetchMembers()
await updateMembers()
@ -158,15 +192,6 @@ class RoomProxy: RoomProxyProtocol {
}
}
func removeTimelineListener() {
roomTimelineObservationToken?.cancel()
roomTimelineObservationToken = nil
roomSubscriptionObservationToken = nil
roomUnsubscriptionObservationToken = slidingSyncRoom.unsubscribeFromRoom()
}
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomProxyError> {
do {
try await Task.dispatch(on: .global()) {
@ -487,3 +512,15 @@ class RoomProxy: RoomProxyProtocol {
self.displayName = displayName
}
}
private class RoomTimelineListener: TimelineListener {
private let onUpdateClosure: (TimelineDiff) -> Void
init(_ onUpdateClosure: @escaping (TimelineDiff) -> Void) {
self.onUpdateClosure = onUpdateClosure
}
func onUpdate(update: TimelineDiff) {
onUpdateClosure(update)
}
}

View File

@ -20,6 +20,7 @@ import MatrixRustSDK
enum RoomProxyError: Error {
case noMoreMessagesToBackPaginate
case roomListenerAlreadyRegistered
case failedPaginatingBackwards
case failedRetrievingMemberAvatarURL
case failedRetrievingMemberDisplayName
@ -59,14 +60,19 @@ protocol RoomProxyProtocol {
var avatarURL: URL? { get }
var membersPublisher: AnyPublisher<[RoomMemberProxyProtocol], Never> { get }
/// Publishes the room's updates.
/// The publisher starts publishing after the first call to `registerTimelineListenerIfNeeded()`
/// The thread on which this publisher sends the output isn't defined.
var updatesPublisher: AnyPublisher<TimelineDiff, Never> { get }
func loadAvatarURLForUserId(_ userId: String) async -> Result<URL?, RoomProxyError>
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, RoomProxyError>
func addTimelineListener(listener: TimelineListener) -> Result<[TimelineItem], RoomProxyError>
func removeTimelineListener()
/// Registers a timeline listener if not registered already.
/// Updates for this object will be published on the `updatesPublisher` publisher.
func registerTimelineListenerIfNeeded() -> Result<[TimelineItem], RoomProxyError>
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomProxyError>
@ -130,4 +136,10 @@ extension RoomProxyProtocol {
func sendMessage(_ message: String) async -> Result<Void, RoomProxyError> {
await sendMessage(message, inReplyTo: nil)
}
// Avoids to duplicate the same logic around in the app
// Probably this should be done in rust.
var roomTitle: String {
displayName ?? name ?? "Unknown room 💥"
}
}

View File

@ -18,14 +18,6 @@ import Combine
import Foundation
import MatrixRustSDK
private class RoomTimelineListener: TimelineListener {
let itemsUpdatePublisher = PassthroughSubject<TimelineDiff, Never>()
func onUpdate(update: TimelineDiff) {
itemsUpdatePublisher.send(update)
}
}
class RoomTimelineProvider: RoomTimelineProviderProtocol {
private let roomProxy: RoomProxyProtocol
private var cancellables = Set<AnyCancellable>()
@ -48,21 +40,21 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider", qos: .utility)
itemProxies = []
Task {
let roomTimelineListener = RoomTimelineListener()
roomTimelineListener
.itemsUpdatePublisher
Task { @MainActor in
roomProxy
.updatesPublisher
.collect(.byTime(serialDispatchQueue, 0.1))
.sink { [weak self] in self?.updateItemsWithDiffs($0) }
.store(in: &cancellables)
switch await roomProxy.addTimelineListener(listener: roomTimelineListener) {
case .success(let items):
switch roomProxy.registerTimelineListenerIfNeeded() {
case let .success(items):
itemProxies = items.map(TimelineItemProxy.init)
MXLog.info("Added timeline listener, current items (\(items.count)) : \(items.map(\.debugIdentifier))")
case .failure(.roomListenerAlreadyRegistered):
MXLog.info("Listener already registered for the room: \(roomProxy.id)")
case .failure:
let roomID = await roomProxy.id
let roomID = roomProxy.id
MXLog.error("Failed adding timeline listener on room with identifier: \(roomID)")
}
}

View File

@ -214,4 +214,9 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
await Task.yield()
XCTAssertTrue(callbackCorrectlyCalled)
}
func testRoomSubscription() async {
await context.nextViewState()
XCTAssertEqual(roomProxyMock.registerTimelineListenerIfNeededCallsCount, 1)
}
}

View File

@ -35,7 +35,7 @@ class RoomScreenViewModelTests: XCTestCase {
timelineController.timelineItems = items
let viewModel = RoomScreenViewModel(timelineController: timelineController,
mediaProvider: MockMediaProvider(),
roomName: nil)
roomProxy: RoomProxyMock(with: .init(displayName: "")))
// Then the messages should be grouped together.
XCTAssertEqual(viewModel.state.items[0].timelineGroupStyle, .first, "Nothing should prevent the first message from being grouped.")
@ -65,7 +65,7 @@ class RoomScreenViewModelTests: XCTestCase {
timelineController.timelineItems = items
let viewModel = RoomScreenViewModel(timelineController: timelineController,
mediaProvider: MockMediaProvider(),
roomName: nil)
roomProxy: RoomProxyMock(with: .init(displayName: "")))
// Then the messages should be grouped by sender.
XCTAssertEqual(viewModel.state.items[0].timelineGroupStyle, .single, "A message should not be grouped when the sender changes.")
@ -93,7 +93,7 @@ class RoomScreenViewModelTests: XCTestCase {
timelineController.timelineItems = items
let viewModel = RoomScreenViewModel(timelineController: timelineController,
mediaProvider: MockMediaProvider(),
roomName: nil)
roomProxy: RoomProxyMock(with: .init(displayName: "")))
// Then the first message should not be grouped but the other two should.
XCTAssertEqual(viewModel.state.items[0].timelineGroupStyle, .single, "When the first message has reactions it should not be grouped.")
@ -118,7 +118,7 @@ class RoomScreenViewModelTests: XCTestCase {
timelineController.timelineItems = items
let viewModel = RoomScreenViewModel(timelineController: timelineController,
mediaProvider: MockMediaProvider(),
roomName: nil)
roomProxy: RoomProxyMock(with: .init(displayName: "")))
// Then the first and second messages should be grouped and the last one should not.
XCTAssertEqual(viewModel.state.items[0].timelineGroupStyle, .first, "Nothing should prevent the first message from being grouped.")
@ -143,7 +143,7 @@ class RoomScreenViewModelTests: XCTestCase {
timelineController.timelineItems = items
let viewModel = RoomScreenViewModel(timelineController: timelineController,
mediaProvider: MockMediaProvider(),
roomName: nil)
roomProxy: RoomProxyMock(with: .init(displayName: "")))
// Then the messages should be grouped together.
XCTAssertEqual(viewModel.state.items[0].timelineGroupStyle, .first, "Nothing should prevent the first message from being grouped.")