From 39908892116aacbbc6ddce0f37c10fc759ddb9d7 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 25 Oct 2024 13:36:04 +0200 Subject: [PATCH] Video playback improvements --- .../Sources/UniversalVideoNode.swift | 9 ++++ .../ChatItemGalleryFooterContentNode.swift | 2 +- .../Sources/GalleryControllerNode.swift | 4 ++ .../GalleryUI/Sources/GalleryItemNode.swift | 4 ++ .../Items/UniversalVideoGalleryItem.swift | 45 ++++++++++++++++--- .../Sources/HLSVideoJSNativeContentNode.swift | 5 +++ .../Sources/NativeVideoContent.swift | 4 ++ .../Sources/PlatformVideoContent.swift | 3 ++ .../Sources/SystemVideoContent.swift | 3 ++ .../Sources/WebEmbedPlayerNode.swift | 3 ++ .../Sources/WebEmbedVideoContent.swift | 3 ++ 11 files changed, 79 insertions(+), 6 deletions(-) diff --git a/submodules/AccountContext/Sources/UniversalVideoNode.swift b/submodules/AccountContext/Sources/UniversalVideoNode.swift index 8ff0bf498f..70dc74e14d 100644 --- a/submodules/AccountContext/Sources/UniversalVideoNode.swift +++ b/submodules/AccountContext/Sources/UniversalVideoNode.swift @@ -44,6 +44,7 @@ public protocol UniversalVideoContentNode: AnyObject { func setCanPlaybackWithoutHierarchy(_ canPlaybackWithoutHierarchy: Bool) func enterNativePictureInPicture() -> Bool func exitNativePictureInPicture() + func setNativePictureInPictureIsActive(_ value: Bool) } public protocol UniversalVideoContent { @@ -445,4 +446,12 @@ public final class UniversalVideoNode: ASDisplayNode { } }) } + + public func setNativePictureInPictureIsActive(_ value: Bool) { + self.manager.withUniversalVideoContent(id: self.content.id, { contentNode in + if let contentNode = contentNode { + contentNode.setNativePictureInPictureIsActive(value) + } + }) + } } diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index 082471eebc..ce9f9e7b01 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -957,7 +957,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll } else if media is TelegramMediaImage { hasCaption = true } else if let file = media as? TelegramMediaFile { - hasCaption = file.mimeType.hasPrefix("image/") + hasCaption = file.mimeType.hasPrefix("image/") || file.mimeType.hasPrefix("video/") } else if media is TelegramMediaInvoice { hasCaption = true } diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 84cccba91c..8947584ff1 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -470,6 +470,10 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0 let minimalDismissDistance = scrollView.contentSize.height / 12.0 if abs(velocity.y) > 1.0 || abs(distanceFromEquilibrium) > minimalDismissDistance { + if distanceFromEquilibrium > 1.0, let centralItemNode = self.pager.centralItemNode(), centralItemNode.maybePerformActionForSwipeDismiss() { + return + } + if let backgroundColor = self.backgroundNode.backgroundColor { self.backgroundNode.layer.animate(from: backgroundColor, to: UIColor(white: 0.0, alpha: 0.0).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.2, removeOnCompletion: false) } diff --git a/submodules/GalleryUI/Sources/GalleryItemNode.swift b/submodules/GalleryUI/Sources/GalleryItemNode.swift index 222a018862..51b9630b0a 100644 --- a/submodules/GalleryUI/Sources/GalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/GalleryItemNode.swift @@ -100,6 +100,10 @@ open class GalleryItemNode: ASDisplayNode { open func animateOut(to node: (ASDisplayNode, CGRect, () -> (UIView?, UIView?)), addToTransitionSurface: (UIView) -> Void, completion: @escaping () -> Void) { } + open func maybePerformActionForSwipeDismiss() -> Bool { + return false + } + open func contentSize() -> CGSize? { return nil } diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index b92f8f4562..793e8f63e2 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -1128,6 +1128,7 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict private let node: UniversalVideoNode private let willBegin: (NativePictureInPictureContentImpl) -> Void private let didBegin: (NativePictureInPictureContentImpl) -> Void + private let didEnd: (NativePictureInPictureContentImpl) -> Void private let expand: (@escaping () -> Void) -> Void private var pictureInPictureTimer: SwiftSignalKit.Timer? private var didExpand: Bool = false @@ -1138,7 +1139,7 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict private var isNativePictureInPictureActiveDisposable: Disposable? - init(context: AccountContext, mediaManager: MediaManager, accountId: AccountRecordId, hiddenMedia: (MessageId, Media)?, videoNode: UniversalVideoNode, canSkip: Bool, willBegin: @escaping (NativePictureInPictureContentImpl) -> Void, didBegin: @escaping (NativePictureInPictureContentImpl) -> Void, expand: @escaping (@escaping () -> Void) -> Void) { + init(context: AccountContext, mediaManager: MediaManager, accountId: AccountRecordId, hiddenMedia: (MessageId, Media)?, videoNode: UniversalVideoNode, canSkip: Bool, willBegin: @escaping (NativePictureInPictureContentImpl) -> Void, didBegin: @escaping (NativePictureInPictureContentImpl) -> Void, didEnd: @escaping (NativePictureInPictureContentImpl) -> Void, expand: @escaping (@escaping () -> Void) -> Void) { self.context = context self.mediaManager = mediaManager self.accountId = accountId @@ -1146,6 +1147,7 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict self.node = videoNode self.willBegin = willBegin self.didBegin = didBegin + self.didEnd = didEnd self.expand = expand super.init() @@ -1255,6 +1257,7 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex) self.hiddenMediaManagerIndex = nil } + self.didEnd(self) } public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) { @@ -1683,8 +1686,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { isAdaptive = true } - //TODO:release - //self.settingsBarButton.setContent(.image(generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/NavigationSettingsQAuto"), color: .white))) let _ = isAdaptive let dimensions = item.content.dimensions @@ -2701,6 +2702,20 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { }) } + override func maybePerformActionForSwipeDismiss() -> Bool { + if let data = self.context.currentAppConfiguration.with({ $0 }).data, let _ = data["ios_killswitch_disable_swipe_pip"] { + return false + } + + if #available(iOS 15.0, *) { + if let nativePictureInPictureContent = self.nativePictureInPictureContent as? NativePictureInPictureContentImpl { + nativePictureInPictureContent.beginPictureInPicture() + return true + } + } + return false + } + override func title() -> Signal { return self._title.get() } @@ -2874,6 +2889,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } if #available(iOS 15.0, *) { + var didExpand = false let content = NativePictureInPictureContentImpl(context: self.context, mediaManager: self.context.sharedContext.mediaManager, accountId: self.context.account.id, hiddenMedia: hiddenMedia, videoNode: videoNode, canSkip: true, willBegin: { [weak self] content in guard let self, let controller = self.galleryController(), let navigationController = self.baseNavigationController() else { return @@ -2885,12 +2901,30 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { controller.view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in self?.completeCustomDismiss(true) }) + if let videoNode = self.videoNode { + videoNode.setNativePictureInPictureIsActive(false) + } + didExpand = false }, didBegin: { [weak self] _ in guard let self else { return } let _ = self + }, didEnd: { [weak self] _ in + guard let self else { + return + } + if let videoNode = self.videoNode { + videoNode.setNativePictureInPictureIsActive(false) + } + + if !didExpand { + self.activePictureInPictureController = nil + self.activePictureInPictureNavigationController = nil + } }, expand: { [weak self] completion in + didExpand = true + guard let self, let activePictureInPictureController = self.activePictureInPictureController, let activePictureInPictureNavigationController = self.activePictureInPictureNavigationController else { completion() return @@ -2904,9 +2938,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { }) activePictureInPictureController.view.alpha = 1.0 - activePictureInPictureController.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, completion: { _ in - completion() + activePictureInPictureController.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.35, completion: { _ in }) + + completion() }) self.nativePictureInPictureContent = content diff --git a/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift b/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift index b189b313ff..9963ace1b5 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift @@ -1600,6 +1600,7 @@ final class HLSVideoJSNativeContentNode: ASDisplayNode, UniversalVideoContentNod } func setCanPlaybackWithoutHierarchy(_ canPlaybackWithoutHierarchy: Bool) { + self.playerNode.setCanPlaybackWithoutHierarchy(canPlaybackWithoutHierarchy) } func enterNativePictureInPicture() -> Bool { @@ -1608,6 +1609,10 @@ final class HLSVideoJSNativeContentNode: ASDisplayNode, UniversalVideoContentNod func exitNativePictureInPicture() { } + + func setNativePictureInPictureIsActive(_ value: Bool) { + self.imageNode.isHidden = !value + } } private func serializeRanges(_ ranges: RangeSet) -> [Double] { diff --git a/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift index e2b186fc63..888710395b 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift @@ -716,4 +716,8 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent func exitNativePictureInPicture() { } + + func setNativePictureInPictureIsActive(_ value: Bool) { + self.imageNode.isHidden = value + } } diff --git a/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift index a7e26bb004..1a2ca5b5a5 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/PlatformVideoContent.swift @@ -482,4 +482,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte func exitNativePictureInPicture() { } + + func setNativePictureInPictureIsActive(_ value: Bool) { + } } diff --git a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift index 46d2e9ed8e..ea061ae46c 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift @@ -319,5 +319,8 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent func exitNativePictureInPicture() { } + + func setNativePictureInPictureIsActive(_ value: Bool) { + } } diff --git a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift index 294aa1211c..781ebfeb9c 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedPlayerNode.swift @@ -234,4 +234,7 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate { func exitNativePictureInPicture() { } + + func setNativePictureInPictureIsActive(_ value: Bool) { + } } diff --git a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift index 71c3c44d87..60aa892cb6 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/WebEmbedVideoContent.swift @@ -218,4 +218,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode { func exitNativePictureInPicture() { } + + func setNativePictureInPictureIsActive(_ value: Bool) { + } }