From e59a705459cbce81f7f0e1926d00980906427bd7 Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:56:51 +0000 Subject: [PATCH] Use TimelineMediaQuickLook in the MediaEventsTimelineScreen. (#3598) --- ElementX.xcodeproj/project.pbxproj | 4 ++ ElementX/Resources/clear.png | Bin 0 -> 1302 bytes .../MediaEventsTimelineFlowCoordinator.swift | 3 +- .../TimelineMediaPreviewController.swift | 37 ++++++++++++++++-- .../TimelineMediaPreviewModels.swift | 4 +- ...MediaEventsTimelineScreenCoordinator.swift | 4 +- .../MediaEventsTimelineScreenModels.swift | 2 + .../MediaEventsTimelineScreenViewModel.swift | 27 ++++++++++++- .../View/MediaEventsTimelineScreen.swift | 25 +++++++----- ...diaPreviewDetailsView-iPad-en-GB.Image.png | 4 +- ...iewDetailsView-iPad-en-GB.Unknown-type.png | 4 +- ...iaPreviewDetailsView-iPad-pseudo.Image.png | 4 +- ...eviewDetailsView-iPhone-16-en-GB.Image.png | 4 +- ...tailsView-iPhone-16-en-GB.Unknown-type.png | 4 +- ...viewDetailsView-iPhone-16-pseudo.Image.png | 4 +- ...iewRedactConfirmationView-iPad-en-GB.1.png | 4 +- ...ewRedactConfirmationView-iPad-pseudo.1.png | 4 +- ...dactConfirmationView-iPhone-16-en-GB.1.png | 4 +- ...actConfirmationView-iPhone-16-pseudo.1.png | 4 +- 19 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 ElementX/Resources/clear.png diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 7fc893359..36b076f9c 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -922,6 +922,7 @@ BE8E5985771DF9137C6CE89A /* ProcessInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077B01C13BBA2996272C5FB5 /* ProcessInfo.swift */; }; BEA646DF302711A753F0D420 /* MapTilerStyleBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 225EFCA26877E75CDFE7F48D /* MapTilerStyleBuilderProtocol.swift */; }; BEC6DFEA506085D3027E353C /* MediaEventsTimelineScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002399C6CB875C4EBB01CBC0 /* MediaEventsTimelineScreen.swift */; }; + BFDDAF1A36FBC7CF63DCB7DD /* clear.png in Resources */ = {isa = PBXBuildFile; fileRef = 17F7A723A46DF5C95BE15EBF /* clear.png */; }; BFEB24336DFD5F196E6F3456 /* IntentionalMentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DF5CBAF69BDF5DF31C661E1 /* IntentionalMentions.swift */; }; C0090506A52A1991BAF4BA68 /* NotificationSettingsChatType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07579F9C29001E40715F3014 /* NotificationSettingsChatType.swift */; }; C022284E2774A5E1EF683B4D /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */; }; @@ -1408,6 +1409,7 @@ 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = ""; }; 1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationTests.swift; sourceTree = ""; }; 17A8AA0DFA06012A9DAB951E /* TimelineProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxyMock.swift; sourceTree = ""; }; + 17F7A723A46DF5C95BE15EBF /* clear.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = clear.png; sourceTree = ""; }; 18486B87745B1811E7FBD3D2 /* AnalyticsPromptScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenModels.swift; sourceTree = ""; }; 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = ""; }; 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxy.swift; sourceTree = ""; }; @@ -2958,6 +2960,7 @@ isa = PBXGroup; children = ( 01C4C7DB37597D7D8379511A /* Assets.xcassets */, + 17F7A723A46DF5C95BE15EBF /* clear.png */, A0C06C0F6A8621B22BFAEB56 /* Localizations */, 8AEA6A91159FA0D3EAFCCB0D /* Sounds */, ); @@ -6204,6 +6207,7 @@ 5FCD8AFA364206EE32B909A3 /* Settings.bundle in Resources */, CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */, 2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */, + BFDDAF1A36FBC7CF63DCB7DD /* clear.png in Resources */, 147597951DB07123A87AA1D1 /* landscape_test_image.jpg in Resources */, FDC67E8C0EDCB00ABC66C859 /* landscape_test_video.mov in Resources */, E67418DACEDBC29E988E6ACD /* message.caf in Resources */, diff --git a/ElementX/Resources/clear.png b/ElementX/Resources/clear.png new file mode 100644 index 0000000000000000000000000000000000000000..07fc8418cb1ee0de4bb01856c30d3650125b66e4 GIT binary patch literal 1302 zcmZ`(OK;Oa5MKACkWvm%5Go)nb3sV)+D=-Om1Bw4&;*eZg@6(csBW?Wi^Ln*Tg6D6 zxS$@85J%w9U(f^BUJ*wQ{0q+f0cPzyTsK*1cV}n5ZyviIAJz7D*RmT~gwR^0Y}a9z z#LTR~di(0nBXJ1oyW8mG_szd>_(hwQZncW;ft*1r(q*(LAc7@rpyfzL=!JA+BEORE zjxY;=(GjfZ8qDrT7cGtO?_n3C3{%99_L>{gUfO0!y%cbHG* zEmc!B#mdUEZ2FxpsoRf6bU2liH=GX$#>3%I9p+W$zs7p8Sj3uv4I>ALT=350PMGt8 zJF%0oADaek-yLw5d9v{99I!)PQWOzrGU7aG=uRVf!Kf@K5DN>|RSnOgako2%CMffj|5W}ODCcPMV!x^HMOur5{;pEIYaQ|5Ee<(4s`q||9vYigerFlkOxpZYF^ z?sd3q&ctchEDzLnIJHEp<#Z#bYmITMCFn6G#jZlv zbR6!a`MOSwJlWJ<#tzQFMlMV&zWPKL#4Q$Sp~tK&P{;jhW!FnzENJ1?iv6IGxz*km XKayo6eLDU2PqcRB;huf6z5n4q^VwAC literal 0 HcmV?d00001 diff --git a/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift index 6965a1053..14d78941d 100644 --- a/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/MediaEventsTimelineFlowCoordinator.swift @@ -86,7 +86,8 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol { mediaPlayerProvider: MediaPlayerProvider(), voiceMessageMediaManager: userSession.voiceMessageMediaManager, appMediator: appMediator, - emojiProvider: emojiProvider) + emojiProvider: emojiProvider, + userIndicatorController: userIndicatorController) let coordinator = MediaEventsTimelineScreenCoordinator(parameters: parameters) diff --git a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewController.swift b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewController.swift index e78f15321..f0569d915 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewController.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewController.swift @@ -28,8 +28,10 @@ class TimelineMediaPreviewController: QLPreviewController, QLPreviewControllerDa headerHostingController = UIHostingController(rootView: HeaderView(context: viewModel.context)) headerHostingController.view.backgroundColor = .clear + headerHostingController.sizingOptions = .intrinsicContentSize captionHostingController = UIHostingController(rootView: CaptionView(context: viewModel.context)) captionHostingController.view.backgroundColor = .clear + captionHostingController.sizingOptions = .intrinsicContentSize detailsHostingController = UIHostingController(rootView: TimelineMediaPreviewDetailsView(context: viewModel.context)) detailsHostingController.view.backgroundColor = .compound.bgCanvasDefault @@ -87,9 +89,7 @@ class TimelineMediaPreviewController: QLPreviewController, QLPreviewControllerDa navigationBar?.topItem?.titleView = headerHostingController.view - if navigationBar?.topItem?.rightBarButtonItems?.count == 1 { - navigationBar?.topItem?.rightBarButtonItems?.append(UIBarButtonItem(image: UIImage(systemSymbol: .infoCircle), style: .plain, target: self, action: #selector(presentMediaDetails))) - } + updateBarButtons() } // MARK: QLPreviewControllerDataSource @@ -111,6 +111,21 @@ class TimelineMediaPreviewController: QLPreviewController, QLPreviewControllerDa present(detailsHostingController, animated: true) } + + private var detailsButtonIcon: UIImage { + guard let bundle = Bundle(url: Bundle.main.bundleURL.appending(path: "CompoundDesignTokens_CompoundDesignTokens.bundle")) else { + return UIImage(systemSymbol: .infoCircle) + } + + return UIImage(named: "info", in: bundle, compatibleWith: nil) ?? UIImage(systemSymbol: .infoCircle) + } + + private func updateBarButtons() { + if navigationBar?.topItem?.rightBarButtonItems?.count == 1 { + let button = UIBarButtonItem(image: detailsButtonIcon, style: .plain, target: self, action: #selector(presentMediaDetails)) + navigationBar?.topItem?.rightBarButtonItems?.append(button) + } + } } // MARK: - Subviews @@ -143,7 +158,21 @@ private struct CaptionView: View { .frame(maxWidth: .infinity, alignment: .leading) .fixedSize(horizontal: false, vertical: true) .padding(16) - .background(.ultraThinMaterial) + .background { + BlurView(style: .systemChromeMaterial) // Darkest material available, matches the bottom bar when content is beneath. + } } } } + +private struct BlurView: UIViewRepresentable { + var style: UIBlurEffect.Style + + func makeUIView(context: Context) -> UIVisualEffectView { + UIVisualEffectView(effect: UIBlurEffect(style: style)) + } + + func updateUIView(_ uiView: UIVisualEffectView, context: Context) { + uiView.effect = UIBlurEffect(style: style) + } +} diff --git a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModels.swift b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModels.swift index 24ccd0198..057b28034 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModels.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewModels.swift @@ -31,7 +31,9 @@ class TimelineMediaPreviewItem: NSObject, QLPreviewItem { // MARK: QLPreviewItem var previewItemURL: URL? { - fileHandle?.url + // Falling back to a clear image allows the presentation animation to work when + // the item is in the event cache and just needs to be loaded from the store. + fileHandle?.url ?? Bundle.main.url(forResource: "clear", withExtension: "png") } var previewItemTitle: String? { diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenCoordinator.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenCoordinator.swift index d05fc4cd7..98523013e 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenCoordinator.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenCoordinator.swift @@ -17,6 +17,7 @@ struct MediaEventsTimelineScreenCoordinatorParameters { let voiceMessageMediaManager: VoiceMessageMediaManagerProtocol let appMediator: AppMediatorProtocol let emojiProvider: EmojiProviderProtocol + let userIndicatorController: UserIndicatorControllerProtocol } enum MediaEventsTimelineScreenCoordinatorAction { } @@ -59,7 +60,8 @@ final class MediaEventsTimelineScreenCoordinator: CoordinatorProtocol { viewModel = MediaEventsTimelineScreenViewModel(mediaTimelineViewModel: mediaTimelineViewModel, filesTimelineViewModel: filesTimelineViewModel, - mediaProvider: parameters.mediaProvider) + mediaProvider: parameters.mediaProvider, + userIndicatorController: parameters.userIndicatorController) } func toPresentable() -> AnyView { diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenModels.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenModels.swift index c9f761a28..82b187785 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenModels.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenModels.swift @@ -23,10 +23,12 @@ struct MediaEventsTimelineScreenViewState: BindableState { struct MediaEventsTimelineScreenViewStateBindings { var screenMode: MediaEventsTimelineScreenMode + var mediaPreviewViewModel: TimelineMediaPreviewViewModel? } enum MediaEventsTimelineScreenViewAction { case changedScreenMode case oldestItemDidAppear case oldestItemDidDisappear + case tappedItem(RoomTimelineItemViewState) } diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift index 62b1ab6c1..09d28e478 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift @@ -13,6 +13,7 @@ typealias MediaEventsTimelineScreenViewModelType = StateStoreViewModel