mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 15:45:11 +00:00
Implement support for ElementCall through Rust side widgets (#1906)
* Implement support for ElementCall through Rust side widgets * Add Element Call feature flag * Fix the unit tests * Address PR comments
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
03D684A3AE85A23B3DA3B43F /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26747B3154A5DBC3A7E24A5 /* Image.swift */; };
|
03D684A3AE85A23B3DA3B43F /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26747B3154A5DBC3A7E24A5 /* Image.swift */; };
|
||||||
0437765FF480249486893CC7 /* ScreenTrackerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */; };
|
0437765FF480249486893CC7 /* ScreenTrackerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */; };
|
||||||
044DD8F80231BC30570F7965 /* UserDiscoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AAD845E53B0C8B5E0812C2 /* UserDiscoveryService.swift */; };
|
044DD8F80231BC30570F7965 /* UserDiscoveryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AAD845E53B0C8B5E0812C2 /* UserDiscoveryService.swift */; };
|
||||||
|
04778AA4D6AD2E153D7AAFF2 /* CallScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */; };
|
||||||
04A16B45228F7678A027C079 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 422724361B6555364C43281E /* RoomHeaderView.swift */; };
|
04A16B45228F7678A027C079 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 422724361B6555364C43281E /* RoomHeaderView.swift */; };
|
||||||
04F17DE71A50206336749BAC /* UserPreferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */; };
|
04F17DE71A50206336749BAC /* UserPreferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */; };
|
||||||
059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; };
|
059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; };
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A057F2FDC14866C3026A89A4 /* NotificationManagerProtocol.swift */; };
|
06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A057F2FDC14866C3026A89A4 /* NotificationManagerProtocol.swift */; };
|
||||||
071A017E415AD378F2961B11 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 227AC5D71A4CE43512062243 /* URL.swift */; };
|
071A017E415AD378F2961B11 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 227AC5D71A4CE43512062243 /* URL.swift */; };
|
||||||
07756D532EFE33DD1FA258E5 /* GeoURITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */; };
|
07756D532EFE33DD1FA258E5 /* GeoURITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */; };
|
||||||
|
07CC13C5729C24255348CBBD /* ElementCallWidgetDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 309AD8BAE6437C31BA7157BF /* ElementCallWidgetDriver.swift */; };
|
||||||
086D01E79C8E8D3F004FAF21 /* AudioPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC9104846487244648D32C6D /* AudioPlayerProtocol.swift */; };
|
086D01E79C8E8D3F004FAF21 /* AudioPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC9104846487244648D32C6D /* AudioPlayerProtocol.swift */; };
|
||||||
08CB4BD12CEEDE6AAE4A18DD /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035177BCD8E8308B098AC3C2 /* WindowManager.swift */; };
|
08CB4BD12CEEDE6AAE4A18DD /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035177BCD8E8308B098AC3C2 /* WindowManager.swift */; };
|
||||||
095C0ACFC234E0550A6404C5 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */; };
|
095C0ACFC234E0550A6404C5 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */; };
|
||||||
@@ -179,10 +181,12 @@
|
|||||||
352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; };
|
352C439BE0F75E101EF11FB1 /* RoomScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */; };
|
||||||
355B11D08CE0CEF97A813236 /* AppRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A9E3FBE8A66B5A17AD7F74 /* AppRoutes.swift */; };
|
355B11D08CE0CEF97A813236 /* AppRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A9E3FBE8A66B5A17AD7F74 /* AppRoutes.swift */; };
|
||||||
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
35E975CFDA60E05362A7CF79 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 1222DB76B917EB8A55365BA5 /* target.yml */; };
|
||||||
|
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */; };
|
||||||
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */; };
|
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */; };
|
||||||
36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */; };
|
36AC963F2F04069B7FF1AA0C /* UIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */; };
|
||||||
36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; };
|
36AD4DD4C798E22584ED3200 /* Emojibase in Frameworks */ = {isa = PBXBuildFile; productRef = C05729B1684C331F5FFE9232 /* Emojibase */; };
|
||||||
36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; };
|
36CD6E11B37396E14F032CB6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; };
|
||||||
|
370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */; };
|
||||||
377980ABF16525114E72DDE2 /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = 2B9ACE4FCACB5A8812154424 /* Version */; };
|
377980ABF16525114E72DDE2 /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = 2B9ACE4FCACB5A8812154424 /* Version */; };
|
||||||
37D789F24199B32E3FD1AA7B /* FileRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.swift */; };
|
37D789F24199B32E3FD1AA7B /* FileRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.swift */; };
|
||||||
383055C6ABE5BE058CEE1DDB /* WelcomeScreenScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FE5EF0AFFE360C66420AAE /* WelcomeScreenScreenCoordinator.swift */; };
|
383055C6ABE5BE058CEE1DDB /* WelcomeScreenScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FE5EF0AFFE360C66420AAE /* WelcomeScreenScreenCoordinator.swift */; };
|
||||||
@@ -193,6 +197,7 @@
|
|||||||
3982C505960006B341CFD0C6 /* UserDetailsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */; };
|
3982C505960006B341CFD0C6 /* UserDetailsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */; };
|
||||||
3982E60F9C126437D5E488A3 /* PillContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A6314FDC51DA25712D9A81 /* PillContextTests.swift */; };
|
3982E60F9C126437D5E488A3 /* PillContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A6314FDC51DA25712D9A81 /* PillContextTests.swift */; };
|
||||||
39929D29B265C3F6606047DE /* AlignedScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8872E9C5E91E9F2BFC4EBCCA /* AlignedScrollView.swift */; };
|
39929D29B265C3F6606047DE /* AlignedScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8872E9C5E91E9F2BFC4EBCCA /* AlignedScrollView.swift */; };
|
||||||
|
39A987B3E41B976D1DF944C6 /* CallScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */; };
|
||||||
3A08584ECDD4A4541DBF21F8 /* EmojiLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 201305507D7DFD16E544563A /* EmojiLoaderProtocol.swift */; };
|
3A08584ECDD4A4541DBF21F8 /* EmojiLoaderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 201305507D7DFD16E544563A /* EmojiLoaderProtocol.swift */; };
|
||||||
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */; };
|
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */; };
|
||||||
3A5BD701D1AC916AC534F52C /* OnboardingScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB26F24164E9461B2054D0B3 /* OnboardingScreenModels.swift */; };
|
3A5BD701D1AC916AC534F52C /* OnboardingScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB26F24164E9461B2054D0B3 /* OnboardingScreenModels.swift */; };
|
||||||
@@ -362,6 +367,7 @@
|
|||||||
6AD722DD92E465E56D2885AB /* BugReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */; };
|
6AD722DD92E465E56D2885AB /* BugReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */; };
|
||||||
6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */; };
|
6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */; };
|
||||||
6B4BF4A6450F55939B49FAEF /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67779D9A1B797285A09B7720 /* PollOptionView.swift */; };
|
6B4BF4A6450F55939B49FAEF /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67779D9A1B797285A09B7720 /* PollOptionView.swift */; };
|
||||||
|
6BAD956B909A6E29F6CC6E7C /* ButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */; };
|
||||||
6BB6944443C421C722ED1E7D /* portrait_test_video.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */; };
|
6BB6944443C421C722ED1E7D /* portrait_test_video.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */; };
|
||||||
6C34237AFB808E38FC8776B9 /* RoomStateEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */; };
|
6C34237AFB808E38FC8776B9 /* RoomStateEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */; };
|
||||||
6C5A2C454E6C198AB39ED760 /* SharedUserDefaultsKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */; };
|
6C5A2C454E6C198AB39ED760 /* SharedUserDefaultsKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */; };
|
||||||
@@ -394,6 +400,7 @@
|
|||||||
754602A7B2AAD443C4228ED4 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 7731767AE437BA3BD2CC14A8 /* Sentry */; };
|
754602A7B2AAD443C4228ED4 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 7731767AE437BA3BD2CC14A8 /* Sentry */; };
|
||||||
755727E0B756430DFFEC4732 /* SessionVerificationViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF05DA24F71B455E8EFEBC3B /* SessionVerificationViewModelTests.swift */; };
|
755727E0B756430DFFEC4732 /* SessionVerificationViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF05DA24F71B455E8EFEBC3B /* SessionVerificationViewModelTests.swift */; };
|
||||||
762DAF94846C7AC8550F1CC1 /* MediaPlayerProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */; };
|
762DAF94846C7AC8550F1CC1 /* MediaPlayerProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */; };
|
||||||
|
763D69741D58D2B650BC1FC9 /* CallScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37FA1A5D55633E1942B153B /* CallScreenCoordinator.swift */; };
|
||||||
764AFCC225B044CF5F9B41E5 /* PaginationIndicatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEA67A6796BDC2761619C5 /* PaginationIndicatorRoomTimelineView.swift */; };
|
764AFCC225B044CF5F9B41E5 /* PaginationIndicatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEA67A6796BDC2761619C5 /* PaginationIndicatorRoomTimelineView.swift */; };
|
||||||
767D366C40F1311CFA333763 /* PillContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86376BEE425704AEE197CA54 /* PillContext.swift */; };
|
767D366C40F1311CFA333763 /* PillContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86376BEE425704AEE197CA54 /* PillContext.swift */; };
|
||||||
76BA28216FBAF83B2D86A027 /* InvitesScreenCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2A71915C1F075E403F559C /* InvitesScreenCell.swift */; };
|
76BA28216FBAF83B2D86A027 /* InvitesScreenCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2A71915C1F075E403F559C /* InvitesScreenCell.swift */; };
|
||||||
@@ -442,6 +449,7 @@
|
|||||||
8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9227F7495DA43324050A863 /* TextBasedRoomTimelineItem.swift */; };
|
8317E1314C00DCCC99D30DA8 /* TextBasedRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9227F7495DA43324050A863 /* TextBasedRoomTimelineItem.swift */; };
|
||||||
83A4DAB181C56987C3E804FF /* MapTilerStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B9F5BC4C80543DE7228B9D /* MapTilerStyle.swift */; };
|
83A4DAB181C56987C3E804FF /* MapTilerStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B9F5BC4C80543DE7228B9D /* MapTilerStyle.swift */; };
|
||||||
84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A8E19C4645D3F5F9FB02355 /* UnitTestsAppCoordinator.swift */; };
|
84226AD2E1F1FBC965F3B09E /* UnitTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A8E19C4645D3F5F9FB02355 /* UnitTestsAppCoordinator.swift */; };
|
||||||
|
84CAE3E96D93194DA06B9194 /* CallScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD9AD6AE5FC868962F090740 /* CallScreenViewModelProtocol.swift */; };
|
||||||
84EFCB95F9DA2979C8042B26 /* UITestsSignalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */; };
|
84EFCB95F9DA2979C8042B26 /* UITestsSignalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */; };
|
||||||
8544657DEEE717ED2E22E382 /* RoomNotificationSettingsProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */; };
|
8544657DEEE717ED2E22E382 /* RoomNotificationSettingsProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D1BAA90F3A073D91B4F16B /* RoomNotificationSettingsProxyMock.swift */; };
|
||||||
854E82E064BA53CD0BC45600 /* LocationRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6613DE16AD26B3A74DA1F5 /* LocationRoomTimelineItemContent.swift */; };
|
854E82E064BA53CD0BC45600 /* LocationRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6613DE16AD26B3A74DA1F5 /* LocationRoomTimelineItemContent.swift */; };
|
||||||
@@ -644,6 +652,7 @@
|
|||||||
B717A820BE02C6FE2CB53F6E /* WaitlistScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B697816AF93DA06EC58C5D70 /* WaitlistScreenViewModelProtocol.swift */; };
|
B717A820BE02C6FE2CB53F6E /* WaitlistScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B697816AF93DA06EC58C5D70 /* WaitlistScreenViewModelProtocol.swift */; };
|
||||||
B721125D17A0BA86794F29FB /* MockServerSelectionScreenState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E057FB1F07A5C201C89061 /* MockServerSelectionScreenState.swift */; };
|
B721125D17A0BA86794F29FB /* MockServerSelectionScreenState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E057FB1F07A5C201C89061 /* MockServerSelectionScreenState.swift */; };
|
||||||
B796A25F282C0A340D1B9C12 /* ImageRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B5EDCD05D50BA9B815C66C /* ImageRoomTimelineItemContent.swift */; };
|
B796A25F282C0A340D1B9C12 /* ImageRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B5EDCD05D50BA9B815C66C /* ImageRoomTimelineItemContent.swift */; };
|
||||||
|
B7C9E07F4F9CCC8DD7156A20 /* CallScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28146817C61423CACCF942F5 /* CallScreenModels.swift */; };
|
||||||
B828C600A54B2EE20871A451 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD700E035C85738EE4B97129 /* PerformanceTests.swift */; };
|
B828C600A54B2EE20871A451 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD700E035C85738EE4B97129 /* PerformanceTests.swift */; };
|
||||||
B879446FD8E65A711EF8F9F7 /* AdvancedSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */; };
|
B879446FD8E65A711EF8F9F7 /* AdvancedSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */; };
|
||||||
B89990DD875B0B603D4D4332 /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; };
|
B89990DD875B0B603D4D4332 /* NotificationItemProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B927CF5EF7FCCDA5EDC474B /* NotificationItemProxyProtocol.swift */; };
|
||||||
@@ -733,6 +742,7 @@
|
|||||||
D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */; };
|
D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */; };
|
||||||
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */; };
|
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */; };
|
||||||
D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23AA3F4B285570805CB0CCDD /* MapTiler.swift */; };
|
D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23AA3F4B285570805CB0CCDD /* MapTiler.swift */; };
|
||||||
|
D19A748E95E2FAB2940570F0 /* CallScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4103AB4340F2974D690A12A /* CallScreen.swift */; };
|
||||||
D1DFECA12FBF5346EAC4EE92 /* WaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A931ECBDC32FC90A6480751F /* WaveformView.swift */; };
|
D1DFECA12FBF5346EAC4EE92 /* WaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A931ECBDC32FC90A6480751F /* WaveformView.swift */; };
|
||||||
D1EEF0CB0F5D9C15E224E670 /* landscape_test_video.mov in Resources */ = {isa = PBXBuildFile; fileRef = 9A2AC7BE17C05CF7D2A22338 /* landscape_test_video.mov */; };
|
D1EEF0CB0F5D9C15E224E670 /* landscape_test_video.mov in Resources */ = {isa = PBXBuildFile; fileRef = 9A2AC7BE17C05CF7D2A22338 /* landscape_test_video.mov */; };
|
||||||
D2A15D03F81342A09340BD56 /* AnalyticsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFEEE93B82937B2E86F92EB /* AnalyticsScreen.swift */; };
|
D2A15D03F81342A09340BD56 /* AnalyticsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFEEE93B82937B2E86F92EB /* AnalyticsScreen.swift */; };
|
||||||
@@ -1038,6 +1048,7 @@
|
|||||||
1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreen.swift; sourceTree = "<group>"; };
|
1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreen.swift; sourceTree = "<group>"; };
|
||||||
1D56469A9EE0CFA2B7BA9760 /* SessionVerificationControllerProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationControllerProxyProtocol.swift; sourceTree = "<group>"; };
|
1D56469A9EE0CFA2B7BA9760 /* SessionVerificationControllerProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationControllerProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
1D67E616BCA82D8A1258D488 /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
|
1D67E616BCA82D8A1258D488 /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
|
||||||
|
1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenUITests.swift; sourceTree = "<group>"; };
|
1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
1DFE0E493FB55E5A62E7852A /* ProposedViewSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProposedViewSize.swift; sourceTree = "<group>"; };
|
1DFE0E493FB55E5A62E7852A /* ProposedViewSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProposedViewSize.swift; sourceTree = "<group>"; };
|
||||||
@@ -1072,6 +1083,7 @@
|
|||||||
27B8315A340B46F98B9C5AF0 /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = "<group>"; };
|
27B8315A340B46F98B9C5AF0 /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = "<group>"; };
|
||||||
27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenModels.swift; sourceTree = "<group>"; };
|
27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenModels.swift; sourceTree = "<group>"; };
|
||||||
27EA0F71A3A400A202E15318 /* CreatePollScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreen.swift; sourceTree = "<group>"; };
|
27EA0F71A3A400A202E15318 /* CreatePollScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreen.swift; sourceTree = "<group>"; };
|
||||||
|
28146817C61423CACCF942F5 /* CallScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenModels.swift; sourceTree = "<group>"; };
|
||||||
283974987DA7EC61D2AB57D9 /* VoiceMessageCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageCacheTests.swift; sourceTree = "<group>"; };
|
283974987DA7EC61D2AB57D9 /* VoiceMessageCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageCacheTests.swift; sourceTree = "<group>"; };
|
||||||
287FC98AF2664EAD79C0D902 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
|
287FC98AF2664EAD79C0D902 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
|
||||||
28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||||
@@ -1091,6 +1103,7 @@
|
|||||||
2F36C5D9B37E50915ECBD3EE /* RoomMemberProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxy.swift; sourceTree = "<group>"; };
|
2F36C5D9B37E50915ECBD3EE /* RoomMemberProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxy.swift; sourceTree = "<group>"; };
|
||||||
2FD0E68C42CA7DDCD4CAD68D /* MentionSuggestionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSuggestionItemView.swift; sourceTree = "<group>"; };
|
2FD0E68C42CA7DDCD4CAD68D /* MentionSuggestionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSuggestionItemView.swift; sourceTree = "<group>"; };
|
||||||
303FCADE77DF1F3670C086ED /* BugReportScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModel.swift; sourceTree = "<group>"; };
|
303FCADE77DF1F3670C086ED /* BugReportScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
309AD8BAE6437C31BA7157BF /* ElementCallWidgetDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriver.swift; sourceTree = "<group>"; };
|
||||||
30ED584467DB380E3CEFB1DB /* NotificationManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManagerTests.swift; sourceTree = "<group>"; };
|
30ED584467DB380E3CEFB1DB /* NotificationManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManagerTests.swift; sourceTree = "<group>"; };
|
||||||
314F1C79850BE46E8ABEAFCB /* ReadReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceipt.swift; sourceTree = "<group>"; };
|
314F1C79850BE46E8ABEAFCB /* ReadReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceipt.swift; sourceTree = "<group>"; };
|
||||||
31A6314FDC51DA25712D9A81 /* PillContextTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContextTests.swift; sourceTree = "<group>"; };
|
31A6314FDC51DA25712D9A81 /* PillContextTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillContextTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -1112,6 +1125,7 @@
|
|||||||
36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; };
|
36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = "<group>"; };
|
||||||
376D941BF8BB294389C0DE24 /* MapTilerURLBuildersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerURLBuildersTests.swift; sourceTree = "<group>"; };
|
376D941BF8BB294389C0DE24 /* MapTilerURLBuildersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerURLBuildersTests.swift; sourceTree = "<group>"; };
|
||||||
37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItem.swift; sourceTree = "<group>"; };
|
37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItem.swift; sourceTree = "<group>"; };
|
||||||
|
37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringTests.swift; sourceTree = "<group>"; };
|
37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringTests.swift; sourceTree = "<group>"; };
|
||||||
37E727F7E0BCE8A0BBFD33FF /* OnboardingScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenCoordinator.swift; sourceTree = "<group>"; };
|
37E727F7E0BCE8A0BBFD33FF /* OnboardingScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxyMock.swift; sourceTree = "<group>"; };
|
382B50F7E379B3DBBD174364 /* NotificationSettingsProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxyMock.swift; sourceTree = "<group>"; };
|
||||||
@@ -1370,6 +1384,7 @@
|
|||||||
8AFCE895ECFFA53FEE64D62B /* MediaLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoader.swift; sourceTree = "<group>"; };
|
8AFCE895ECFFA53FEE64D62B /* MediaLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoader.swift; sourceTree = "<group>"; };
|
||||||
8BEBF0E59F25E842EDB6FD11 /* LocationSharingScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreenModels.swift; sourceTree = "<group>"; };
|
8BEBF0E59F25E842EDB6FD11 /* LocationSharingScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSharingScreenModels.swift; sourceTree = "<group>"; };
|
||||||
8C8616254EE40CA8BA5E9BC2 /* VideoRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
8C8616254EE40CA8BA5E9BC2 /* VideoRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItemContent.swift; sourceTree = "<group>"; };
|
||||||
|
8CC23C63849452BC86EA2852 /* ButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonStyle.swift; sourceTree = "<group>"; };
|
||||||
8D168471461717AF5689F64B /* OnboardingScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenUITests.swift; sourceTree = "<group>"; };
|
8D168471461717AF5689F64B /* OnboardingScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
|
8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
|
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
@@ -1446,6 +1461,7 @@
|
|||||||
A5DDF245FA51CF75F89E58A4 /* CreatePollScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreenUITests.swift; sourceTree = "<group>"; };
|
A5DDF245FA51CF75F89E58A4 /* CreatePollScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePollScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
A65F140F9FE5E8D4DAEFF354 /* RoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxy.swift; sourceTree = "<group>"; };
|
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>"; };
|
A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = "<group>"; };
|
||||||
|
A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = "<group>"; };
|
||||||
A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; };
|
A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = "<group>"; };
|
||||||
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
|
A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
|
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
@@ -1468,6 +1484,7 @@
|
|||||||
ACCC1874C122E2BBE648B8F5 /* LegalInformationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenUITests.swift; sourceTree = "<group>"; };
|
ACCC1874C122E2BBE648B8F5 /* LegalInformationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
AD378D580A41E42560C60E9C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
AD378D580A41E42560C60E9C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxy.swift; sourceTree = "<group>"; };
|
AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxy.swift; sourceTree = "<group>"; };
|
||||||
|
AD9AD6AE5FC868962F090740 /* CallScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
AD9CB3B9DFA353AB2B7CD9F8 /* NotificationSettingsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenCoordinator.swift; sourceTree = "<group>"; };
|
AD9CB3B9DFA353AB2B7CD9F8 /* NotificationSettingsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
ADB35E2DB4EFE8E6F3959629 /* InviteUsersScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenUITests.swift; sourceTree = "<group>"; };
|
ADB35E2DB4EFE8E6F3959629 /* InviteUsersScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; };
|
ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
@@ -1578,6 +1595,7 @@
|
|||||||
CA89A2DD51B6BBE1DA55E263 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
CA89A2DD51B6BBE1DA55E263 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
|
||||||
CA90BD288E5AE6BC643AFDDF /* TemplateScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenCoordinator.swift; sourceTree = "<group>"; };
|
CA90BD288E5AE6BC643AFDDF /* TemplateScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
CACA846B3E3E9A521D98B178 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
CACA846B3E3E9A521D98B178 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
CB26F24164E9461B2054D0B3 /* OnboardingScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenModels.swift; sourceTree = "<group>"; };
|
CB26F24164E9461B2054D0B3 /* OnboardingScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreenModels.swift; sourceTree = "<group>"; };
|
||||||
CB8D34E94AB07128DB73D6C7 /* PillConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillConstants.swift; sourceTree = "<group>"; };
|
CB8D34E94AB07128DB73D6C7 /* PillConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillConstants.swift; sourceTree = "<group>"; };
|
||||||
CBBCC6E74774E79B599625D0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
CBBCC6E74774E79B599625D0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
@@ -1656,6 +1674,7 @@
|
|||||||
E3059CFA00C67D8787273B20 /* ServerSelectionScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModel.swift; sourceTree = "<group>"; };
|
E3059CFA00C67D8787273B20 /* ServerSelectionScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
|
E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
|
||||||
E3B97591B2D3D4D67553506D /* AnalyticsClientProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsClientProtocol.swift; sourceTree = "<group>"; };
|
E3B97591B2D3D4D67553506D /* AnalyticsClientProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsClientProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
E4103AB4340F2974D690A12A /* CallScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreen.swift; sourceTree = "<group>"; };
|
||||||
E413F4CBD7BF0588F394A9DD /* RoomDetailsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModel.swift; sourceTree = "<group>"; };
|
E413F4CBD7BF0588F394A9DD /* RoomDetailsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
E43005941B3A2C9671E23C85 /* UserIndicatorModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorModalView.swift; sourceTree = "<group>"; };
|
E43005941B3A2C9671E23C85 /* UserIndicatorModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorModalView.swift; sourceTree = "<group>"; };
|
||||||
E44928D844E16EE48A311FCA /* ComposerToolbarViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModelProtocol.swift; sourceTree = "<group>"; };
|
E44928D844E16EE48A311FCA /* ComposerToolbarViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -1707,6 +1726,7 @@
|
|||||||
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
|
F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = "<group>"; };
|
||||||
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
|
F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = "<group>"; };
|
F36C0A6D59717193F49EA986 /* UserSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionTests.swift; sourceTree = "<group>"; };
|
||||||
|
F37FA1A5D55633E1942B153B /* CallScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||||
F3BC2D3573D900A9C9F8C191 /* HomeScreenUserMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenUserMenuButton.swift; sourceTree = "<group>"; };
|
F3BC2D3573D900A9C9F8C191 /* HomeScreenUserMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenUserMenuButton.swift; sourceTree = "<group>"; };
|
||||||
F3BC6BBEAF640C64C10C0340 /* CompletionSuggestionServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionServiceProtocol.swift; sourceTree = "<group>"; };
|
F3BC6BBEAF640C64C10C0340 /* CompletionSuggestionServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionServiceProtocol.swift; sourceTree = "<group>"; };
|
||||||
F3EAE3E9D5EF4A6D5D9C6CFD /* EmojiPickerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModel.swift; sourceTree = "<group>"; };
|
F3EAE3E9D5EF4A6D5D9C6CFD /* EmojiPickerScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModel.swift; sourceTree = "<group>"; };
|
||||||
@@ -1930,6 +1950,7 @@
|
|||||||
0ED3F5C21537519389C07644 /* BugReport */,
|
0ED3F5C21537519389C07644 /* BugReport */,
|
||||||
8039515BAA53B7C3275AC64A /* Client */,
|
8039515BAA53B7C3275AC64A /* Client */,
|
||||||
8C3BAE06B336D97DABBE2509 /* CreateRoom */,
|
8C3BAE06B336D97DABBE2509 /* CreateRoom */,
|
||||||
|
92E99C57D7F92ED16F73282C /* ElementCall */,
|
||||||
39557ADF21345E18F3865B9E /* Emojis */,
|
39557ADF21345E18F3865B9E /* Emojis */,
|
||||||
CA555F7C7CA382ACACF0D82B /* Keychain */,
|
CA555F7C7CA382ACACF0D82B /* Keychain */,
|
||||||
79E560F5113ED25D172E550C /* Media */,
|
79E560F5113ED25D172E550C /* Media */,
|
||||||
@@ -1998,6 +2019,14 @@
|
|||||||
path = ViewModel;
|
path = ViewModel;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
109C9345160DC608877BD25C /* View */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E4103AB4340F2974D690A12A /* CallScreen.swift */,
|
||||||
|
);
|
||||||
|
path = View;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
114DC16B28140F885FD833E2 /* NotificationSettings */ = {
|
114DC16B28140F885FD833E2 /* NotificationSettings */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -2011,6 +2040,18 @@
|
|||||||
path = NotificationSettings;
|
path = NotificationSettings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
1185EECDD07495D65AC84AFC /* CallScreen */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F37FA1A5D55633E1942B153B /* CallScreenCoordinator.swift */,
|
||||||
|
28146817C61423CACCF942F5 /* CallScreenModels.swift */,
|
||||||
|
37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */,
|
||||||
|
AD9AD6AE5FC868962F090740 /* CallScreenViewModelProtocol.swift */,
|
||||||
|
109C9345160DC608877BD25C /* View */,
|
||||||
|
);
|
||||||
|
path = CallScreen;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
13ACE3300D6A86770E757FC0 /* View */ = {
|
13ACE3300D6A86770E757FC0 /* View */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -2217,6 +2258,7 @@
|
|||||||
children = (
|
children = (
|
||||||
8F21ED7205048668BEB44A38 /* AppActivityView.swift */,
|
8F21ED7205048668BEB44A38 /* AppActivityView.swift */,
|
||||||
CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */,
|
CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */,
|
||||||
|
8CC23C63849452BC86EA2852 /* ButtonStyle.swift */,
|
||||||
0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */,
|
0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */,
|
||||||
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */,
|
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */,
|
||||||
C352359663A0E52BA20761EE /* LoadableImage.swift */,
|
C352359663A0E52BA20761EE /* LoadableImage.swift */,
|
||||||
@@ -2867,6 +2909,7 @@
|
|||||||
6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */,
|
6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */,
|
||||||
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
|
||||||
7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */,
|
7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */,
|
||||||
|
CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */,
|
||||||
D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */,
|
D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */,
|
||||||
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
|
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
|
||||||
3EB1D0C69FEDD93404DF927E /* CreatePollScreenViewModelTests.swift */,
|
3EB1D0C69FEDD93404DF927E /* CreatePollScreenViewModelTests.swift */,
|
||||||
@@ -3297,6 +3340,15 @@
|
|||||||
path = View;
|
path = View;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
92E99C57D7F92ED16F73282C /* ElementCall */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
309AD8BAE6437C31BA7157BF /* ElementCallWidgetDriver.swift */,
|
||||||
|
A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */,
|
||||||
|
);
|
||||||
|
path = ElementCall;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
93F4D089C78719B688D576ED /* WelcomeScreenScreen */ = {
|
93F4D089C78719B688D576ED /* WelcomeScreenScreen */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -3339,6 +3391,7 @@
|
|||||||
349C633291427A0F29C28C54 /* AppLockScreenUITests.swift */,
|
349C633291427A0F29C28C54 /* AppLockScreenUITests.swift */,
|
||||||
5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */,
|
5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */,
|
||||||
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */,
|
C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */,
|
||||||
|
1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */,
|
||||||
A5DDF245FA51CF75F89E58A4 /* CreatePollScreenUITests.swift */,
|
A5DDF245FA51CF75F89E58A4 /* CreatePollScreenUITests.swift */,
|
||||||
F8CEB4634C0DD7779C4AB504 /* CreateRoomScreenUITests.swift */,
|
F8CEB4634C0DD7779C4AB504 /* CreateRoomScreenUITests.swift */,
|
||||||
3F684BDD23ECEADB3053BA5A /* DeveloperOptionsScreenUITests.swift */,
|
3F684BDD23ECEADB3053BA5A /* DeveloperOptionsScreenUITests.swift */,
|
||||||
@@ -3987,6 +4040,7 @@
|
|||||||
77566988A0A4F94744C3818B /* AppLockScreen */,
|
77566988A0A4F94744C3818B /* AppLockScreen */,
|
||||||
E74CD7681375AD2EAA34D66B /* Authentication */,
|
E74CD7681375AD2EAA34D66B /* Authentication */,
|
||||||
53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */,
|
53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */,
|
||||||
|
1185EECDD07495D65AC84AFC /* CallScreen */,
|
||||||
27F2500AC8736AAE774520C0 /* ComposerToolbar */,
|
27F2500AC8736AAE774520C0 /* ComposerToolbar */,
|
||||||
90DC2E28718955ED87AD1456 /* CreatePollScreen */,
|
90DC2E28718955ED87AD1456 /* CreatePollScreen */,
|
||||||
C18958141C8ED6D778F779A4 /* CreateRoom */,
|
C18958141C8ED6D778F779A4 /* CreateRoom */,
|
||||||
@@ -4688,6 +4742,7 @@
|
|||||||
0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */,
|
0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */,
|
||||||
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
|
||||||
C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */,
|
C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */,
|
||||||
|
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */,
|
||||||
B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */,
|
B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */,
|
||||||
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */,
|
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */,
|
||||||
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
|
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
|
||||||
@@ -4864,6 +4919,12 @@
|
|||||||
3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */,
|
3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */,
|
||||||
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */,
|
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */,
|
||||||
E1DF24D085572A55C9758A2D /* Bundle.swift in Sources */,
|
E1DF24D085572A55C9758A2D /* Bundle.swift in Sources */,
|
||||||
|
6BAD956B909A6E29F6CC6E7C /* ButtonStyle.swift in Sources */,
|
||||||
|
D19A748E95E2FAB2940570F0 /* CallScreen.swift in Sources */,
|
||||||
|
763D69741D58D2B650BC1FC9 /* CallScreenCoordinator.swift in Sources */,
|
||||||
|
B7C9E07F4F9CCC8DD7156A20 /* CallScreenModels.swift in Sources */,
|
||||||
|
39A987B3E41B976D1DF944C6 /* CallScreenViewModel.swift in Sources */,
|
||||||
|
84CAE3E96D93194DA06B9194 /* CallScreenViewModelProtocol.swift in Sources */,
|
||||||
BB6BF528BC7F5B87E08C4F18 /* CameraPicker.swift in Sources */,
|
BB6BF528BC7F5B87E08C4F18 /* CameraPicker.swift in Sources */,
|
||||||
E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */,
|
E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */,
|
||||||
6A0E7551E0D1793245F34CDD /* ClientError.swift in Sources */,
|
6A0E7551E0D1793245F34CDD /* ClientError.swift in Sources */,
|
||||||
@@ -4914,6 +4975,8 @@
|
|||||||
2955F4C160CFD7794D819C64 /* EffectsScene.swift in Sources */,
|
2955F4C160CFD7794D819C64 /* EffectsScene.swift in Sources */,
|
||||||
AE1160076F663BF14E0E893A /* EffectsView.swift in Sources */,
|
AE1160076F663BF14E0E893A /* EffectsView.swift in Sources */,
|
||||||
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */,
|
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */,
|
||||||
|
07CC13C5729C24255348CBBD /* ElementCallWidgetDriver.swift in Sources */,
|
||||||
|
370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */,
|
||||||
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */,
|
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */,
|
||||||
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
|
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
|
||||||
7361B011A79BF723D8C9782B /* EmojiCategory.swift in Sources */,
|
7361B011A79BF723D8C9782B /* EmojiCategory.swift in Sources */,
|
||||||
@@ -5399,6 +5462,7 @@
|
|||||||
ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */,
|
ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */,
|
||||||
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */,
|
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */,
|
||||||
94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */,
|
94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */,
|
||||||
|
04778AA4D6AD2E153D7AAFF2 /* CallScreenUITests.swift in Sources */,
|
||||||
5E415EF9A5D31B1690CE27F5 /* CreatePollScreenUITests.swift in Sources */,
|
5E415EF9A5D31B1690CE27F5 /* CreatePollScreenUITests.swift in Sources */,
|
||||||
9F19096BFA629C0AC282B1E4 /* CreateRoomScreenUITests.swift in Sources */,
|
9F19096BFA629C0AC282B1E4 /* CreateRoomScreenUITests.swift in Sources */,
|
||||||
C1F863E16BDBC87255D23B57 /* DeveloperOptionsScreenUITests.swift in Sources */,
|
C1F863E16BDBC87255D23B57 /* DeveloperOptionsScreenUITests.swift in Sources */,
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ final class AppSettings {
|
|||||||
case voiceMessageEnabled
|
case voiceMessageEnabled
|
||||||
case mentionsEnabled
|
case mentionsEnabled
|
||||||
case appLockFlowEnabled
|
case appLockFlowEnabled
|
||||||
|
case elementCallEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||||
@@ -203,6 +204,10 @@ final class AppSettings {
|
|||||||
@UserPreference(key: UserDefaultsKeys.richTextEditorEnabled, defaultValue: true, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.richTextEditorEnabled, defaultValue: true, storageType: .userDefaults(store))
|
||||||
var richTextEditorEnabled
|
var richTextEditorEnabled
|
||||||
|
|
||||||
|
// MARK: - Element Call
|
||||||
|
|
||||||
|
let elementCallBaseURL: URL = "https://call.element.io"
|
||||||
|
|
||||||
// MARK: - Notifications
|
// MARK: - Notifications
|
||||||
|
|
||||||
@UserPreference(key: UserDefaultsKeys.enableNotifications, defaultValue: true, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.enableNotifications, defaultValue: true, storageType: .userDefaults(store))
|
||||||
@@ -261,4 +266,7 @@ final class AppSettings {
|
|||||||
|
|
||||||
@UserPreference(key: UserDefaultsKeys.appLockFlowEnabled, defaultValue: false, storageType: .volatile)
|
@UserPreference(key: UserDefaultsKeys.appLockFlowEnabled, defaultValue: false, storageType: .volatile)
|
||||||
var appLockFlowEnabled
|
var appLockFlowEnabled
|
||||||
|
|
||||||
|
@UserPreference(key: UserDefaultsKeys.elementCallEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
|
var elementCallEnabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,20 @@ import UserNotifications
|
|||||||
enum RoomFlowCoordinatorAction: Equatable {
|
enum RoomFlowCoordinatorAction: Equatable {
|
||||||
case presentedRoom(String)
|
case presentedRoom(String)
|
||||||
case dismissedRoom
|
case dismissedRoom
|
||||||
|
case presentCallScreen(roomProxy: RoomProxyProtocol)
|
||||||
|
|
||||||
|
static func == (lhs: RoomFlowCoordinatorAction, rhs: RoomFlowCoordinatorAction) -> Bool {
|
||||||
|
switch (lhs, rhs) {
|
||||||
|
case (.presentedRoom(let lhsRoomID), .presentedRoom(let rhsRoomID)):
|
||||||
|
return lhsRoomID == rhsRoomID
|
||||||
|
case (.dismissedRoom, .dismissedRoom):
|
||||||
|
return true
|
||||||
|
case (.presentCallScreen(let lhsRoomProxy), .presentCallScreen(let rhsRoomProxy)):
|
||||||
|
return lhsRoomProxy.id == rhsRoomProxy.id
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||||
@@ -372,6 +386,12 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
stateMachine.tryEvent(.presentRoomMemberDetails(member: .init(value: member)))
|
stateMachine.tryEvent(.presentRoomMemberDetails(member: .init(value: member)))
|
||||||
case .presentMessageForwarding(let itemID):
|
case .presentMessageForwarding(let itemID):
|
||||||
stateMachine.tryEvent(.presentMessageForwarding(itemID: itemID))
|
stateMachine.tryEvent(.presentMessageForwarding(itemID: itemID))
|
||||||
|
case .presentCallScreen:
|
||||||
|
guard let roomProxy = self.roomProxy else {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
case .dismissedRoom:
|
case .dismissedRoom:
|
||||||
stateMachine.processEvent(.deselectRoom)
|
stateMachine.processEvent(.deselectRoom)
|
||||||
analytics.signpost.endRoomFlow()
|
analytics.signpost.endRoomFlow()
|
||||||
|
case .presentCallScreen(let roomProxy):
|
||||||
|
presentCallScreen(roomProxy: roomProxy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
@@ -453,4 +455,23 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
self?.stateMachine.processEvent(.closedInvitesScreen)
|
self?.stateMachine.processEvent(.closedInvitesScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Calls
|
||||||
|
|
||||||
|
private func presentCallScreen(roomProxy: RoomProxyProtocol) {
|
||||||
|
let callScreenCoordinator = CallScreenCoordinator(parameters: .init(roomProxy: roomProxy,
|
||||||
|
callBaseURL: appSettings.elementCallBaseURL,
|
||||||
|
clientID: InfoPlistReader.main.bundleIdentifier))
|
||||||
|
|
||||||
|
callScreenCoordinator.actions
|
||||||
|
.sink { [weak self] action in
|
||||||
|
switch action {
|
||||||
|
case .dismiss:
|
||||||
|
self?.navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
navigationSplitCoordinator.setSheetCoordinator(callScreenCoordinator, animated: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,6 +425,61 @@ class CompletionSuggestionServiceMock: CompletionSuggestionServiceProtocol {
|
|||||||
setSuggestionTriggerClosure?(suggestionTrigger)
|
setSuggestionTriggerClosure?(suggestionTrigger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class ElementCallWidgetDriverMock: ElementCallWidgetDriverProtocol {
|
||||||
|
var messagePublisher: PassthroughSubject<String, Never> {
|
||||||
|
get { return underlyingMessagePublisher }
|
||||||
|
set(value) { underlyingMessagePublisher = value }
|
||||||
|
}
|
||||||
|
var underlyingMessagePublisher: PassthroughSubject<String, Never>!
|
||||||
|
var actions: AnyPublisher<ElementCallWidgetDriverAction, Never> {
|
||||||
|
get { return underlyingActions }
|
||||||
|
set(value) { underlyingActions = value }
|
||||||
|
}
|
||||||
|
var underlyingActions: AnyPublisher<ElementCallWidgetDriverAction, Never>!
|
||||||
|
|
||||||
|
//MARK: - start
|
||||||
|
|
||||||
|
var startBaseURLClientIDCallsCount = 0
|
||||||
|
var startBaseURLClientIDCalled: Bool {
|
||||||
|
return startBaseURLClientIDCallsCount > 0
|
||||||
|
}
|
||||||
|
var startBaseURLClientIDReceivedArguments: (baseURL: URL, clientID: String)?
|
||||||
|
var startBaseURLClientIDReceivedInvocations: [(baseURL: URL, clientID: String)] = []
|
||||||
|
var startBaseURLClientIDReturnValue: Result<URL, ElementCallWidgetDriverError>!
|
||||||
|
var startBaseURLClientIDClosure: ((URL, String) async -> Result<URL, ElementCallWidgetDriverError>)?
|
||||||
|
|
||||||
|
func start(baseURL: URL, clientID: String) async -> Result<URL, ElementCallWidgetDriverError> {
|
||||||
|
startBaseURLClientIDCallsCount += 1
|
||||||
|
startBaseURLClientIDReceivedArguments = (baseURL: baseURL, clientID: clientID)
|
||||||
|
startBaseURLClientIDReceivedInvocations.append((baseURL: baseURL, clientID: clientID))
|
||||||
|
if let startBaseURLClientIDClosure = startBaseURLClientIDClosure {
|
||||||
|
return await startBaseURLClientIDClosure(baseURL, clientID)
|
||||||
|
} else {
|
||||||
|
return startBaseURLClientIDReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//MARK: - sendMessage
|
||||||
|
|
||||||
|
var sendMessageCallsCount = 0
|
||||||
|
var sendMessageCalled: Bool {
|
||||||
|
return sendMessageCallsCount > 0
|
||||||
|
}
|
||||||
|
var sendMessageReceivedMessage: String?
|
||||||
|
var sendMessageReceivedInvocations: [String] = []
|
||||||
|
var sendMessageReturnValue: Result<Bool, ElementCallWidgetDriverError>!
|
||||||
|
var sendMessageClosure: ((String) async -> Result<Bool, ElementCallWidgetDriverError>)?
|
||||||
|
|
||||||
|
func sendMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
||||||
|
sendMessageCallsCount += 1
|
||||||
|
sendMessageReceivedMessage = message
|
||||||
|
sendMessageReceivedInvocations.append(message)
|
||||||
|
if let sendMessageClosure = sendMessageClosure {
|
||||||
|
return await sendMessageClosure(message)
|
||||||
|
} else {
|
||||||
|
return sendMessageReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
class KeychainControllerMock: KeychainControllerProtocol {
|
class KeychainControllerMock: KeychainControllerProtocol {
|
||||||
|
|
||||||
//MARK: - setRestorationToken
|
//MARK: - setRestorationToken
|
||||||
@@ -1173,6 +1228,11 @@ class RoomProxyMock: RoomProxyProtocol {
|
|||||||
set(value) { underlyingIsTombstoned = value }
|
set(value) { underlyingIsTombstoned = value }
|
||||||
}
|
}
|
||||||
var underlyingIsTombstoned: Bool!
|
var underlyingIsTombstoned: Bool!
|
||||||
|
var isCallOngoing: Bool {
|
||||||
|
get { return underlyingIsCallOngoing }
|
||||||
|
set(value) { underlyingIsCallOngoing = value }
|
||||||
|
}
|
||||||
|
var underlyingIsCallOngoing: Bool!
|
||||||
var canonicalAlias: String?
|
var canonicalAlias: String?
|
||||||
var alternativeAliases: [String] = []
|
var alternativeAliases: [String] = []
|
||||||
var hasUnreadNotifications: Bool {
|
var hasUnreadNotifications: Bool {
|
||||||
@@ -1944,6 +2004,23 @@ class RoomProxyMock: RoomProxyProtocol {
|
|||||||
return endPollPollStartIDTextReturnValue
|
return endPollPollStartIDTextReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//MARK: - elementCallWidgetDriver
|
||||||
|
|
||||||
|
var elementCallWidgetDriverCallsCount = 0
|
||||||
|
var elementCallWidgetDriverCalled: Bool {
|
||||||
|
return elementCallWidgetDriverCallsCount > 0
|
||||||
|
}
|
||||||
|
var elementCallWidgetDriverReturnValue: ElementCallWidgetDriverProtocol!
|
||||||
|
var elementCallWidgetDriverClosure: (() -> ElementCallWidgetDriverProtocol)?
|
||||||
|
|
||||||
|
func elementCallWidgetDriver() -> ElementCallWidgetDriverProtocol {
|
||||||
|
elementCallWidgetDriverCallsCount += 1
|
||||||
|
if let elementCallWidgetDriverClosure = elementCallWidgetDriverClosure {
|
||||||
|
return elementCallWidgetDriverClosure()
|
||||||
|
} else {
|
||||||
|
return elementCallWidgetDriverReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class RoomTimelineProviderMock: RoomTimelineProviderProtocol {
|
class RoomTimelineProviderMock: RoomTimelineProviderProtocol {
|
||||||
var updatePublisher: AnyPublisher<TimelineProviderUpdate, Never> {
|
var updatePublisher: AnyPublisher<TimelineProviderUpdate, Never> {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ struct RoomProxyMockConfiguration {
|
|||||||
var isPublic = Bool.random()
|
var isPublic = Bool.random()
|
||||||
var isEncrypted = Bool.random()
|
var isEncrypted = Bool.random()
|
||||||
var isTombstoned = Bool.random()
|
var isTombstoned = Bool.random()
|
||||||
|
var isCallOngoing = Bool.random()
|
||||||
var canonicalAlias: String?
|
var canonicalAlias: String?
|
||||||
var alternativeAliases: [String] = []
|
var alternativeAliases: [String] = []
|
||||||
var hasUnreadNotifications = Bool.random()
|
var hasUnreadNotifications = Bool.random()
|
||||||
@@ -56,6 +57,7 @@ extension RoomProxyMock {
|
|||||||
isPublic = configuration.isPublic
|
isPublic = configuration.isPublic
|
||||||
isEncrypted = configuration.isEncrypted
|
isEncrypted = configuration.isEncrypted
|
||||||
isTombstoned = configuration.isTombstoned
|
isTombstoned = configuration.isTombstoned
|
||||||
|
isCallOngoing = configuration.isCallOngoing
|
||||||
canonicalAlias = configuration.canonicalAlias
|
canonicalAlias = configuration.canonicalAlias
|
||||||
alternativeAliases = configuration.alternativeAliases
|
alternativeAliases = configuration.alternativeAliases
|
||||||
hasUnreadNotifications = configuration.hasUnreadNotifications
|
hasUnreadNotifications = configuration.hasUnreadNotifications
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ElementCallButtonStyle: ButtonStyle {
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
configuration.label
|
||||||
|
.padding(.horizontal, 16.0)
|
||||||
|
.padding(.vertical, 4.0)
|
||||||
|
.foregroundColor(.compound.bgCanvasDefault)
|
||||||
|
.background(Color.compound.iconAccentTertiary)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct CallScreenCoordinatorParameters {
|
||||||
|
let roomProxy: RoomProxyProtocol
|
||||||
|
/// Which Element Call instance should be used
|
||||||
|
let callBaseURL: URL
|
||||||
|
/// A way to identify the current client against Element Call
|
||||||
|
let clientID: String
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CallScreenCoordinatorAction {
|
||||||
|
case dismiss
|
||||||
|
}
|
||||||
|
|
||||||
|
final class CallScreenCoordinator: CoordinatorProtocol {
|
||||||
|
private let parameters: CallScreenCoordinatorParameters
|
||||||
|
private var viewModel: CallScreenViewModelProtocol
|
||||||
|
private let actionsSubject: PassthroughSubject<CallScreenCoordinatorAction, Never> = .init()
|
||||||
|
|
||||||
|
private var cancellables: Set<AnyCancellable> = .init()
|
||||||
|
var actions: AnyPublisher<CallScreenCoordinatorAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(parameters: CallScreenCoordinatorParameters) {
|
||||||
|
self.parameters = parameters
|
||||||
|
|
||||||
|
viewModel = CallScreenViewModel(roomProxy: parameters.roomProxy,
|
||||||
|
callBaseURL: parameters.callBaseURL,
|
||||||
|
clientID: parameters.clientID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
viewModel.actions.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .dismiss:
|
||||||
|
actionsSubject.send(.dismiss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPresentable() -> AnyView {
|
||||||
|
AnyView(CallScreen(context: viewModel.context))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum CallScreenViewModelAction {
|
||||||
|
case dismiss
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CallScreenViewState: BindableState {
|
||||||
|
let messageHandler: String
|
||||||
|
let script: String?
|
||||||
|
var url: URL?
|
||||||
|
var bindings = Bindings()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bindings {
|
||||||
|
var javaScriptMessageHandler: ((Any) -> Void)?
|
||||||
|
var javaScriptEvaluator: ((String) async throws -> Any)?
|
||||||
|
|
||||||
|
var alertInfo: AlertInfo<UUID>?
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CallScreenViewAction {
|
||||||
|
case urlChanged(URL?)
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AVFoundation
|
||||||
|
import CallKit
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
typealias CallScreenViewModelType = StateStoreViewModel<CallScreenViewState, CallScreenViewAction>
|
||||||
|
|
||||||
|
class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol {
|
||||||
|
private let roomProxy: RoomProxyProtocol
|
||||||
|
private let callBaseURL: URL
|
||||||
|
private let clientID: String
|
||||||
|
|
||||||
|
private let widgetDriver: ElementCallWidgetDriverProtocol
|
||||||
|
|
||||||
|
private let callController = CXCallController()
|
||||||
|
private let callProvider = CXProvider(configuration: .init())
|
||||||
|
private let callID = UUID()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<CallScreenViewModelAction, Never> = .init()
|
||||||
|
var actions: AnyPublisher<CallScreenViewModelAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
tearDownVoIPSession(callID: callID)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Designated initialiser
|
||||||
|
/// - Parameters:
|
||||||
|
/// - roomProxy: The room in which the call should be created
|
||||||
|
/// - callBaseURL: Which Element Call instance should be used
|
||||||
|
/// - clientID: Something to identify the current client on the Element Call side
|
||||||
|
init(roomProxy: RoomProxyProtocol, callBaseURL: URL, clientID: String) {
|
||||||
|
self.roomProxy = roomProxy
|
||||||
|
self.callBaseURL = callBaseURL
|
||||||
|
self.clientID = clientID
|
||||||
|
|
||||||
|
widgetDriver = roomProxy.elementCallWidgetDriver()
|
||||||
|
|
||||||
|
super.init(initialViewState: CallScreenViewState(messageHandler: Self.eventHandlerName,
|
||||||
|
script: Self.eventHandlerInjectionScript))
|
||||||
|
|
||||||
|
state.bindings.javaScriptMessageHandler = { [weak self] message in
|
||||||
|
guard let self,
|
||||||
|
let message = message as? String else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Task {
|
||||||
|
await self.widgetDriver.sendMessage(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
widgetDriver.messagePublisher
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] receivedMessage in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let message = "postMessage(\(receivedMessage), '*')"
|
||||||
|
let result = try await self.state.bindings.javaScriptEvaluator?(message)
|
||||||
|
MXLog.debug("Evaluated javascript: \(message) with result: \(String(describing: result))")
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Received javascript evaluation error: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
widgetDriver.actions
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] action in
|
||||||
|
guard let self else { return }
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case .callEnded:
|
||||||
|
actionsSubject.send(.dismiss)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
Task {
|
||||||
|
switch await widgetDriver.start(baseURL: callBaseURL, clientID: clientID) {
|
||||||
|
case .success(let url):
|
||||||
|
state.url = url
|
||||||
|
case .failure(let error):
|
||||||
|
MXLog.error("Failed starting ElementCall Widget Driver with error: \(error)")
|
||||||
|
state.bindings.alertInfo = .init(id: UUID(), title: L10n.errorUnknown, primaryButton: .init(title: L10n.actionOk, action: { [weak self] in
|
||||||
|
self?.actionsSubject.send(.dismiss)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try await setupVoIPSession(callID: callID)
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed setting up VoIP session with error: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func process(viewAction: CallScreenViewAction) {
|
||||||
|
switch viewAction {
|
||||||
|
case .urlChanged(let url):
|
||||||
|
guard let url else { return }
|
||||||
|
MXLog.info("URL changed to: \(url)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - CXCallObserverDelegate
|
||||||
|
|
||||||
|
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
|
||||||
|
MXLog.info("Call changed: \(call)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - CXProviderDelegate
|
||||||
|
|
||||||
|
func providerDidReset(_ provider: CXProvider) {
|
||||||
|
MXLog.info("Call provider did reset: \(provider)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private static let eventHandlerName = "elementx"
|
||||||
|
|
||||||
|
private static var eventHandlerInjectionScript: String {
|
||||||
|
"""
|
||||||
|
window.addEventListener(
|
||||||
|
"message",
|
||||||
|
(event) => {
|
||||||
|
let message = {data: event.data, origin: event.origin}
|
||||||
|
if (message.data.response && message.data.api == "toWidget"
|
||||||
|
|| !message.data.response && message.data.api == "fromWidget") {
|
||||||
|
window.webkit.messageHandlers.\(eventHandlerName).postMessage(JSON.stringify(message.data));
|
||||||
|
}else{
|
||||||
|
console.log("-- skipped event handling by the client because it is send from the client itself.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
private func evaluateJavaScript(_ script: String) async -> String? {
|
||||||
|
guard let evaluator = state.bindings.javaScriptEvaluator else {
|
||||||
|
fatalError("Invalid javaScriptEvaluator")
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
return try await evaluator(script) as? String
|
||||||
|
} catch {
|
||||||
|
MXLog.error("Failed evaluating javaScript with error: \(error)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupVoIPSession(callID: UUID) async throws {
|
||||||
|
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .videoChat, options: [])
|
||||||
|
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
|
||||||
|
|
||||||
|
let handle = CXHandle(type: .generic, value: roomProxy.roomTitle)
|
||||||
|
let startCallAction = CXStartCallAction(call: callID, handle: handle)
|
||||||
|
startCallAction.isVideo = true
|
||||||
|
|
||||||
|
let transaction = CXTransaction(action: startCallAction)
|
||||||
|
|
||||||
|
try await callController.request(transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
private nonisolated func tearDownVoIPSession(callID: UUID?) {
|
||||||
|
guard let callID else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try? AVAudioSession.sharedInstance().setActive(false)
|
||||||
|
|
||||||
|
let endCallAction = CXEndCallAction(call: callID)
|
||||||
|
let transaction = CXTransaction(action: endCallAction)
|
||||||
|
|
||||||
|
callController.request(transaction) { error in
|
||||||
|
if let error {
|
||||||
|
MXLog.error("Failed transaction with error: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
protocol CallScreenViewModelProtocol {
|
||||||
|
var actions: AnyPublisher<CallScreenViewModelAction, Never> { get }
|
||||||
|
var context: CallScreenViewModelType.Context { get }
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
struct CallScreen: View {
|
||||||
|
@ObservedObject var context: CallScreenViewModel.Context
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
WebView(url: context.viewState.url, viewModelContext: context)
|
||||||
|
.navigationTitle("Call")
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.ignoresSafeArea(edges: .bottom)
|
||||||
|
.presentationDragIndicator(.visible)
|
||||||
|
.environment(\.colorScheme, .dark)
|
||||||
|
.alert(item: $context.alertInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct WebView: UIViewRepresentable {
|
||||||
|
let url: URL?
|
||||||
|
let viewModelContext: CallScreenViewModel.Context
|
||||||
|
|
||||||
|
func makeUIView(context: Context) -> WKWebView {
|
||||||
|
context.coordinator.webView
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeCoordinator() -> Coordinator {
|
||||||
|
Coordinator(viewModelContext: viewModelContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIView(_ webView: WKWebView, context: Context) {
|
||||||
|
if let url {
|
||||||
|
context.coordinator.url = url
|
||||||
|
let request = URLRequest(url: url)
|
||||||
|
webView.load(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class Coordinator: NSObject, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate {
|
||||||
|
private let viewModelContext: CallScreenViewModel.Context
|
||||||
|
private var webViewURLObservation: NSKeyValueObservation?
|
||||||
|
|
||||||
|
private(set) var webView: WKWebView!
|
||||||
|
|
||||||
|
var url: URL!
|
||||||
|
|
||||||
|
init(viewModelContext: CallScreenViewModel.Context) {
|
||||||
|
self.viewModelContext = viewModelContext
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
// Avoid `Publishing changes from within view update warnings`
|
||||||
|
viewModelContext.javaScriptEvaluator = self.evaluateJavaScript(_:)
|
||||||
|
}
|
||||||
|
|
||||||
|
let configuration = WKWebViewConfiguration()
|
||||||
|
|
||||||
|
let userContentController = WKUserContentController()
|
||||||
|
userContentController.add(self, name: viewModelContext.viewState.messageHandler)
|
||||||
|
|
||||||
|
configuration.userContentController = userContentController
|
||||||
|
configuration.allowsInlineMediaPlayback = true
|
||||||
|
configuration.allowsPictureInPictureMediaPlayback = true
|
||||||
|
|
||||||
|
if let script = viewModelContext.viewState.script {
|
||||||
|
let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
|
||||||
|
configuration.userContentController.addUserScript(userScript)
|
||||||
|
}
|
||||||
|
|
||||||
|
webView = WKWebView(frame: .zero, configuration: configuration)
|
||||||
|
webView.uiDelegate = self
|
||||||
|
webView.navigationDelegate = self
|
||||||
|
|
||||||
|
// Try matching Element Call colors
|
||||||
|
webView.isOpaque = false
|
||||||
|
webView.backgroundColor = .compound.bgCanvasDefault
|
||||||
|
webView.scrollView.backgroundColor = .compound.bgCanvasDefault
|
||||||
|
}
|
||||||
|
|
||||||
|
func evaluateJavaScript(_ script: String) async throws -> Any? {
|
||||||
|
// After testing different scenarios it seems that when using async/await version of these
|
||||||
|
// methods wkwebView expects JavaScript to return with a value (something other than Void),
|
||||||
|
// if there is no value returning from the JavaScript that you evaluate you will have a crash.
|
||||||
|
try await withCheckedThrowingContinuation { continuaton in
|
||||||
|
webView.evaluateJavaScript(script) { result, error in
|
||||||
|
if let error {
|
||||||
|
continuaton.resume(throwing: error)
|
||||||
|
} else {
|
||||||
|
continuaton.resume(returning: result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - WKScriptMessageHandler
|
||||||
|
|
||||||
|
nonisolated func userContentController(_ userContentController: WKUserContentController,
|
||||||
|
didReceive message: WKScriptMessage) {
|
||||||
|
Task { @MainActor in
|
||||||
|
viewModelContext.javaScriptMessageHandler?(message.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - WKUIDelegate
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, decideMediaCapturePermissionsFor origin: WKSecurityOrigin, initiatedBy frame: WKFrameInfo, type: WKMediaCaptureType) async -> WKPermissionDecision {
|
||||||
|
// Don't allow permissions for domains different than what the call was started on
|
||||||
|
guard origin.host == url.host else {
|
||||||
|
return .deny
|
||||||
|
}
|
||||||
|
|
||||||
|
return .grant
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - WKNavigationDelegate
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
|
||||||
|
// Allow any content from the main URL.
|
||||||
|
if navigationAction.request.url?.host == url.host {
|
||||||
|
return .allow
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additionally allow any embedded content such as captchas.
|
||||||
|
if let targetFrame = navigationAction.targetFrame, !targetFrame.isMainFrame {
|
||||||
|
return .allow
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the request is invalid.
|
||||||
|
return .cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
nonisolated func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||||
|
Task { @MainActor in
|
||||||
|
viewModelContext.send(viewAction: .urlChanged(webView.url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
struct CallScreen_Previews: PreviewProvider {
|
||||||
|
static let viewModel = {
|
||||||
|
let roomProxy = RoomProxyMock()
|
||||||
|
|
||||||
|
let widgetDriver = ElementCallWidgetDriverMock()
|
||||||
|
widgetDriver.underlyingMessagePublisher = .init()
|
||||||
|
widgetDriver.underlyingActions = PassthroughSubject<ElementCallWidgetDriverAction, Never>().eraseToAnyPublisher()
|
||||||
|
widgetDriver.startBaseURLClientIDReturnValue = .success(URL.userDirectory)
|
||||||
|
|
||||||
|
roomProxy.elementCallWidgetDriverReturnValue = widgetDriver
|
||||||
|
|
||||||
|
return CallScreenViewModel(roomProxy: roomProxy,
|
||||||
|
callBaseURL: "https://call.element.io",
|
||||||
|
clientID: "io.element.elementx")
|
||||||
|
}()
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
NavigationStack {
|
||||||
|
CallScreen(context: viewModel.context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@ enum RoomScreenCoordinatorAction {
|
|||||||
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
|
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
|
||||||
case presentRoomMemberDetails(member: RoomMemberProxyProtocol)
|
case presentRoomMemberDetails(member: RoomMemberProxyProtocol)
|
||||||
case presentMessageForwarding(itemID: TimelineItemIdentifier)
|
case presentMessageForwarding(itemID: TimelineItemIdentifier)
|
||||||
|
case presentCallScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
final class RoomScreenCoordinator: CoordinatorProtocol {
|
final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||||
@@ -109,6 +110,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.presentLocationViewer(body: body, geoURI: geoURI, description: description))
|
actionsSubject.send(.presentLocationViewer(body: body, geoURI: geoURI, description: description))
|
||||||
case .composer(let action):
|
case .composer(let action):
|
||||||
composerViewModel.process(roomAction: action)
|
composerViewModel.process(roomAction: action)
|
||||||
|
case .displayCallScreen:
|
||||||
|
actionsSubject.send(.presentCallScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ enum RoomScreenViewModelAction {
|
|||||||
case displayMessageForwarding(itemID: TimelineItemIdentifier)
|
case displayMessageForwarding(itemID: TimelineItemIdentifier)
|
||||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
||||||
case composer(action: RoomScreenComposerAction)
|
case composer(action: RoomScreenComposerAction)
|
||||||
|
case displayCallScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RoomScreenComposerMode: Equatable {
|
enum RoomScreenComposerMode: Equatable {
|
||||||
@@ -63,7 +64,7 @@ enum RoomScreenViewAction {
|
|||||||
case paginateBackwards
|
case paginateBackwards
|
||||||
case selectedPollOption(pollStartID: String, optionID: String)
|
case selectedPollOption(pollStartID: String, optionID: String)
|
||||||
case endPoll(pollStartID: String)
|
case endPoll(pollStartID: String)
|
||||||
|
|
||||||
case timelineItemMenu(itemID: TimelineItemIdentifier)
|
case timelineItemMenu(itemID: TimelineItemIdentifier)
|
||||||
case timelineItemMenuAction(itemID: TimelineItemIdentifier, action: TimelineItemMenuAction)
|
case timelineItemMenuAction(itemID: TimelineItemIdentifier, action: TimelineItemMenuAction)
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ enum RoomScreenViewAction {
|
|||||||
case tappedOnUser(userID: String)
|
case tappedOnUser(userID: String)
|
||||||
|
|
||||||
case reactionSummary(itemID: TimelineItemIdentifier, key: String)
|
case reactionSummary(itemID: TimelineItemIdentifier, key: String)
|
||||||
|
|
||||||
case retrySend(itemID: TimelineItemIdentifier)
|
case retrySend(itemID: TimelineItemIdentifier)
|
||||||
case cancelSend(itemID: TimelineItemIdentifier)
|
case cancelSend(itemID: TimelineItemIdentifier)
|
||||||
|
|
||||||
@@ -81,8 +82,11 @@ enum RoomScreenViewAction {
|
|||||||
|
|
||||||
case enableLongPress(itemID: TimelineItemIdentifier)
|
case enableLongPress(itemID: TimelineItemIdentifier)
|
||||||
case disableLongPress(itemID: TimelineItemIdentifier)
|
case disableLongPress(itemID: TimelineItemIdentifier)
|
||||||
|
|
||||||
case playPauseAudio(itemID: TimelineItemIdentifier)
|
case playPauseAudio(itemID: TimelineItemIdentifier)
|
||||||
case seekAudio(itemID: TimelineItemIdentifier, progress: Double)
|
case seekAudio(itemID: TimelineItemIdentifier, progress: Double)
|
||||||
|
|
||||||
|
case presentCall
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RoomScreenComposerAction {
|
enum RoomScreenComposerAction {
|
||||||
@@ -103,9 +107,13 @@ struct RoomScreenViewState: BindableState {
|
|||||||
var isEncryptedOneToOneRoom = false
|
var isEncryptedOneToOneRoom = false
|
||||||
var timelineViewState = TimelineViewState() // check the doc before changing this
|
var timelineViewState = TimelineViewState() // check the doc before changing this
|
||||||
var swiftUITimelineEnabled = false
|
var swiftUITimelineEnabled = false
|
||||||
|
|
||||||
var longPressDisabledItemID: TimelineItemIdentifier?
|
var longPressDisabledItemID: TimelineItemIdentifier?
|
||||||
var ownUserID: String
|
var ownUserID: String
|
||||||
|
|
||||||
|
var showCallButton = false
|
||||||
|
var isCallOngoing = false
|
||||||
|
|
||||||
var bindings: RoomScreenViewStateBindings
|
var bindings: RoomScreenViewStateBindings
|
||||||
|
|
||||||
/// A closure providing the actions to show when long pressing on an item in the timeline.
|
/// A closure providing the actions to show when long pressing on an item in the timeline.
|
||||||
@@ -127,14 +135,14 @@ struct RoomScreenViewStateBindings {
|
|||||||
|
|
||||||
/// Information describing the currently displayed alert.
|
/// Information describing the currently displayed alert.
|
||||||
var alertInfo: AlertInfo<RoomScreenErrorType>?
|
var alertInfo: AlertInfo<RoomScreenErrorType>?
|
||||||
|
|
||||||
/// An alert info for confirmation actions (e.g. ending a poll)
|
/// An alert info for confirmation actions (e.g. ending a poll)
|
||||||
var confirmationAlertInfo: AlertInfo<UUID>?
|
var confirmationAlertInfo: AlertInfo<UUID>?
|
||||||
|
|
||||||
var debugInfo: TimelineItemDebugInfo?
|
var debugInfo: TimelineItemDebugInfo?
|
||||||
|
|
||||||
var actionMenuInfo: TimelineItemActionMenuInfo?
|
var actionMenuInfo: TimelineItemActionMenuInfo?
|
||||||
|
|
||||||
var sendFailedConfirmationDialogInfo: SendFailedConfirmationDialogInfo?
|
var sendFailedConfirmationDialogInfo: SendFailedConfirmationDialogInfo?
|
||||||
|
|
||||||
var reactionSummaryInfo: ReactionSummaryInfo?
|
var reactionSummaryInfo: ReactionSummaryInfo?
|
||||||
@@ -144,7 +152,7 @@ struct TimelineItemActionMenuInfo: Equatable, Identifiable {
|
|||||||
static func == (lhs: TimelineItemActionMenuInfo, rhs: TimelineItemActionMenuInfo) -> Bool {
|
static func == (lhs: TimelineItemActionMenuInfo, rhs: TimelineItemActionMenuInfo) -> Bool {
|
||||||
lhs.id == rhs.id
|
lhs.id == rhs.id
|
||||||
}
|
}
|
||||||
|
|
||||||
let item: EventBasedTimelineItemProtocol
|
let item: EventBasedTimelineItemProtocol
|
||||||
|
|
||||||
var id: TimelineItemIdentifier {
|
var id: TimelineItemIdentifier {
|
||||||
@@ -154,7 +162,7 @@ struct TimelineItemActionMenuInfo: Equatable, Identifiable {
|
|||||||
|
|
||||||
struct SendFailedConfirmationDialogInfo: ConfirmationDialogProtocol {
|
struct SendFailedConfirmationDialogInfo: ConfirmationDialogProtocol {
|
||||||
let title = L10n.screenRoomRetrySendMenuTitle
|
let title = L10n.screenRoomRetrySendMenuTitle
|
||||||
|
|
||||||
let itemID: TimelineItemIdentifier
|
let itemID: TimelineItemIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,19 +192,19 @@ struct RoomMemberState {
|
|||||||
struct TimelineViewState {
|
struct TimelineViewState {
|
||||||
var canBackPaginate = true
|
var canBackPaginate = true
|
||||||
var isBackPaginating = false
|
var isBackPaginating = false
|
||||||
|
|
||||||
// These can be removed when we have full swiftUI and moved as @State values in the view
|
// These can be removed when we have full swiftUI and moved as @State values in the view
|
||||||
var scrollToBottomPublisher = PassthroughSubject<Void, Never>()
|
var scrollToBottomPublisher = PassthroughSubject<Void, Never>()
|
||||||
|
|
||||||
var itemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
|
var itemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
|
||||||
|
|
||||||
var renderedTimelineIDs = [String]()
|
var renderedTimelineIDs = [String]()
|
||||||
var pendingTimelineIDs = [String]()
|
var pendingTimelineIDs = [String]()
|
||||||
|
|
||||||
var timelineIDs: [String] {
|
var timelineIDs: [String] {
|
||||||
itemsDictionary.keys.elements
|
itemsDictionary.keys.elements
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemViewStates: [RoomTimelineItemViewState] {
|
var itemViewStates: [RoomTimelineItemViewState] {
|
||||||
renderedTimelineIDs.compactMap { itemsDictionary[$0] }
|
renderedTimelineIDs.compactMap { itemsDictionary[$0] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
readReceiptsEnabled: appSettings.readReceiptsEnabled,
|
readReceiptsEnabled: appSettings.readReceiptsEnabled,
|
||||||
isEncryptedOneToOneRoom: roomProxy.isEncryptedOneToOneRoom,
|
isEncryptedOneToOneRoom: roomProxy.isEncryptedOneToOneRoom,
|
||||||
ownUserID: roomProxy.ownUserID,
|
ownUserID: roomProxy.ownUserID,
|
||||||
|
isCallOngoing: roomProxy.isCallOngoing,
|
||||||
bindings: .init(reactionsCollapsed: [:])),
|
bindings: .init(reactionsCollapsed: [:])),
|
||||||
imageProvider: mediaProvider)
|
imageProvider: mediaProvider)
|
||||||
|
|
||||||
@@ -163,6 +164,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
message: L10n.commonPollEndConfirmation,
|
message: L10n.commonPollEndConfirmation,
|
||||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
|
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
|
||||||
secondaryButton: .init(title: L10n.actionOk, action: { self.endPoll(pollStartID: pollStartID) }))
|
secondaryButton: .init(title: L10n.actionOk, action: { self.endPoll(pollStartID: pollStartID) }))
|
||||||
|
case .presentCall:
|
||||||
|
actionsSubject.send(.displayCallScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +246,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
.weakAssign(to: \.state.readReceiptsEnabled, on: self)
|
.weakAssign(to: \.state.readReceiptsEnabled, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
appSettings.$elementCallEnabled
|
||||||
|
.weakAssign(to: \.state.showCallButton, on: self)
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
roomProxy.members
|
roomProxy.members
|
||||||
.map { members in
|
.map { members in
|
||||||
members.reduce(into: [String: RoomMemberState]()) { dictionary, member in
|
members.reduce(into: [String: RoomMemberState]()) { dictionary, member in
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import WysiwygComposer
|
import WysiwygComposer
|
||||||
|
|
||||||
@@ -155,8 +156,33 @@ struct RoomScreen: View {
|
|||||||
ToolbarItem(placement: .principal) {
|
ToolbarItem(placement: .principal) {
|
||||||
RoomHeaderView(context: context)
|
RoomHeaderView(context: context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolbarItem(placement: .primaryAction) {
|
||||||
|
callButton
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var callButton: some View {
|
||||||
|
if context.viewState.showCallButton {
|
||||||
|
if context.viewState.isCallOngoing {
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .presentCall)
|
||||||
|
} label: {
|
||||||
|
Label(L10n.actionJoin, icon: \.videoCall)
|
||||||
|
.labelStyle(.titleAndIcon)
|
||||||
|
}
|
||||||
|
.buttonStyle(ElementCallButtonStyle())
|
||||||
|
} else {
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .presentCall)
|
||||||
|
} label: {
|
||||||
|
CompoundIcon(\.videoCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var isNavigationBarHidden: Bool {
|
private var isNavigationBarHidden: Bool {
|
||||||
composerToolbarContext.composerActionsEnabled && composerToolbarContext.composerExpanded && UIDevice.current.userInterfaceIdiom == .pad
|
composerToolbarContext.composerActionsEnabled && composerToolbarContext.composerExpanded && UIDevice.current.userInterfaceIdiom == .pad
|
||||||
}
|
}
|
||||||
@@ -167,11 +193,11 @@ struct RoomScreen: View {
|
|||||||
struct RoomScreen_Previews: PreviewProvider, TestablePreview {
|
struct RoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
|
static let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
|
||||||
mediaProvider: MockMediaProvider(),
|
mediaProvider: MockMediaProvider(),
|
||||||
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")),
|
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room", isCallOngoing: true)),
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
RoomScreen(context: viewModel.context, composerToolbar: ComposerToolbar.mock())
|
RoomScreen(context: viewModel.context, composerToolbar: ComposerToolbar.mock())
|
||||||
|
|||||||
+1
@@ -52,6 +52,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
|||||||
var voiceMessageEnabled: Bool { get set }
|
var voiceMessageEnabled: Bool { get set }
|
||||||
var mentionsEnabled: Bool { get set }
|
var mentionsEnabled: Bool { get set }
|
||||||
var appLockFlowEnabled: Bool { get set }
|
var appLockFlowEnabled: Bool { get set }
|
||||||
|
var elementCallEnabled: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSettings: DeveloperOptionsProtocol { }
|
extension AppSettings: DeveloperOptionsProtocol { }
|
||||||
|
|||||||
+4
@@ -50,6 +50,10 @@ struct DeveloperOptionsScreen: View {
|
|||||||
Text("Show user mentions")
|
Text("Show user mentions")
|
||||||
Text("Requires app reboot")
|
Text("Requires app reboot")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $context.elementCallEnabled) {
|
||||||
|
Text("Elemement Call")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Room creation") {
|
Section("Room creation") {
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
|
private struct ElementCallWidgetMessage: Codable {
|
||||||
|
enum Direction: String, Codable {
|
||||||
|
case fromWidget
|
||||||
|
case toWidget
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Action: String, Codable {
|
||||||
|
case hangup = "im.vector.hangup"
|
||||||
|
}
|
||||||
|
|
||||||
|
let direction: Direction
|
||||||
|
let action: Action
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case direction = "api"
|
||||||
|
case action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ElementCallWidgetDriver: WidgetPermissionsProvider, ElementCallWidgetDriverProtocol {
|
||||||
|
private let room: RoomProtocol
|
||||||
|
private var widgetDriver: WidgetDriverAndHandle?
|
||||||
|
|
||||||
|
let messagePublisher = PassthroughSubject<String, Never>()
|
||||||
|
|
||||||
|
private let actionsSubject: PassthroughSubject<ElementCallWidgetDriverAction, Never> = .init()
|
||||||
|
var actions: AnyPublisher<ElementCallWidgetDriverAction, Never> {
|
||||||
|
actionsSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(room: RoomProtocol) {
|
||||||
|
self.room = room
|
||||||
|
}
|
||||||
|
|
||||||
|
func start(baseURL: URL, clientID: String) async -> Result<URL, ElementCallWidgetDriverError> {
|
||||||
|
guard let room = room as? Room else {
|
||||||
|
return .failure(.roomInvalid)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let widgetSettings = try? newVirtualElementCallWidget(props: .init(elementCallUrl: baseURL.absoluteString,
|
||||||
|
widgetId: UUID().uuidString,
|
||||||
|
parentUrl: nil,
|
||||||
|
hideHeader: nil,
|
||||||
|
preload: nil,
|
||||||
|
fontScale: nil,
|
||||||
|
appPrompt: false,
|
||||||
|
skipLobby: true,
|
||||||
|
confineToRoom: true,
|
||||||
|
fonts: nil,
|
||||||
|
analyticsId: nil)) else {
|
||||||
|
return .failure(.failedBuildingWidgetSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let urlString = try? await generateWebviewUrl(widgetSettings: widgetSettings, room: room,
|
||||||
|
props: .init(clientId: clientID,
|
||||||
|
languageTag: nil,
|
||||||
|
theme: nil)) else {
|
||||||
|
return .failure(.failedBuildingCallURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let url = URL(string: urlString) else {
|
||||||
|
return .failure(.failedParsingCallURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let widgetDriver = try? makeWidgetDriver(settings: widgetSettings) else {
|
||||||
|
return .failure(.failedBuildingWidgetDriver)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.widgetDriver = widgetDriver
|
||||||
|
|
||||||
|
Task.detached { [weak self, widgetDriver, messagePublisher] in
|
||||||
|
MXLog.debug("Started message receiving loop")
|
||||||
|
|
||||||
|
defer {
|
||||||
|
MXLog.debug("Stopped message receiving loop")
|
||||||
|
}
|
||||||
|
|
||||||
|
while true {
|
||||||
|
guard let receivedMessage = await widgetDriver.handle.recv() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
messagePublisher.send(receivedMessage)
|
||||||
|
MXLog.debug("Received message: \(receivedMessage)")
|
||||||
|
|
||||||
|
self?.handleMessageIfNeeded(receivedMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.detached { [widgetDriver] in
|
||||||
|
MXLog.debug("Started widget driver")
|
||||||
|
|
||||||
|
defer {
|
||||||
|
MXLog.debug("Stopped widget driver")
|
||||||
|
}
|
||||||
|
|
||||||
|
await widgetDriver.driver.run(room: room, permissionsProvider: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
return .success(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError> {
|
||||||
|
guard let widgetDriver else {
|
||||||
|
return .failure(.driverNotSetup)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = await widgetDriver.handle.send(msg: message)
|
||||||
|
MXLog.debug("Sent message: \(message) with result: \(result)")
|
||||||
|
|
||||||
|
handleMessageIfNeeded(message)
|
||||||
|
|
||||||
|
return .success(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - WidgetPermissionsProvider
|
||||||
|
|
||||||
|
func acquirePermissions(permissions: MatrixRustSDK.WidgetPermissions) -> MatrixRustSDK.WidgetPermissions {
|
||||||
|
permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
func handleMessageIfNeeded(_ message: String) {
|
||||||
|
guard let data = message.data(using: .utf8),
|
||||||
|
let widgetMessage = try? JSONDecoder().decode(ElementCallWidgetMessage.self, from: data) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if widgetMessage.direction == .fromWidget {
|
||||||
|
switch widgetMessage.action {
|
||||||
|
case .hangup:
|
||||||
|
actionsSubject.send(.callEnded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2023 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ElementCallWidgetDriverError: Error {
|
||||||
|
case roomInvalid
|
||||||
|
case failedBuildingCallURL
|
||||||
|
case failedBuildingWidgetSettings
|
||||||
|
case failedBuildingWidgetDriver
|
||||||
|
case failedParsingCallURL
|
||||||
|
case driverNotSetup
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ElementCallWidgetDriverAction {
|
||||||
|
case callEnded
|
||||||
|
case errorReceived(ElementCallWidgetDriverError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sourcery: AutoMockable
|
||||||
|
protocol ElementCallWidgetDriverProtocol {
|
||||||
|
var messagePublisher: PassthroughSubject<String, Never> { get }
|
||||||
|
var actions: AnyPublisher<ElementCallWidgetDriverAction, Never> { get }
|
||||||
|
|
||||||
|
func start(baseURL: URL, clientID: String) async -> Result<URL, ElementCallWidgetDriverError>
|
||||||
|
|
||||||
|
func sendMessage(_ message: String) async -> Result<Bool, ElementCallWidgetDriverError>
|
||||||
|
}
|
||||||
@@ -151,6 +151,10 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
room.isTombstoned()
|
room.isTombstoned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isCallOngoing: Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
var canonicalAlias: String? {
|
var canonicalAlias: String? {
|
||||||
room.canonicalAlias()
|
room.canonicalAlias()
|
||||||
}
|
}
|
||||||
@@ -252,7 +256,7 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
return .success(())
|
return .success(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendMessage(_ message: String, html: String?, inReplyTo eventID: String? = nil) async -> Result<Void, RoomProxyError> {
|
func sendMessage(_ message: String, html: String?, inReplyTo eventID: String? = nil) async -> Result<Void, RoomProxyError> {
|
||||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||||
defer {
|
defer {
|
||||||
@@ -430,13 +434,13 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
self.room.cancelSend(txnId: transactionID)
|
self.room.cancelSend(txnId: transactionID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func editMessage(_ message: String, html: String?, original eventID: String) async -> Result<Void, RoomProxyError> {
|
func editMessage(_ message: String, html: String?, original eventID: String) async -> Result<Void, RoomProxyError> {
|
||||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||||
defer {
|
defer {
|
||||||
sendMessageBackgroundTask?.stop()
|
sendMessageBackgroundTask?.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
let messageContent = buildMessageContentFor(message, html: html)
|
let messageContent = buildMessageContentFor(message, html: html)
|
||||||
|
|
||||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||||
@@ -705,6 +709,12 @@ class RoomProxy: RoomProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Element Call
|
||||||
|
|
||||||
|
func elementCallWidgetDriver() -> ElementCallWidgetDriverProtocol {
|
||||||
|
ElementCallWidgetDriver(room: room)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ protocol RoomProxyProtocol {
|
|||||||
var isSpace: Bool { get }
|
var isSpace: Bool { get }
|
||||||
var isEncrypted: Bool { get }
|
var isEncrypted: Bool { get }
|
||||||
var isTombstoned: Bool { get }
|
var isTombstoned: Bool { get }
|
||||||
|
var isCallOngoing: Bool { get }
|
||||||
var canonicalAlias: String? { get }
|
var canonicalAlias: String? { get }
|
||||||
var alternativeAliases: [String] { get }
|
var alternativeAliases: [String] { get }
|
||||||
var hasUnreadNotifications: Bool { get }
|
var hasUnreadNotifications: Bool { get }
|
||||||
@@ -176,6 +177,10 @@ protocol RoomProxyProtocol {
|
|||||||
func sendPollResponse(pollStartID: String, answers: [String]) async -> Result<Void, RoomProxyError>
|
func sendPollResponse(pollStartID: String, answers: [String]) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
func endPoll(pollStartID: String, text: String) async -> Result<Void, RoomProxyError>
|
func endPoll(pollStartID: String, text: String) async -> Result<Void, RoomProxyError>
|
||||||
|
|
||||||
|
// MARK: - Element Call
|
||||||
|
|
||||||
|
func elementCallWidgetDriver() -> ElementCallWidgetDriverProtocol
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RoomProxyProtocol {
|
extension RoomProxyProtocol {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ElementX
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class CallScreenUITests: XCTestCase { }
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2022 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
@testable import ElementX
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class CallScreenViewModelTests: XCTestCase { }
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Add support for running Element Calls through Rust side widgets
|
||||||
Reference in New Issue
Block a user