diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index b7a759f52..1246d56c8 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -50,7 +50,6 @@ 12CCA59536EDD99A3272CF77 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC3F82523D6F48B926D6AF68 /* AppSettings.swift */; }; 13853973A5E24374FCEDE8A3 /* RedactedRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F2A7A4E3F5060F52ACFFB0 /* RedactedRoomTimelineView.swift */; }; 13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */; }; - 14132418A748C988B85B025E /* OnboardingPageIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09199C43BAB209C0BD89A836 /* OnboardingPageIndicator.swift */; }; 149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */; }; 14E99D27628B1A6F0CB46FEA /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A9F49B3EE59147AF2F70BB /* SeparatorRoomTimelineItem.swift */; }; 152AE2B8650FB23AFD2E28B9 /* MockAuthenticationServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C2B80DD0BF6F10BB5FA922 /* MockAuthenticationServiceProxy.swift */; }; @@ -193,6 +192,7 @@ 500CB65ED116B81DA52FDAEE /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874A1842477895F199567BD7 /* TimelineView.swift */; }; 501304F26B52DF7024011B6C /* EmojiMartJSONLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BF9E3E6A23180EC05F06460 /* EmojiMartJSONLoaderTests.swift */; }; 50C90117FE25390BFBD40173 /* RustTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542D4F49FABA056DEEEB3400 /* RustTracing.swift */; }; + 5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; }; 518C93DC6516D3D018DE065F /* UNNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */; }; 520EEDAFBC778AB0B41F2F53 /* ClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */; }; 5375902175B2FEA2949D7D74 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDDDD9FE1A699D23A5E096 /* LoginScreen.swift */; }; @@ -358,6 +358,7 @@ 90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */; }; 90EB25D13AE6EEF034BDE9D2 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D52BAA5BADB06E5E8C295D /* Assets.swift */; }; 913134A9302FD13139372A2F /* AnalyticsSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93B3513E60591237A49EE102 /* AnalyticsSettingsScreenCoordinator.swift */; }; + 915241C42A274FA80087BF83 /* FullscreenDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 915241C32A274FA80087BF83 /* FullscreenDialog.swift */; }; 9219640F4D980CFC5FE855AD /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 536E72DCBEEC4A1FE66CFDCE /* target.yml */; }; 92B95779840CD749117B3615 /* EmojiMartStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38AE3617D7619EF30CDD229 /* EmojiMartStore.swift */; }; 92D9088B901CEBB1A99ECA4E /* RoomMemberProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */; }; @@ -616,7 +617,6 @@ F16109A6F6DF03DA26D59233 /* RoomDetailsEditScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 122186B7CD1BC46A9C629DD9 /* RoomDetailsEditScreenUITests.swift */; }; F18CA61A58C77C84F551B8E7 /* GeneratedMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57916A1578D8043BB0795441 /* GeneratedMocks.swift */; }; F253AAB4C8F06208173C9C4A /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D52BAA5BADB06E5E8C295D /* Assets.swift */; }; - F257F964493A9CD02A6F720C /* OnboardingPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF2717AB91060260E5F4781 /* OnboardingPageView.swift */; }; F32B271F60531BE92C6E62A1 /* StickerRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 612EF972F2A1800682D32C5E /* StickerRoomTimelineView.swift */; }; F37629BAA5E8F50AAF2A131D /* SoftLogoutScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB7BAD55A4E2B8E5828CD64C /* SoftLogoutScreenViewModel.swift */; }; F3E2D3F7ACDED65A4E5CD8DE /* RoomMembersListScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */; }; @@ -722,7 +722,6 @@ 07E65E613F057697A1A0BC03 /* NotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationViewController.swift; sourceTree = ""; }; 086B997409328F091EBA43CE /* RoomScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenUITests.swift; sourceTree = ""; }; 086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentViewModelTests.swift; sourceTree = ""; }; - 09199C43BAB209C0BD89A836 /* OnboardingPageIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPageIndicator.swift; sourceTree = ""; }; 095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProviderProtocol.swift; sourceTree = ""; }; 0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementToggleStyle.swift; sourceTree = ""; }; 099F2D36C141D845A445B1E6 /* EmojiProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiProviderTests.swift; sourceTree = ""; }; @@ -750,7 +749,7 @@ 1222DB76B917EB8A55365BA5 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; 127A57D053CE8C87B5EFB089 /* Consumable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Consumable.swift; sourceTree = ""; }; 127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = ""; }; - 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = ""; }; + 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = ""; }; 130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = ""; }; 13673F95EBA78D40C09CCE35 /* MockUserIndicatorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserIndicatorController.swift; sourceTree = ""; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -778,7 +777,6 @@ 1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreen.swift; sourceTree = ""; }; 1D56469A9EE0CFA2B7BA9760 /* SessionVerificationControllerProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationControllerProxyProtocol.swift; sourceTree = ""; }; 1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenUITests.swift; sourceTree = ""; }; - 1DF2717AB91060260E5F4781 /* OnboardingPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPageView.swift; sourceTree = ""; }; 1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelProtocol.swift; sourceTree = ""; }; 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DTHTMLElement+AttributedStringBuilder.swift"; sourceTree = ""; }; 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilder.swift; sourceTree = ""; }; @@ -830,6 +828,7 @@ 35FA991289149D31F4286747 /* UserPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreference.swift; sourceTree = ""; }; 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = ""; }; 37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItem.swift; sourceTree = ""; }; + 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringTests.swift; sourceTree = ""; }; 39001365B76B89983FDB7AD8 /* EmojiMartJSONLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiMartJSONLoader.swift; sourceTree = ""; }; 3948D16F021DFDB2CD26EAA8 /* MockBackgroundTaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBackgroundTaskService.swift; sourceTree = ""; }; 398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadableFrameModifier.swift; sourceTree = ""; }; @@ -865,7 +864,7 @@ 46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = ""; }; 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = ""; }; 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = ""; }; - 478BE8591BD13E908EF70C0C /* DesignKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = DesignKit; path = DesignKit; sourceTree = SOURCE_ROOT; }; + 478BE8591BD13E908EF70C0C /* DesignKit */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DesignKit; sourceTree = SOURCE_ROOT; }; 4798B3B7A1E8AE3901CEE8C6 /* FramePreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramePreferenceKey.swift; sourceTree = ""; }; 47E6DD75A81D07CD91997D8C /* SettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenViewModelProtocol.swift; sourceTree = ""; }; 47EBB5D698CE9A25BB553A2D /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; @@ -1012,7 +1011,7 @@ 8D6094DEAAEB388E1AE118C6 /* MockRoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineProvider.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = ""; }; - 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = ""; }; + 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = ""; }; 8E1BBA73B611EDEEA6E20E05 /* InvitesScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenModels.swift; sourceTree = ""; }; 8EC57A32ABC80D774CC663DB /* SettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenUITests.swift; sourceTree = ""; }; 8F61A0DD8243B395499C99A2 /* InvitesScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenUITests.swift; sourceTree = ""; }; @@ -1020,6 +1019,7 @@ 8FC26871038FB0E4AAE22605 /* apple_emojis_data.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = apple_emojis_data.json; sourceTree = ""; }; 8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; 90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = ""; }; + 915241C32A274FA80087BF83 /* FullscreenDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullscreenDialog.swift; sourceTree = ""; }; 923485F85E1D765EF9D20E88 /* UserProfileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileCell.swift; sourceTree = ""; }; 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAuthenticationPresenter.swift; sourceTree = ""; }; 92B45A6B13D32A131FCA4EFF /* FilePreviewScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -1110,7 +1110,7 @@ B43AF03660F5FD4FFFA7F1CE /* TimelineItemContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemContextMenu.swift; sourceTree = ""; }; B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = ""; }; B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = ""; }; - B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = ""; }; + B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = ""; }; B6311F21F911E23BE4DF51B4 /* ReadMarkerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadMarkerRoomTimelineView.swift; sourceTree = ""; }; B6E89E530A8E92EC44301CA1 /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = ""; }; B7DBA101D643B31E813F3AC1 /* AnalyticsSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreen.swift; sourceTree = ""; }; @@ -1177,7 +1177,7 @@ CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = ""; }; CECF45B5E8E795666B8C5013 /* SettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenModels.swift; sourceTree = ""; }; CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = ""; }; - CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = ""; }; + CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = ""; }; CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = ""; }; D06A27D9C70E0DCC1E199163 /* OnboardingBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackgroundView.swift; sourceTree = ""; }; D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = ""; }; @@ -1243,7 +1243,7 @@ ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModel.swift; sourceTree = ""; }; ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = ""; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = ""; }; - ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = ""; }; + ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = ""; }; ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = ""; }; EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelTests.swift; sourceTree = ""; }; EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = ""; }; @@ -2218,6 +2218,7 @@ C687844F60BFF532D49A994C /* AnalyticsTests.swift */, 893777A4997BBDB68079D4F5 /* ArrayTests.swift */, AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */, + 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */, 6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */, EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */, 7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */, @@ -2372,8 +2373,6 @@ isa = PBXGroup; children = ( D06A27D9C70E0DCC1E199163 /* OnboardingBackgroundView.swift */, - 09199C43BAB209C0BD89A836 /* OnboardingPageIndicator.swift */, - 1DF2717AB91060260E5F4781 /* OnboardingPageView.swift */, AB8E75B9CB6C78BE8D09B1AF /* OnboardingScreen.swift */, ); path = View; @@ -2930,6 +2929,7 @@ isa = PBXGroup; children = ( 8872E9C5E91E9F2BFC4EBCCA /* AlignedScrollView.swift */, + 915241C32A274FA80087BF83 /* FullscreenDialog.swift */, 4798B3B7A1E8AE3901CEE8C6 /* FramePreferenceKey.swift */, 398817652FA8ABAE0A31AC6D /* ReadableFrameModifier.swift */, EFF7BF82A950B91BC5469E91 /* ViewFrameReader.swift */, @@ -3634,6 +3634,7 @@ 890F0D453FE388756479AC97 /* AnalyticsTests.swift in Sources */, 3EC698F80DDEEFA273857841 /* ArrayTests.swift in Sources */, 90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */, + 5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */, 0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */, 7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */, C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */, @@ -3858,6 +3859,7 @@ 7CD16990BA843BE9ED639129 /* ImageRoomTimelineItem.swift in Sources */, B796A25F282C0A340D1B9C12 /* ImageRoomTimelineItemContent.swift in Sources */, D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */, + 915241C42A274FA80087BF83 /* FullscreenDialog.swift in Sources */, B6048166B4AA4CEFEA9B77A6 /* InfoPlistReader.swift in Sources */, C4D2BCAA54E2C62B94B24AF4 /* InviteUsersScreen.swift in Sources */, E27C4D1A1F8BB77CA790B403 /* InviteUsersScreenCoordinator.swift in Sources */, @@ -3931,8 +3933,6 @@ 48FE5F0E3921146DBF4E61E7 /* OnboardingBackgroundView.swift in Sources */, 2CB6787E25B11711518E9588 /* OnboardingCoordinator.swift in Sources */, 5D7960B32C350FA93F48D02B /* OnboardingModels.swift in Sources */, - 14132418A748C988B85B025E /* OnboardingPageIndicator.swift in Sources */, - F257F964493A9CD02A6F720C /* OnboardingPageView.swift in Sources */, 7F64FA937B95924B3A44EC12 /* OnboardingScreen.swift in Sources */, CE7148E80F09B7305E026AC6 /* OnboardingViewModel.swift in Sources */, 992477AB8E3F3C36D627D32E /* OnboardingViewModelProtocol.swift in Sources */, @@ -4443,9 +4443,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 13.3; MARKETING_VERSION = 1.1.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4517,9 +4517,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 13.3; MARKETING_VERSION = 1.1.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; diff --git a/ElementX/Sources/Other/Extensions/AttributedString.swift b/ElementX/Sources/Other/Extensions/AttributedString.swift index bb838ddba..19f9ea621 100644 --- a/ElementX/Sources/Other/Extensions/AttributedString.swift +++ b/ElementX/Sources/Other/Extensions/AttributedString.swift @@ -49,4 +49,18 @@ extension AttributedString { replacement.link = url replaceSubrange(range, with: replacement) } + + /// Returns a new attributed string, created by replacing any hard coded `UIFont` with + /// a simple presentation intent. This allows simple formatting to respond to Dynamic Type. + /// + /// Currently only supports regular and bold weights. + func replacingFontWithPresentationIntent() -> AttributedString { + var newValue = self + for run in newValue.runs { + guard let font = run.uiKit.font else { continue } + newValue[run.range].inlinePresentationIntent = font.fontDescriptor.symbolicTraits.contains(.traitBold) ? .stronglyEmphasized : nil + newValue[run.range].uiKit.font = nil + } + return newValue + } } diff --git a/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift b/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift new file mode 100644 index 000000000..80b6f3f5d --- /dev/null +++ b/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift @@ -0,0 +1,161 @@ +// +// 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 + +/// A layout that separates the main content of a screen from the buttons shown at +/// the bottom for a dialogs that fill the entire screen. On larger devices (iPad/Mac), +/// the height is constrained to keep the content relatively close to the buttons. If +/// the content overflows the space available, it will become scrollable. +/// +/// The background color behind the buttons is read from the `backgroundStyle` +/// environment value, so make sure to set this to match the screen's background. +struct FullscreenDialog: View { + @Environment(\.dynamicTypeSize) private var dynamicTypeSize + + /// Padding applied to the top of the content automatically. Use `UIConstants` for preset values. + var topPadding: CGFloat = UIConstants.titleTopPaddingToNavigationBar + /// Padding applied to the content and buttons automatically + var horizontalPadding: CGFloat = 16 + /// The spacing between the content and the buttons. + var spacing: CGFloat = 16 + + /// The main content shown at the top of the layout. + @ViewBuilder var content: () -> Content + /// The content shown at the bottom of the layout. + @ViewBuilder var bottomContent: () -> BottomContent + + var body: some View { + if dynamicTypeSize < .accessibility1 { + standardLayout + } else { + accessibilityLayout + } + } + + /// A layout where the content scrolls with the bottom content overlaid. Used with regular font sizes. + var standardLayout: some View { + GeometryReader { geometry in + ScrollView { + VStack { + Spacer() + .frame(height: UIConstants.spacerHeight(in: geometry)) + + content() + .readableFrame() + .padding(.horizontal, horizontalPadding) + .padding(.top, topPadding) + } + } + .scrollBounceBehavior(.basedOnSize) + .safeAreaInset(edge: .bottom) { + VStack { + bottomContent() + .readableFrame() + .padding(.horizontal, horizontalPadding) + .padding(.top, spacing) + .padding(.bottom, UIConstants.actionButtonBottomPadding) + + Spacer() + .frame(height: UIConstants.spacerHeight(in: geometry)) + } + .background() + } + } + } + + /// A continuously scrolling layout used for accessibility font sizes. + var accessibilityLayout: some View { + GeometryReader { geometry in + ScrollView { + VStack { + Spacer() + .frame(height: UIConstants.spacerHeight(in: geometry)) + + content() + .readableFrame() + .padding(.horizontal, horizontalPadding) + .padding(.top, topPadding) + + Spacer(minLength: spacing) + + bottomContent() + .readableFrame() + .padding(.horizontal, horizontalPadding) + .padding(.bottom, UIConstants.actionButtonBottomPadding) + + Spacer() + .frame(height: UIConstants.spacerHeight(in: geometry)) + } + .frame(minHeight: geometry.size.height) + } + .scrollBounceBehavior(.basedOnSize) + } + } +} + +struct FullscreenDialog_Previews: PreviewProvider { + static var previews: some View { + FullscreenDialog(topPadding: UIConstants.iconTopPaddingToNavigationBar) { + content + } bottomContent: { + buttons + } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.element.background)) + } + + private static var content: some View { + VStack(spacing: 8) { + Image(systemName: "globe") + .font(.system(size: 50)) + .foregroundColor(.compound.textPrimary) + .padding() + .background(Color.compound.bgSubtlePrimary, in: Circle()) + .padding(.bottom, 8) + Text("Hello, World") + .font(.compound.headingLG) + .foregroundColor(.compound.textPrimary) + Text("I am a subtitle") + .font(.compound.bodyLG) + .foregroundColor(.compound.textSecondary) + .padding(.bottom) + + VStack(alignment: .leading, spacing: 6) { + Label("We care about you", systemImage: "person") + Label("Environmentally focussed", systemImage: "leaf") + Label("All of the options", systemImage: "wrench") + Label("Fun to use", systemImage: "logo.xbox") + } + } + } + + private static var buttons: some View { + VStack(spacing: 16) { + Button { } label: { + Text("Continue") + .font(.compound.bodyLGSemibold) + } + .buttonStyle(.elementAction(.xLarge)) + + Button { } label: { + Text("More options") + .font(.compound.bodyLGSemibold) + .padding(14) + } + } + } +} diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift b/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift index 2987e00e0..d0bd0df6d 100644 --- a/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift +++ b/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift @@ -38,8 +38,8 @@ struct AnalyticsPromptScreenViewState: BindableState { /// A collection of strings for the UI that need to be parsed from HTML struct AnalyticsPromptScreenStrings { let optInContent: AttributedString - let point1 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptDataUsage) ?? AttributedString(L10n.screenAnalyticsPromptDataUsage) - let point2 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptThirdPartySharing) ?? AttributedString(L10n.screenAnalyticsPromptThirdPartySharing) + let point1 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptDataUsage)?.replacingFontWithPresentationIntent() ?? AttributedString(L10n.screenAnalyticsPromptDataUsage) + let point2 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptThirdPartySharing)?.replacingFontWithPresentationIntent() ?? AttributedString(L10n.screenAnalyticsPromptThirdPartySharing) let point3 = L10n.screenAnalyticsPromptSettings init(termsURL: URL) { diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift b/ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift index 1b8f51b2d..e1637da64 100644 --- a/ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift +++ b/ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift @@ -18,37 +18,16 @@ import SwiftUI /// A prompt that asks the user whether they would like to enable Analytics or not. struct AnalyticsPromptScreen: View { - private let horizontalPadding: CGFloat = 16 - @ObservedObject var context: AnalyticsPromptScreenViewModel.Context var body: some View { - GeometryReader { geometry in - ScrollView { - Spacer() - .frame(height: UIConstants.spacerHeight(in: geometry)) - - mainContent - .readableFrame() - .padding(.horizontal, horizontalPadding) - .padding(.top, UIConstants.onboardingBreakerScreenTopPadding) - .padding(.bottom, 8) - } - .safeAreaInset(edge: .bottom) { - VStack { - buttons - .readableFrame() - .padding(.horizontal, horizontalPadding) - .padding(.bottom, UIConstants.actionButtonBottomPadding) - - Spacer() - .frame(height: UIConstants.spacerHeight(in: geometry)) - } - .padding(.top, 8) - .background(Color.element.background.ignoresSafeArea()) - } - .background(Color.element.background.ignoresSafeArea()) + FullscreenDialog(topPadding: UIConstants.onboardingBreakerScreenTopPadding) { + mainContent + } bottomContent: { + buttons } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.element.background)) .navigationBarHidden(true) .navigationBarBackButtonHidden(true) } @@ -95,7 +74,7 @@ struct AnalyticsPromptScreen: View { /// The stack of enable/disable buttons. private var buttons: some View { - VStack { + VStack(spacing: 16) { Button { context.send(viewAction: .enable) } label: { Text(L10n.actionEnable) .font(.compound.bodyLGSemibold) @@ -106,7 +85,7 @@ struct AnalyticsPromptScreen: View { Button { context.send(viewAction: .disable) } label: { Text(L10n.actionNotNow) .font(.compound.bodyLGSemibold) - .padding(12) + .padding(14) } .accessibilityIdentifier(A11yIdentifiers.analyticsPromptScreen.notNow) } diff --git a/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift b/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift index 19814c783..dd87f55f9 100644 --- a/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift +++ b/ElementX/Sources/Screens/Authentication/ServerConfirmationScreen/View/ServerConfirmationScreen.swift @@ -20,20 +20,13 @@ struct ServerConfirmationScreen: View { @ObservedObject var context: ServerConfirmationScreenViewModel.Context var body: some View { - ScrollView { + FullscreenDialog(topPadding: UIConstants.iconTopPaddingToNavigationBar) { header - .padding(.top, UIConstants.iconTopPaddingToNavigationBar) - .padding(.horizontal, 16) - .readableFrame() - } - .background(Color.element.background.ignoresSafeArea()) - .safeAreaInset(edge: .bottom) { + } bottomContent: { buttons - .padding(.horizontal, 16) - .padding(.vertical, 16) - .readableFrame() - .background(Color.element.background.ignoresSafeArea()) } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.element.background)) .introspectViewController { viewController in guard let window = viewController.view.window else { return } context.send(viewAction: .updateWindow(window)) @@ -62,7 +55,7 @@ struct ServerConfirmationScreen: View { /// The action buttons shown at the bottom of the view. var buttons: some View { - VStack(spacing: 24) { + VStack(spacing: 16) { Button { context.send(viewAction: .confirm) } label: { Text(L10n.actionContinue) } @@ -72,7 +65,7 @@ struct ServerConfirmationScreen: View { Button { context.send(viewAction: .changeServer) } label: { Text(L10n.screenServerConfirmationChangeServer) .font(.compound.bodyLGSemibold) - .padding(.vertical, 14) + .padding(14) } .accessibilityIdentifier(A11yIdentifiers.serverConfirmationScreen.changeServer) } diff --git a/ElementX/Sources/Screens/OnboardingScreen/OnboardingModels.swift b/ElementX/Sources/Screens/OnboardingScreen/OnboardingModels.swift index 127bbd68c..8aa8f8770 100644 --- a/ElementX/Sources/Screens/OnboardingScreen/OnboardingModels.swift +++ b/ElementX/Sources/Screens/OnboardingScreen/OnboardingModels.swift @@ -33,24 +33,7 @@ enum OnboardingViewModelAction { case login } -struct OnboardingViewState: BindableState { - /// An array containing all content of the carousel pages - let content: [OnboardingPageContent] - var bindings: OnboardingBindings - - init() { - content = [ - OnboardingPageContent(title: L10n.screenOnboardingWelcomeTitle.tinting(".", color: .element.accent), - message: L10n.screenOnboardingWelcomeSubtitle(InfoPlistReader.main.bundleDisplayName), - image: Asset.Images.onboardingAppLogo) - ] - bindings = OnboardingBindings() - } -} - -struct OnboardingBindings { - var pageIndex = 0 -} +struct OnboardingViewState: BindableState { } enum OnboardingViewAction { case login diff --git a/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingPageIndicator.swift b/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingPageIndicator.swift deleted file mode 100644 index 58ad7e160..000000000 --- a/ElementX/Sources/Screens/OnboardingScreen/View/OnboardingPageIndicator.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// 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 SwiftUI - -struct OnboardingPageIndicator: View { - /// The number of pages that are shown. - let pageCount: Int - /// The index of the current page - let pageIndex: Int - - internal init(pageCount: Int, pageIndex: Int) { - self.pageCount = pageCount - - // Clamp the page index to handle the hidden page. - if pageIndex == -1 { - self.pageIndex = pageCount - 1 - } else { - self.pageIndex = pageIndex % pageCount - } - } - - var body: some View { - HStack { - ForEach(0..