From ef4bbb9f6b6c036973ea5524be2d7f46be35c6a4 Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:57:04 +0200 Subject: [PATCH] Pinned Items Banner UI (#3072) --- ElementX.xcodeproj/project.pbxproj | 54 +++++----- .../Screens/RoomScreen/RoomScreenModels.swift | 1 + .../RoomScreen/RoomScreenViewModel.swift | 6 +- .../PinnedItemsBannerView.swift | 98 +++++++++++++++++++ .../PinnedItemsIndicatorView.swift | 66 +++++++++++++ .../Screens/RoomScreen/View/RoomScreen.swift | 10 ++ .../View/DeveloperOptionsScreen.swift | 1 + ...est_pinnedItemsBannerView-iPad-en-GB.1.png | 3 + ...st_pinnedItemsBannerView-iPad-pseudo.1.png | 3 + ...innedItemsBannerView-iPhone-15-en-GB.1.png | 3 + ...nnedItemsBannerView-iPhone-15-pseudo.1.png | 3 + ..._pinnedItemsIndicatorView-iPad-en-GB.1.png | 3 + ...pinnedItemsIndicatorView-iPad-pseudo.1.png | 3 + ...edItemsIndicatorView-iPhone-15-en-GB.1.png | 3 + ...dItemsIndicatorView-iPhone-15-pseudo.1.png | 3 + 15 files changed, 236 insertions(+), 24 deletions(-) create mode 100644 ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsBannerView.swift create mode 100644 ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsIndicatorView.swift create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-en-GB.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-pseudo.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-en-GB.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-pseudo.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-en-GB.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-pseudo.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-en-GB.1.png create mode 100644 PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-pseudo.1.png diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 3989e7415..3b0d9dc08 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 56; objects = { /* Begin PBXAggregateTarget section */ @@ -723,6 +723,8 @@ A6F345328CCC5C9B0DAE2257 /* LogViewerScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB05221D7D941CC82DC8480 /* LogViewerScreenViewModel.swift */; }; A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; }; A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; }; + A75DDB792C4A9EDE00A80681 /* PinnedItemsBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75DDB782C4A9EDE00A80681 /* PinnedItemsBannerView.swift */; }; + A75DDB7C2C4AA89400A80681 /* PinnedItemsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75DDB7B2C4AA89400A80681 /* PinnedItemsIndicatorView.swift */; }; A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; }; A816F7087C495D85048AC50E /* RoomMemberDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */; }; A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; }; @@ -1163,13 +1165,13 @@ 033DB41C51865A2E83174E87 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; 035177BCD8E8308B098AC3C2 /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = ""; }; 0376C429FAB1687C3D905F3E /* MockCoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCoder.swift; sourceTree = ""; }; - 0392E3FDE372C9B56FEEED8B /* test_voice_message.m4a */ = {isa = PBXFileReference; path = test_voice_message.m4a; sourceTree = ""; }; + 0392E3FDE372C9B56FEEED8B /* test_voice_message.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = ""; }; 03DD998E523D4EC93C7ED703 /* RoomNotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; 03FABD73FD8086EFAB699F42 /* MediaUploadPreviewScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadPreviewScreenViewModelTests.swift; sourceTree = ""; }; 044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = ""; }; 045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; }; 046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = ""; }; - 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = ""; }; 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; 0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = ""; }; @@ -1229,7 +1231,7 @@ 127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentValuePublisher.swift; sourceTree = ""; }; 128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = ""; }; 12F1E7F9C2BE8BB751037826 /* WaitlistScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenCoordinator.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 = ""; }; 136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = ""; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -1319,7 +1321,7 @@ 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = ""; }; 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = ""; }; 260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = ""; }; - 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = ""; }; + 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = ""; }; 26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = ""; }; 26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = ""; }; 2721D7B051F0159AA919DA05 /* RoomChangePermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -1382,7 +1384,7 @@ 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = ""; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 35FA991289149D31F4286747 /* UserPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreference.swift; sourceTree = ""; }; - 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = ""; }; 376D941BF8BB294389C0DE24 /* MapTilerURLBuildersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerURLBuildersTests.swift; sourceTree = ""; }; 37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiItem.swift; sourceTree = ""; }; @@ -1723,7 +1725,7 @@ 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.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 = ""; }; 8F21ED7205048668BEB44A38 /* AppActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppActivityView.swift; sourceTree = ""; }; 8F6210134203BE1F2DD5C679 /* RoomDirectoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectoryCell.swift; sourceTree = ""; }; 8F841F219ACDFC1D3F42FEFB /* RoomChangeRolesScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenViewModelTests.swift; sourceTree = ""; }; @@ -1816,6 +1818,8 @@ A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = ""; }; A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = ""; }; A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = ""; }; + A75DDB782C4A9EDE00A80681 /* PinnedItemsBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedItemsBannerView.swift; sourceTree = ""; }; + A75DDB7B2C4AA89400A80681 /* PinnedItemsIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedItemsIndicatorView.swift; sourceTree = ""; }; A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = ""; }; A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = ""; }; A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = ""; }; @@ -1884,7 +1888,7 @@ B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.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 = ""; }; B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = ""; }; B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = ""; }; @@ -1998,7 +2002,7 @@ CE47A97726F0675DEE387BF9 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = ""; }; CEE0E6043EFCF6FD2A341861 /* TimelineReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReplyView.swift; sourceTree = ""; }; CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = ""; }; - CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = ""; }; + CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = ""; }; D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = ""; }; D086854995173E897F993C26 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; D09A267106B9585D3D0CFC0D /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = ""; }; @@ -2123,7 +2127,7 @@ ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = ""; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = ""; }; ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = ""; }; - ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = ""; }; + ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = ""; }; ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; 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 = ""; }; @@ -2146,7 +2150,7 @@ F174A5627CDB3CAF280D1880 /* EmojiPickerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenModels.swift; sourceTree = ""; }; F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProvider.swift; sourceTree = ""; }; F1B8500C152BC59445647DA8 /* UnsupportedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsupportedRoomTimelineItem.swift; sourceTree = ""; }; - F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = ""; }; + F2D513D2477B57F90E98EEC0 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; sourceTree = ""; }; F2E4EF80DFB8FE7C4469B15D /* RoomDirectorySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreen.swift; sourceTree = ""; }; F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegexTests.swift; sourceTree = ""; }; F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineItem.swift; sourceTree = ""; }; @@ -3819,6 +3823,7 @@ 79023E5904B155E8E2B8B502 /* View */ = { isa = PBXGroup; children = ( + A75DDB7A2C4AA85000A80681 /* PinnedItemsBanner */, 422724361B6555364C43281E /* RoomHeaderView.swift */, 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */, 4552D3466B1453F287223ADA /* SwipeRightAction.swift */, @@ -4412,6 +4417,15 @@ path = View; sourceTree = ""; }; + A75DDB7A2C4AA85000A80681 /* PinnedItemsBanner */ = { + isa = PBXGroup; + children = ( + A75DDB782C4A9EDE00A80681 /* PinnedItemsBannerView.swift */, + A75DDB7B2C4AA89400A80681 /* PinnedItemsIndicatorView.swift */, + ); + path = PinnedItemsBanner; + sourceTree = ""; + }; A78C2592419CA4C76FBA8FD2 /* Application */ = { isa = PBXGroup; children = ( @@ -6098,6 +6112,7 @@ 5780E444F405AA1304E1C23E /* DeveloperOptionsScreen.swift in Sources */, 5DD85A0FE3D85AEC3C7EFE36 /* DeveloperOptionsScreenCoordinator.swift in Sources */, 784592335560C2E91D32D177 /* DeveloperOptionsScreenModels.swift in Sources */, + A75DDB792C4A9EDE00A80681 /* PinnedItemsBannerView.swift in Sources */, B3D652AA1654270742072FB3 /* DeveloperOptionsScreenViewModel.swift in Sources */, B9CB30FED3E29D2036EA3FCC /* DeveloperOptionsScreenViewModelProtocol.swift in Sources */, 037006FB6DF1374F94E4058D /* Dictionary.swift in Sources */, @@ -6230,6 +6245,7 @@ C5A07E2D88BE7D51DCECD166 /* LoginScreenModels.swift in Sources */, BDA68E8D95B2B24B28825B8B /* LoginScreenViewModel.swift in Sources */, A5B9EF45C7B8ACEB4954AE36 /* LoginScreenViewModelProtocol.swift in Sources */, + A75DDB7C2C4AA89400A80681 /* PinnedItemsIndicatorView.swift in Sources */, 4362C770C7E05ADC750E5070 /* LongPressWithFeedback.swift in Sources */, B94368839BDB69172E28E245 /* MXLog.swift in Sources */, C1D0AB8222D7BAFC9AF9C8C0 /* MapLibreMapView.swift in Sources */, @@ -6926,9 +6942,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_NSE", - ); + OTHER_SWIFT_FLAGS = "-DIS_NSE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_NAME = NSE; @@ -6977,9 +6991,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_MAIN_APP", - ); + OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(APP_NAME)"; @@ -7005,9 +7017,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_MAIN_APP", - ); + OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(APP_NAME)"; @@ -7252,9 +7262,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_NSE", - ); + OTHER_SWIFT_FLAGS = "-DIS_NSE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_NAME = NSE; diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift index 449b893ab..3b5fb5baf 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift @@ -165,6 +165,7 @@ struct RoomScreenViewState: BindableState { var canCurrentUserRedactSelf = false var canCurrentUserPin = false var isViewSourceEnabled: Bool + var isPinningEnabled = false var canJoinCall = false var hasOngoingCall = false diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 98545970f..1b8bd9927 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -360,7 +360,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol state.canCurrentUserRedactSelf = false } - if appSettings.pinningEnabled, + if state.isPinningEnabled, case let .success(value) = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomPinnedEvents) { state.canCurrentUserPin = value } else { @@ -414,6 +414,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol .weakAssign(to: \.state.isViewSourceEnabled, on: self) .store(in: &cancellables) + appSettings.$pinningEnabled + .weakAssign(to: \.state.isPinningEnabled, on: self) + .store(in: &cancellables) + roomProxy.membersPublisher .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateMembers($0) } diff --git a/ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsBannerView.swift b/ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsBannerView.swift new file mode 100644 index 000000000..80bcb915e --- /dev/null +++ b/ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsBannerView.swift @@ -0,0 +1,98 @@ +// +// Copyright 2024 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 Compound +import SwiftUI + +struct PinnedItemsBannerView: View { + let pinIndex: Int + let pinsCount: Int + let pinContent: AttributedString + + let onMainButtonTap: () -> Void + let onViewAllButtonTap: () -> Void + + private var bannerIndicatorDescription: AttributedString { + let index = pinIndex + 1 + let boldPlaceholder = "{bold}" + var finalString = AttributedString(L10n.Screen.Room.pinnedBannerIndicatorDescription(boldPlaceholder)) + var boldString = AttributedString(L10n.Screen.Room.pinnedBannerIndicator(index, pinsCount)) + boldString.bold() + finalString.replace(boldPlaceholder, with: boldString) + return finalString + } + + var body: some View { + HStack(spacing: 0) { + mainButton + viewAllButton + } + .padding(.vertical, 16) + .padding(.leading, 16) + .background(Color.compound.bgCanvasDefault) + .shadow(color: Color(red: 0.11, green: 0.11, blue: 0.13).opacity(0.1), radius: 12, x: 0, y: 4) + } + + private var mainButton: some View { + Button { onMainButtonTap() } label: { + HStack(spacing: 0) { + HStack(spacing: 10) { + PinnedItemsIndicatorView(pinIndex: pinIndex, pinsCount: pinsCount) + .accessibilityHidden(true) + CompoundIcon(\.pinSolid, size: .small, relativeTo: .compound.bodyMD) + .foregroundColor(Color.compound.iconSecondaryAlpha) + .accessibilityHidden(true) + content + } + .frame(maxWidth: .infinity, alignment: .leading) + } + } + .accessibilityElement(children: .contain) + } + + private var viewAllButton: some View { + Button { onViewAllButtonTap() } label: { + Text(L10n.Screen.Room.pinnedBannerViewAllButtonTitle) + .font(.compound.bodyMDSemibold) + .foregroundStyle(Color.compound.textPrimary) + .padding(.horizontal, 16) + .padding(.vertical, 5) + } + } + + private var content: some View { + VStack(alignment: .leading, spacing: 0) { + Text(bannerIndicatorDescription) + .font(.compound.bodySM) + .foregroundColor(.compound.textActionAccent) + .lineLimit(1) + Text(pinContent) + .font(.compound.bodyMD) + .foregroundColor(.compound.textPrimary) + .lineLimit(1) + } + } +} + +struct PinnedItemsBannerView_Previews: PreviewProvider, TestablePreview { + static var previews: some View { + PinnedItemsBannerView(pinIndex: 0, + pinsCount: 3, + pinContent: .init(stringLiteral: "Content"), + onMainButtonTap: { }, + onViewAllButtonTap: { }) + } +} diff --git a/ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsIndicatorView.swift b/ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsIndicatorView.swift new file mode 100644 index 000000000..3afc12e2b --- /dev/null +++ b/ElementX/Sources/Screens/RoomScreen/View/PinnedItemsBanner/PinnedItemsIndicatorView.swift @@ -0,0 +1,66 @@ +// +// Copyright 2024 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 Compound +import SwiftUI + +struct PinnedItemsIndicatorView: View { + let pinIndex: Int + let pinsCount: Int + + private var activeIndex: Int { + pinIndex % 3 + } + + private var shownIndicators: Int { + if pinsCount <= 3 { + return pinsCount + } + let remainingPins = pinsCount - pinIndex + return remainingPins >= 3 ? 3 : pinsCount % 3 + } + + var body: some View { + VStack(spacing: 2) { + ForEach(0..<3, id: \.self) { index in + Rectangle() + .fill(index == activeIndex ? Color.compound.iconAccentPrimary : Color.compound._borderInteractiveSecondaryAlpha) + .scaledFrame(width: 2, height: 11) + .opacity(index < shownIndicators ? 1 : 0) + } + } + } +} + +struct PinnedItemsIndicatorView_Previews: PreviewProvider, TestablePreview { + static var previews: some View { + HStack(spacing: 10) { + PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 1) + PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 2) + PinnedItemsIndicatorView(pinIndex: 1, pinsCount: 2) + PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 3) + PinnedItemsIndicatorView(pinIndex: 1, pinsCount: 3) + PinnedItemsIndicatorView(pinIndex: 2, pinsCount: 3) + PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 5) + PinnedItemsIndicatorView(pinIndex: 1, pinsCount: 5) + PinnedItemsIndicatorView(pinIndex: 2, pinsCount: 5) + PinnedItemsIndicatorView(pinIndex: 3, pinsCount: 5) + PinnedItemsIndicatorView(pinIndex: 4, pinsCount: 5) + PinnedItemsIndicatorView(pinIndex: 3, pinsCount: 4) + } + .previewLayout(.sizeThatFits) + } +} diff --git a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift index 7aab36f60..93836cf22 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift @@ -48,6 +48,16 @@ struct RoomScreen: View { .environmentObject(context) .environment(\.roomContext, context) } + .overlay(alignment: .top) { + if context.viewState.isPinningEnabled { + // TODO: Implement tapping logic + hiding when scrolling + PinnedItemsBannerView(pinIndex: 1, + pinsCount: 3, + pinContent: .init(stringLiteral: "Content"), + onMainButtonTap: { }, + onViewAllButtonTap: { }) + } + } .navigationTitle(L10n.screenRoomTitle) // Hidden but used for back button text. .navigationBarTitleDisplayMode(.inline) .navigationBarHidden(isNavigationBarHidden) diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index b7ac6656a..0147a8559 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -37,6 +37,7 @@ struct DeveloperOptionsScreen: View { Section("Message Pinning") { Toggle(isOn: $context.pinningEnabled) { Text("Enable message pinning") + Text("WIP - uses mocked content") } } diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-en-GB.1.png new file mode 100644 index 000000000..98e556874 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08962f7405eacac00d0fbc410e806820202105b03558fbc962ab4d5ba53f0293 +size 85241 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-pseudo.1.png new file mode 100644 index 000000000..4990d784f --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cb3d02aa9af3d6d2fcd8d5d1195ab8c7cb9dcb1a7544fe5eceb468638770009 +size 94063 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-en-GB.1.png new file mode 100644 index 000000000..7c0822bd4 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:22228167b8b988f91baac100e980d41039a3b942be219cdfa7d8a9bfd8947610 +size 42906 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-pseudo.1.png new file mode 100644 index 000000000..cf9afef3b --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsBannerView-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:116c3b0f009cbcb102fa574605577da8d2d68f95d33746f778b99afb19cec872 +size 46568 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-en-GB.1.png new file mode 100644 index 000000000..78cde9524 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63322034c8b0c9b6c6b0c465f2881e4e6416c54116901500d2174aef183b46a6 +size 4523 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-pseudo.1.png new file mode 100644 index 000000000..78cde9524 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63322034c8b0c9b6c6b0c465f2881e4e6416c54116901500d2174aef183b46a6 +size 4523 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-en-GB.1.png new file mode 100644 index 000000000..4363b7c91 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b779d7079302a9fa2406ee3d0d632586cb83802a2630087a2dae5e49c23b45a8 +size 2601 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-pseudo.1.png new file mode 100644 index 000000000..4363b7c91 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_pinnedItemsIndicatorView-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b779d7079302a9fa2406ee3d0d632586cb83802a2630087a2dae5e49c23b45a8 +size 2601