From 6854173dae723f4e26f75bd6601296f23fc19083 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 May 2021 23:31:03 +0400 Subject: [PATCH] Wallpaper updates --- .../AnimatedNavigationStripeNode.swift | 25 +- submodules/Display/Source/NavigationBar.swift | 46 +- .../Display/Source/ViewController.swift | 8 +- .../Sources/PlainGradientBackground.swift | 153 ----- .../Sources/SoftwareGradientBackground.swift | 11 + submodules/SettingsUI/BUILD | 1 + .../BubbleSettingsController.swift | 6 +- .../TextSizeSelectionController.swift | 6 +- .../Themes/SettingsThemeWallpaperNode.swift | 18 + .../Themes/ThemePreviewControllerNode.swift | 6 +- .../Themes/ThemeSettingsChatPreviewItem.swift | 11 +- .../Themes/WallpaperGalleryController.swift | 7 +- .../Sources/Themes/WallpaperGalleryItem.swift | 22 + submodules/ShareController/BUILD | 1 + .../Sources/ShareController.swift | 1 + .../StickerPreviewControllerNode.swift | 2 +- .../Sources/StickerResources.swift | 2 +- .../SyncCore/Sources/TelegramWallpaper.swift | 12 +- .../Sources/ChatMessageBubbleImages.swift | 2 +- .../DefaultDarkPresentationTheme.swift | 2 +- .../Sources/DefaultDayPresentationTheme.swift | 37 +- submodules/TelegramUI/BUILD | 1 + .../TelegramUI/Sources/ChatController.swift | 69 +-- .../Sources/ChatControllerNode.swift | 566 +----------------- .../Sources/ChatInfoTitlePanelNode.swift | 16 +- .../Sources/ChatMediaInputNode.swift | 57 +- .../ChatPinnedMessageTitlePanelNode.swift | 13 +- .../ChatReportPeerTitlePanelNode.swift | 18 +- .../ChatRequestInProgressTitlePanelNode.swift | 13 +- .../Sources/ChatTitleAccessoryPanelNode.swift | 9 +- .../Sources/ChatToastAlertPanelNode.swift | 12 +- .../Sources/UndoOverlayControllerNode.swift | 5 +- submodules/WallpaperBackgroundNode/BUILD | 22 + .../Sources}/WallpaperBackgroundNode.swift | 74 ++- 34 files changed, 356 insertions(+), 898 deletions(-) delete mode 100644 submodules/GradientBackground/Sources/PlainGradientBackground.swift create mode 100644 submodules/WallpaperBackgroundNode/BUILD rename submodules/{Display/Source => WallpaperBackgroundNode/Sources}/WallpaperBackgroundNode.swift (57%) diff --git a/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift b/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift index c95452e7e4..be5b3498a8 100644 --- a/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift +++ b/submodules/AnimatedNavigationStripeNode/Sources/AnimatedNavigationStripeNode.swift @@ -61,26 +61,35 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { private let foregroundLineNode: ASImageNode private var backgroundLineNodes: [Int: BackgroundLineNode] = [:] private var removingBackgroundLineNodes: [BackgroundLineNode] = [] - + + private let maskContainerNode: ASDisplayNode private let topShadowNode: ASImageNode private let bottomShadowNode: ASImageNode + private let middleShadowNode: ASDisplayNode private var currentForegroundImage: UIImage? private var currentBackgroundImage: UIImage? private var currentClearBackgroundImage: UIImage? override public init() { + self.maskContainerNode = ASDisplayNode() + self.foregroundLineNode = ASImageNode() self.topShadowNode = ASImageNode() self.bottomShadowNode = ASImageNode() + self.middleShadowNode = ASDisplayNode() + self.middleShadowNode.backgroundColor = .white super.init() self.clipsToBounds = true - + + self.addSubnode(self.maskContainerNode) self.addSubnode(self.foregroundLineNode) - self.addSubnode(self.topShadowNode) - self.addSubnode(self.bottomShadowNode) + self.maskContainerNode.addSubnode(self.topShadowNode) + self.maskContainerNode.addSubnode(self.bottomShadowNode) + self.maskContainerNode.addSubnode(self.middleShadowNode) + self.layer.mask = self.maskContainerNode.layer } public func update(colors: Colors, configuration: Configuration, transition: ContainedViewLayoutTransition) { @@ -123,7 +132,7 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { context.clear(CGRect(origin: CGPoint(), size: size)) var locations: [CGFloat] = [1.0, 0.0] - let colors: [CGColor] = [colors.clearBackground.cgColor, colors.clearBackground.withAlphaComponent(0.0).cgColor] + let colors: [CGColor] = [UIColor.white.withAlphaComponent(0.0).cgColor, UIColor.white.cgColor] let colorSpace = CGColorSpaceCreateDeviceRGB() let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! @@ -135,7 +144,7 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { context.clear(CGRect(origin: CGPoint(), size: size)) var locations: [CGFloat] = [1.0, 0.0] - let colors: [CGColor] = [colors.clearBackground.cgColor, colors.clearBackground.withAlphaComponent(0.0).cgColor] + let colors: [CGColor] = [UIColor.white.withAlphaComponent(0.0).cgColor, UIColor.white.cgColor] let colorSpace = CGColorSpaceCreateDeviceRGB() let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! @@ -161,6 +170,8 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { transition.updateFrame(node: self.topShadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: defaultVerticalInset))) transition.updateFrame(node: self.bottomShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: configuration.height - defaultVerticalInset), size: CGSize(width: 2.0, height: defaultVerticalInset))) + transition.updateFrame(node: self.middleShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: defaultVerticalInset), size: CGSize(width: 2.0, height: configuration.height - defaultVerticalInset * 2.0))) + transition.updateFrame(node: self.maskContainerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: configuration.height))) let availableVerticalHeight: CGFloat = configuration.height - defaultVerticalInset * 2.0 @@ -214,7 +225,7 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode { itemNode.overlayNode.image = self.currentClearBackgroundImage self.backgroundLineNodes[index] = itemNode self.insertSubnode(itemNode.lineNode, belowSubnode: self.foregroundLineNode) - self.insertSubnode(itemNode.overlayNode, belowSubnode: self.topShadowNode) + self.topShadowNode.supernode?.insertSubnode(itemNode.overlayNode, belowSubnode: self.topShadowNode) backgroundItemNodesToOffset.append(itemNode) } itemNodeTransition.updateFrame(node: itemNode.lineNode, frame: itemFrame, beginWithCurrentState: true) diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index 0d79d222b2..9123374a6d 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -148,19 +148,30 @@ public final class NavigationBackgroundNode: ASDisplayNode { if self.color.lightness > 0.6 { if #available(iOS 13.0, *) { - self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialLight)) + self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialLight)) } else { self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) } } else { if #available(iOS 13.0, *) { - self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialDark)) + self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialDark)) } else { self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) } } if let effectView = self.effectView { + if let sublayer = effectView.layer.sublayers?[0], let filters = sublayer.filters { + sublayer.filters = filters.filter { filter in + guard let filter = filter as? NSObject else { + return true + } + if String(describing: filter) != "gaussianBlur" { + return false + } + return true + } + } effectView.frame = self.bounds self.view.insertSubview(effectView, at: 0) } @@ -171,9 +182,15 @@ public final class NavigationBackgroundNode: ASDisplayNode { } public func update(size: CGSize, transition: ContainedViewLayoutTransition) { - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - if let effectView = self.effectView { - transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: size)) + let contentFrame = CGRect(origin: CGPoint(), size: size) + transition.updateFrame(node: self.backgroundNode, frame: contentFrame) + if let effectView = self.effectView, effectView.frame != contentFrame { + transition.updateFrame(layer: effectView.layer, frame: contentFrame) + if let sublayers = effectView.layer.sublayers { + for sublayer in sublayers { + transition.updateFrame(layer: sublayer, frame: contentFrame) + } + } } } } @@ -185,7 +202,7 @@ open class NavigationBar: ASDisplayNode { var presentationData: NavigationBarPresentationData - private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat, CGFloat, Bool)? + private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, Bool)? private var requestedLayout: Bool = false var requestContainerLayout: (ContainedViewLayoutTransition) -> Void = { _ in } @@ -911,19 +928,22 @@ open class NavigationBar: ASDisplayNode { if let validLayout = self.validLayout, self.requestedLayout { self.requestedLayout = false - self.updateLayout(size: validLayout.0, defaultHeight: validLayout.1, additionalHeight: validLayout.2, leftInset: validLayout.3, rightInset: validLayout.4, appearsHidden: validLayout.5, transition: .immediate) + self.updateLayout(size: validLayout.0, defaultHeight: validLayout.1, additionalHeight: validLayout.2, additionalBackgroundHeight: validLayout.3, leftInset: validLayout.4, rightInset: validLayout.5, appearsHidden: validLayout.6, transition: .immediate) } } - func updateLayout(size: CGSize, defaultHeight: CGFloat, additionalHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, appearsHidden: Bool, transition: ContainedViewLayoutTransition) { + func updateLayout(size: CGSize, defaultHeight: CGFloat, additionalHeight: CGFloat, additionalBackgroundHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, appearsHidden: Bool, transition: ContainedViewLayoutTransition) { if self.layoutSuspended { return } - self.validLayout = (size, defaultHeight, additionalHeight, leftInset, rightInset, appearsHidden) + self.validLayout = (size, defaultHeight, additionalHeight, additionalBackgroundHeight, leftInset, rightInset, appearsHidden) - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - self.backgroundNode.update(size: size, transition: transition) + let backgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + additionalBackgroundHeight)) + if self.backgroundNode.frame != backgroundFrame { + transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) + self.backgroundNode.update(size: backgroundFrame.size, transition: transition) + } let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? NavigationBar.defaultSecondaryContentHeight : 0.0 @@ -1164,7 +1184,7 @@ open class NavigationBar: ASDisplayNode { let node = NavigationButtonNode() node.updateManualText(self.backButtonNode.manualText) node.color = accentColor - if let (size, defaultHeight, _, _, _, _) = self.validLayout { + if let (size, defaultHeight, _, _, _, _, _) = self.validLayout { let _ = node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight)) node.frame = self.backButtonNode.frame } @@ -1187,7 +1207,7 @@ open class NavigationBar: ASDisplayNode { } node.updateItems(items) node.color = accentColor - if let (size, defaultHeight, _, _, _, _) = self.validLayout { + if let (size, defaultHeight, _, _, _, _, _) = self.validLayout { let _ = node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight)) node.frame = self.backButtonNode.frame } diff --git a/submodules/Display/Source/ViewController.swift b/submodules/Display/Source/ViewController.swift index 2ecff6f2c3..abdf10f2b3 100644 --- a/submodules/Display/Source/ViewController.swift +++ b/submodules/Display/Source/ViewController.swift @@ -373,8 +373,12 @@ public enum TabBarItemContextActionType { deinit { } + + open func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + self.applyNavigationBarLayout(layout, additionalBackgroundHeight: 0.0, transition: transition) + } - private func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + public func applyNavigationBarLayout(_ layout: ContainerViewLayout, additionalBackgroundHeight: CGFloat, transition: ContainedViewLayoutTransition) { let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0 var defaultNavigationBarHeight: CGFloat if self._presentedInModal { @@ -406,7 +410,7 @@ public enum TabBarItemContextActionType { if let _ = navigationBar.contentNode, let _ = navigationBar.secondaryContentNode, !self.displayNavigationBar { navigationBarFrame.origin.y += NavigationBar.defaultSecondaryContentHeight } - navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: defaultNavigationBarHeight, additionalHeight: 0.0, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, transition: transition) + navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: defaultNavigationBarHeight, additionalHeight: 0.0, additionalBackgroundHeight: additionalBackgroundHeight, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, transition: transition) if !transition.isAnimated { navigationBar.layer.cancelAnimationsRecursive(key: "bounds") navigationBar.layer.cancelAnimationsRecursive(key: "position") diff --git a/submodules/GradientBackground/Sources/PlainGradientBackground.swift b/submodules/GradientBackground/Sources/PlainGradientBackground.swift deleted file mode 100644 index 68668d26e4..0000000000 --- a/submodules/GradientBackground/Sources/PlainGradientBackground.swift +++ /dev/null @@ -1,153 +0,0 @@ -import Foundation -import UIKit -import Display -import AsyncDisplayKit - -func shiftArray(array: [CGPoint], offset: Int) -> [CGPoint] { - var newArray = array - var offset = offset - while offset > 0 { - let element = newArray.removeFirst() - newArray.append(element) - offset -= 1 - } - return newArray -} - -private func generateGradientComponent(size: CGSize, color: UIColor) -> UIImage? { - UIGraphicsBeginImageContextWithOptions(size, false, 1.0) - - let c = UIGraphicsGetCurrentContext() - - c?.clear(CGRect(origin: CGPoint.zero, size: size)) - - c?.setBlendMode(.normal) - - var gradLocs: [CGFloat] = [0.0, 0.05, 1.0] - let colorSpace = CGColorSpaceCreateDeviceRGB() - let radius = min(size.width / 2.0, size.height / 2.0) - - let colors = [ - color.cgColor, - color.cgColor, - color.withAlphaComponent(0).cgColor - ] - - let grad = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &gradLocs) - if let grad = grad { - let newPoint = CGPoint(x: size.width / 2.0, y: size.height / 2.0) - - c?.drawRadialGradient(grad, startCenter: newPoint, startRadius: 0, endCenter: newPoint, endRadius: radius, options: []) - } - - let image = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - return image -} - -final class PlainGradientBackgroundNode: ASDisplayNode, GradientBackgroundNode { - private final class PointImage { - let stack: [UIImageView] - - init(image: UIImage, count: Int) { - self.stack = (0 ..< count).map { _ in - let imageView = UIImageView(image: image) - imageView.alpha = min(1.0, (1.0 / CGFloat(count)) * 1.2) - return imageView - } - } - - func updateFrame(frame: CGRect, transition: ContainedViewLayoutTransition) { - let nextFrame = frame - for i in 0 ..< self.stack.count { - transition.updateFrame(view: self.stack[i], frame: nextFrame) - //nextFrame = nextFrame.insetBy(dx: nextFrame.width / 4.0, dy: nextFrame.height / 4.0) - } - } - } - private var pointImages: [PointImage] = [] - private let dimView: UIView - - private var phase: Int = 0 - - private var validLayout: CGSize? - - override public init() { - self.dimView = UIView() - self.dimView.backgroundColor = UIColor(white: 1.0, alpha: 0.0) - - super.init() - - self.phase = 0 - - self.backgroundColor = .white - self.clipsToBounds = true - - let colors: [UIColor] = [ - UIColor(rgb: 0x7FA381), - UIColor(rgb: 0xFFF5C5), - UIColor(rgb: 0x336F55), - UIColor(rgb: 0xFBE37D) - ] - - let layerCount = 1 - - for i in 0 ..< colors.count { - let image = generateGradientComponent(size: CGSize(width: 300.0, height: 300.0), color: colors[i].withMultiplied(hue: 1.0, saturation: 1.0, brightness: 1.0))! - - let pointImage = PointImage(image: image, count: layerCount) - - self.pointImages.append(pointImage) - } - - for i in 0 ..< layerCount { - for pointImage in self.pointImages { - self.view.addSubview(pointImage.stack[i]) - } - } - - self.view.addSubview(self.dimView) - } - - deinit { - } - - public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { - self.validLayout = size - - self.dimView.frame = CGRect(origin: CGPoint(), size: size) - - let positions: [CGPoint] - - let basePositions: [CGPoint] = [ - CGPoint(x: 0.80, y: 0.10), - CGPoint(x: 0.60, y: 0.20), - CGPoint(x: 0.35, y: 0.25), - CGPoint(x: 0.25, y: 0.60), - CGPoint(x: 0.20, y: 0.90), - CGPoint(x: 0.40, y: 0.80), - CGPoint(x: 0.65, y: 0.75), - CGPoint(x: 0.75, y: 0.40) - ] - - positions = shiftArray(array: basePositions, offset: self.phase % 8) - - for i in 0 ..< positions.count / 2 { - if self.pointImages.count <= i { - break - } - let position = positions[i * 2] - let pointCenter = CGPoint(x: size.width * position.x, y: size.height * position.y) - let pointSize = CGSize(width: size.width * 1.9, height: size.height * 1.9) - self.pointImages[i].updateFrame(frame: CGRect(origin: CGPoint(x: pointCenter.x - pointSize.width / 2.0, y: pointCenter.y - pointSize.height / 2.0), size: pointSize), transition: transition) - } - } - - public func animateEvent(transition: ContainedViewLayoutTransition) { - self.phase = self.phase + 1 - if let size = self.validLayout { - self.updateLayout(size: size, transition: transition) - } - } -} diff --git a/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift b/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift index 0a38703029..e87ac14ac4 100644 --- a/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift +++ b/submodules/GradientBackground/Sources/SoftwareGradientBackground.swift @@ -3,6 +3,17 @@ import UIKit import Display import AsyncDisplayKit +private func shiftArray(array: [CGPoint], offset: Int) -> [CGPoint] { + var newArray = array + var offset = offset + while offset > 0 { + let element = newArray.removeFirst() + newArray.append(element) + offset -= 1 + } + return newArray +} + private func gatherPositions(_ list: [CGPoint]) -> [CGPoint] { var result: [CGPoint] = [] for i in 0 ..< list.count / 2 { diff --git a/submodules/SettingsUI/BUILD b/submodules/SettingsUI/BUILD index f8ead78c65..aef7b6fda1 100644 --- a/submodules/SettingsUI/BUILD +++ b/submodules/SettingsUI/BUILD @@ -89,6 +89,7 @@ swift_library( "//submodules/WidgetSetupScreen:WidgetSetupScreen", "//submodules/UIKitRuntimeUtils:UIKitRuntimeUtils", "//submodules/DebugSettingsUI:DebugSettingsUI", + "//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode", ], visibility = [ "//visibility:public", diff --git a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift index a507b15de0..2e218df33b 100644 --- a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift +++ b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift @@ -13,6 +13,7 @@ import ChatListUI import WallpaperResources import LegacyComponents import ItemListUI +import WallpaperBackgroundNode private func generateMaskImage(color: UIColor) -> UIImage? { return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in @@ -70,10 +71,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) self.chatBackgroundNode.image = chatControllerBackgroundImage(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: false) - self.chatBackgroundNode.motionEnabled = self.presentationData.chatWallpaper.settings?.motion ?? false - if case .gradient = self.presentationData.chatWallpaper { - self.chatBackgroundNode.imageContentMode = .scaleToFill - } + self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper) self.toolbarNode = BubbleSettingsToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData) diff --git a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift index 4f67af1d58..ade8d233f3 100644 --- a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift +++ b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift @@ -13,6 +13,7 @@ import ChatListUI import WallpaperResources import LegacyComponents import ItemListUI +import WallpaperBackgroundNode private func generateMaskImage(color: UIColor) -> UIImage? { return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in @@ -82,10 +83,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) self.chatBackgroundNode.image = chatControllerBackgroundImage(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: false) - self.chatBackgroundNode.motionEnabled = self.presentationData.chatWallpaper.settings?.motion ?? false - if case .gradient = self.presentationData.chatWallpaper { - self.chatBackgroundNode.imageContentMode = .scaleToFill - } + self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper) self.toolbarNode = TextSelectionToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData) diff --git a/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift b/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift index f1fb72e4cf..d758463866 100644 --- a/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift +++ b/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift @@ -10,6 +10,7 @@ import TelegramPresentationData import AccountContext import RadialStatusNode import WallpaperResources +import GradientBackground private func whiteColorImage(theme: PresentationTheme, color: UIColor) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { return .single({ arguments in @@ -36,6 +37,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { let buttonNode = HighlightTrackingButtonNode() let backgroundNode = ASDisplayNode() let imageNode = TransformImageNode() + private var gradientNode: GradientBackgroundNode? private let statusNode: RadialStatusNode var pressed: (() -> Void)? @@ -71,6 +73,22 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { self.buttonNode.frame = CGRect(origin: CGPoint(), size: size) self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) self.imageNode.frame = CGRect(origin: CGPoint(), size: size) + + if case .builtin = wallpaper { + if self.gradientNode == nil { + let gradientNode = createGradientBackgroundNode() + self.gradientNode = gradientNode + self.addSubnode(gradientNode) + } + } else if let gradientNode = self.gradientNode { + self.gradientNode = nil + gradientNode.removeFromSupernode() + } + + if let gradientNode = self.gradientNode { + gradientNode.frame = CGRect(origin: CGPoint(), size: size) + gradientNode.updateLayout(size: size, transition: .immediate) + } let state: RadialStatusNodeState = selected ? .check(.white) : .none self.statusNode.transitionToState(state, animated: false, completion: {}) diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index 430610ebe6..e5221be5ff 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -12,6 +12,7 @@ import AccountContext import ChatListUI import WallpaperResources import LegacyComponents +import WallpaperBackgroundNode private func generateMaskImage(color: UIColor) -> UIImage? { return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in @@ -110,10 +111,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { if self.instantChatBackgroundNode.image != nil { self.ready.set(.single(true)) } - if case .gradient = wallpaper { - self.instantChatBackgroundNode.imageContentMode = .scaleToFill - } - self.instantChatBackgroundNode.motionEnabled = previewTheme.chat.defaultWallpaper.settings?.motion ?? false + self.instantChatBackgroundNode.update(wallpaper: wallpaper) self.instantChatBackgroundNode.view.contentMode = .scaleAspectFill self.remoteChatBackgroundNode = TransformImageNode() diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift index e4d0877f1f..006fb4b353 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift @@ -11,6 +11,7 @@ import TelegramUIPreferences import ItemListUI import PresentationDataUtils import AccountContext +import WallpaperBackgroundNode struct ChatPreviewMessageItem: Equatable { static func == (lhs: ChatPreviewMessageItem, rhs: ChatPreviewMessageItem) -> Bool { @@ -95,7 +96,7 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem { } class ThemeSettingsChatPreviewItemNode: ListViewItemNode { - private let backgroundNode: ASImageNode + private let backgroundNode: WallpaperBackgroundNode private let topStripeNode: ASDisplayNode private let bottomStripeNode: ASDisplayNode private let maskNode: ASImageNode @@ -109,11 +110,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { private let disposable = MetaDisposable() init() { - self.backgroundNode = ASImageNode() - self.backgroundNode.isLayerBacked = true - self.backgroundNode.displaysAsynchronously = false - self.backgroundNode.displayWithoutProcessing = true - self.backgroundNode.contentMode = .scaleAspectFill + self.backgroundNode = WallpaperBackgroundNode() self.topStripeNode = ASDisplayNode() self.topStripeNode.isLayerBacked = true @@ -287,6 +284,8 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) strongSelf.backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0) + strongSelf.backgroundNode.update(wallpaper: item.wallpaper) + strongSelf.backgroundNode.updateLayout(size: strongSelf.backgroundNode.bounds.size, transition: .immediate) strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0) strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)) strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)) diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift index 7924a034f8..ea73251cd8 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift @@ -500,7 +500,12 @@ public class WallpaperGalleryController: ViewController { applyWallpaper(wallpaper) }) } else { - applyWallpaper(wallpaper) + var updatedWallpaper = wallpaper + if var settings = wallpaper.settings { + settings.motion = options.contains(.motion) + updatedWallpaper = updatedWallpaper.withUpdatedSettings(settings) + } + applyWallpaper(updatedWallpaper) } default: break diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift index 83039987af..22f41f7bc2 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryItem.swift @@ -18,6 +18,7 @@ import GalleryUI import LocalMediaResources import WallpaperResources import AppBundle +import WallpaperBackgroundNode struct WallpaperGalleryItemArguments { let colorPreview: Bool @@ -90,6 +91,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { let wrapperNode: ASDisplayNode let imageNode: TransformImageNode + let nativeNode: WallpaperBackgroundNode private let statusNode: RadialStatusNode private let blurredNode: BlurredImageNode let cropNode: WallpaperCropNode @@ -122,6 +124,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { self.wrapperNode = ASDisplayNode() self.imageNode = TransformImageNode() self.imageNode.contentAnimations = .subsequentUpdates + self.nativeNode = WallpaperBackgroundNode() self.cropNode = WallpaperCropNode() self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6)) self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter) @@ -471,9 +474,22 @@ final class WallpaperGalleryItemNode: GalleryItemNode { if self.cropNode.supernode == nil { self.imageNode.contentMode = .scaleAspectFill self.wrapperNode.addSubnode(self.imageNode) + self.wrapperNode.addSubnode(self.nativeNode) } else { self.imageNode.contentMode = .scaleToFill } + + switch entry { + case let .wallpaper(wallpaper, _): + if case .builtin = wallpaper { + self.nativeNode.isHidden = false + self.nativeNode.update(wallpaper: wallpaper) + } else { + self.nativeNode.isHidden = true + } + default: + self.nativeNode.isHidden = true + } self.imageNode.setSignal(signal, dispatchOnDisplayLink: false) self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), custom: patternArguments))() @@ -660,6 +676,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } func setMotionEnabled(_ enabled: Bool, animated: Bool) { + if let entry = self.entry, case let .wallpaper(wallpaper, _) = entry, case .builtin = wallpaper { + return + } + if enabled { let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis) horizontal.minimumRelativeValue = motionAmount @@ -890,6 +910,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode { if self.cropNode.supernode == nil { self.imageNode.frame = self.wrapperNode.bounds + self.nativeNode.frame = self.wrapperNode.bounds + self.nativeNode.updateLayout(size: self.nativeNode.bounds.size, transition: .immediate) self.blurredNode.frame = self.imageNode.frame } else { self.cropNode.frame = self.wrapperNode.bounds diff --git a/submodules/ShareController/BUILD b/submodules/ShareController/BUILD index 0ea81b3ebf..d86123a68d 100644 --- a/submodules/ShareController/BUILD +++ b/submodules/ShareController/BUILD @@ -27,6 +27,7 @@ swift_library( "//submodules/TelegramIntents:TelegramIntents", "//submodules/AccountContext:AccountContext", "//submodules/SegmentedControlNode:SegmentedControlNode", + "//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode", ], visibility = [ "//visibility:public", diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index dcf21b5996..9cd775674c 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -16,6 +16,7 @@ import UrlEscaping import StickerResources import SaveToCameraRoll import TelegramStringFormatting +import WallpaperBackgroundNode public struct ShareControllerAction { let title: String diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift b/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift index 093498780a..edc6b01210 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift @@ -138,7 +138,7 @@ final class StickerPreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(32.0), textColor: .black) break } - self.imageNode.setSignal(chatMessageSticker(account: context.account, file: item.file, small: false)) + self.imageNode.setSignal(chatMessageSticker(account: context.account, file: item.file, small: false, onlyFullSize: false)) if let (layout, navigationBarHeight) = self.containerLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) diff --git a/submodules/StickerResources/Sources/StickerResources.swift b/submodules/StickerResources/Sources/StickerResources.swift index b41cfecd44..7e907abb57 100644 --- a/submodules/StickerResources/Sources/StickerResources.swift +++ b/submodules/StickerResources/Sources/StickerResources.swift @@ -402,7 +402,7 @@ public func chatMessageSticker(postbox: Postbox, file: TelegramMediaFile, small: return nil } - if file.immediateThumbnailData != nil && fullSizeData == nil { + if file.immediateThumbnailData != nil && thumbnailData == nil && fullSizeData == nil { return nil } diff --git a/submodules/SyncCore/Sources/TelegramWallpaper.swift b/submodules/SyncCore/Sources/TelegramWallpaper.swift index 7b500b04de..0e1e5a4b9e 100644 --- a/submodules/SyncCore/Sources/TelegramWallpaper.swift +++ b/submodules/SyncCore/Sources/TelegramWallpaper.swift @@ -1,12 +1,12 @@ import Postbox public struct WallpaperSettings: PostboxCoding, Equatable { - public let blur: Bool - public let motion: Bool - public let color: UInt32? - public let bottomColor: UInt32? - public let intensity: Int32? - public let rotation: Int32? + public var blur: Bool + public var motion: Bool + public var color: UInt32? + public var bottomColor: UInt32? + public var intensity: Int32? + public var rotation: Int32? public init(blur: Bool = false, motion: Bool = false, color: UInt32? = nil, bottomColor: UInt32? = nil, intensity: Int32? = nil, rotation: Int32? = nil) { self.blur = blur diff --git a/submodules/TelegramPresentationData/Sources/ChatMessageBubbleImages.swift b/submodules/TelegramPresentationData/Sources/ChatMessageBubbleImages.swift index 78ffaa5bad..d3aa6134a1 100644 --- a/submodules/TelegramPresentationData/Sources/ChatMessageBubbleImages.swift +++ b/submodules/TelegramPresentationData/Sources/ChatMessageBubbleImages.swift @@ -197,7 +197,7 @@ public func messageBubbleImage(maxCornerRadius: CGFloat, minCornerRadius: CGFloa borderWidth = UIScreenPixel + innerExtension borderOffset = -innerExtension / 2.0 + UIScreenPixel / 2.0 } else { - borderWidth = UIScreenPixel * 2.0 + innerExtension + borderWidth = UIScreenPixel + innerExtension borderOffset = -innerExtension / 2.0 + UIScreenPixel * 2.0 / 2.0 } context.setLineWidth(borderWidth) diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift index 346fbdb355..e5bf1fd51d 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift @@ -250,7 +250,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5), controlColor: UIColor(rgb: 0x767676), accentTextColor: UIColor(rgb: 0xffffff), - backgroundColor: UIColor(rgb: 0x1a1a1a, alpha: 0.5), + backgroundColor: UIColor(rgb: 0x1c1c1d, alpha: 0.7).withMultipliedBrightnessBy(1.1), separatorColor: UIColor(rgb: 0x3d3d40), badgeBackgroundColor: UIColor(rgb: 0xffffff), badgeStrokeColor: UIColor(rgb: 0x1c1c1d), diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index 77044bda03..7c75392bf3 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -337,18 +337,6 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio backgroundColors: PresentationThemeGradientColors(topColor: UIColor(rgb: 0x46739e), bottomColor: UIColor(rgb: 0x2a5982)), buttonColor: .clear ) - - let rootTabBar = PresentationThemeRootTabBar( - backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5), - separatorColor: UIColor(rgb: 0xa3a3a3), - iconColor: UIColor(rgb: 0x959595), - selectedIconColor: UIColor(rgb: 0x007ee5), - textColor: UIColor(rgb: 0x959595), - selectedTextColor: UIColor(rgb: 0x007ee5), - badgeBackgroundColor: UIColor(rgb: 0xff3b30), - badgeStrokeColor: UIColor(rgb: 0xff3b30), - badgeTextColor: UIColor(rgb: 0xffffff) - ) let rootNavigationBar = PresentationThemeRootNavigationBar( buttonColor: UIColor(rgb: 0x007ee5), @@ -357,7 +345,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio secondaryTextColor: UIColor(rgb: 0x787878), controlColor: UIColor(rgb: 0x7e8791), accentTextColor: UIColor(rgb: 0x007ee5), - backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5), + backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.75), separatorColor: UIColor(rgb: 0xc8c7cc), badgeBackgroundColor: UIColor(rgb: 0xff3b30), badgeStrokeColor: UIColor(rgb: 0xff3b30), @@ -369,6 +357,18 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio clearButtonBackgroundColor: UIColor(rgb: 0xE3E3E3, alpha: 0.78), clearButtonForegroundColor: UIColor(rgb: 0x7f7f7f) ) + + let rootTabBar = PresentationThemeRootTabBar( + backgroundColor: rootNavigationBar.backgroundColor, + separatorColor: UIColor(rgb: 0xa3a3a3), + iconColor: UIColor(rgb: 0x959595), + selectedIconColor: UIColor(rgb: 0x007ee5), + textColor: UIColor(rgb: 0x959595), + selectedTextColor: UIColor(rgb: 0x007ee5), + badgeBackgroundColor: UIColor(rgb: 0xff3b30), + badgeStrokeColor: UIColor(rgb: 0xff3b30), + badgeTextColor: UIColor(rgb: 0xffffff) + ) let navigationSearchBar = PresentationThemeNavigationSearchBar( backgroundColor: UIColor(rgb: 0xffffff), @@ -497,7 +497,12 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio onlineDotColor: UIColor(rgb: 0x4cc91f) ) - let bubbleStrokeColor = serviceBackgroundColor.withMultiplied(hue: 0.999, saturation: 1.667, brightness: 1.1).withAlphaComponent(0.2) + let bubbleStrokeColor: UIColor + if day { + bubbleStrokeColor = serviceBackgroundColor.withMultiplied(hue: 0.999, saturation: 1.667, brightness: 1.1).withAlphaComponent(0.2) + } else { + bubbleStrokeColor = UIColor(white: 0.0, alpha: 0.2) + } let message = PresentationThemeChatMessage( incoming: PresentationThemePartedColors( @@ -655,8 +660,8 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio ) let inputPanel = PresentationThemeChatInputPanel( - panelBackgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5), - panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff, alpha: 0.5), + panelBackgroundColor: rootNavigationBar.backgroundColor, + panelBackgroundColorNoWallpaper: rootNavigationBar.backgroundColor, panelSeparatorColor: UIColor(rgb: 0xb2b2b2), panelControlAccentColor: UIColor(rgb: 0x007ee5), panelControlColor: UIColor(rgb: 0x858e99), diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 391f01676d..f7374f2208 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -222,6 +222,7 @@ swift_library( "//submodules/DebugSettingsUI:DebugSettingsUI", "//submodules/ImportStickerPackUI:ImportStickerPackUI", "//submodules/GradientBackground:GradientBackground", + "//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index e467c24954..f2c38d5094 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2701,11 +2701,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId) } } - self.navigationBar?.allowsCustomTransition = { [weak self] in - guard let strongSelf = self else { - return false - } - return !strongSelf.chatDisplayNode.hasEmbeddedTitleContent + self.navigationBar?.allowsCustomTransition = { + return true } self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder) @@ -4564,6 +4561,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } mappedTransition = (ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: deleteItems, insertItems: insertItems, updateItems: transition.updateItems, options: options, scrollToItem: scrollToItem, stationaryItemRange: stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, scrolledToSomeIndex: transition.scrolledToSomeIndex, peerType: transition.peerType, networkType: transition.networkType, animateIn: false, reason: transition.reason, flashIndicators: transition.flashIndicators), updateSizeAndInsets) + }, updateExtraNavigationBarBackgroundHeight: { value in + strongSelf.additionalNavigationBarBackgroundHeight = value }) if let mappedTransition = mappedTransition { @@ -6742,45 +6741,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) } - self.chatDisplayNode.updateHasEmbeddedTitleContent = { [weak self] in - guard let strongSelf = self else { - return - } - - let hasEmbeddedTitleContent = strongSelf.chatDisplayNode.hasEmbeddedTitleContent - let isEmbeddedTitleContentHidden = strongSelf.chatDisplayNode.isEmbeddedTitleContentHidden - - if strongSelf.hasEmbeddedTitleContent != hasEmbeddedTitleContent { - strongSelf.hasEmbeddedTitleContent = hasEmbeddedTitleContent - - if strongSelf.hasEmbeddedTitleContent { - strongSelf.statusBar.statusBarStyle = .White - } else { - strongSelf.statusBar.statusBarStyle = strongSelf.presentationData.theme.rootController.statusBarStyle.style - } - - if let navigationBar = strongSelf.navigationBar { - if let navigationBarCopy = navigationBar.view.snapshotContentTree() { - navigationBar.view.superview?.insertSubview(navigationBarCopy, aboveSubview: navigationBar.view) - navigationBarCopy.alpha = 0.0 - navigationBarCopy.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak navigationBarCopy] _ in - navigationBarCopy?.removeFromSuperview() - }) - } - } - strongSelf.updateNavigationBarPresentation() - } - - if strongSelf.isEmbeddedTitleContentHidden != isEmbeddedTitleContentHidden { - strongSelf.isEmbeddedTitleContentHidden = isEmbeddedTitleContentHidden - - if let navigationBar = strongSelf.navigationBar { - let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut) - transition.updateAlpha(node: navigationBar, alpha: isEmbeddedTitleContentHidden ? 0.0 : 1.0) - } - } - } - self.interfaceInteraction = interfaceInteraction if let search = self.focusOnSearchAfterAppearance { @@ -7344,8 +7304,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return canManagePin } + + private var suspendNavigationBarLayout: Bool = false + private var suspendedNavigationBarLayout: ContainerViewLayout? + private var additionalNavigationBarBackgroundHeight: CGFloat = 0.0 + + override public func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + if self.suspendNavigationBarLayout { + self.suspendedNavigationBarLayout = layout + return + } + self.applyNavigationBarLayout(layout, additionalBackgroundHeight: self.additionalNavigationBarBackgroundHeight, transition: transition) + } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + self.suspendNavigationBarLayout = true super.containerLayoutUpdated(layout, transition: transition) self.validLayout = layout @@ -7365,6 +7338,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion) + }, updateExtraNavigationBarBackgroundHeight: { value in + self.additionalNavigationBarBackgroundHeight = value }) if case .compact = layout.metrics.widthClass { @@ -7379,6 +7354,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } } + + self.suspendNavigationBarLayout = false + if let suspendedNavigationBarLayout = self.suspendedNavigationBarLayout { + self.suspendedNavigationBarLayout = suspendedNavigationBarLayout + self.applyNavigationBarLayout(suspendedNavigationBarLayout, additionalBackgroundHeight: self.additionalNavigationBarBackgroundHeight, transition: transition) + } } func updateChatPresentationInterfaceState(animated: Bool = true, interactive: Bool, saveInterfaceState: Bool = false, _ f: (ChatPresentationInterfaceState) -> ChatPresentationInterfaceState, completion: @escaping (ContainedViewLayoutTransition) -> Void = { _ in }) { diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 59e9150282..4f735344bb 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -16,7 +16,7 @@ import TelegramUniversalVideoContent import ChatInterfaceState import FastBlur import ConfettiEffect -import GradientBackground +import WallpaperBackgroundNode final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem { let itemNode: OverlayMediaItemNode @@ -60,224 +60,6 @@ private struct ChatControllerNodeDerivedLayoutState { var upperInputPositionBound: CGFloat? } -private final class ChatEmbeddedTitleContentNode: ASDisplayNode { - private let context: AccountContext - private let backgroundNode: ASDisplayNode - private let statusBarBackgroundNode: ASDisplayNode - private let videoNode: OverlayUniversalVideoNode - private let disableInternalAnimationIn: Bool - private let isUIHiddenUpdated: () -> Void - private let unembedWhenPortrait: (OverlayMediaItemNode) -> Bool - - private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat)? - - private let dismissed: () -> Void - private let interactiveExtensionUpdated: (ContainedViewLayoutTransition) -> Void - - private(set) var interactiveExtension: CGFloat = 0.0 - private var freezeInteractiveExtension = false - - private(set) var isUIHidden: Bool = false - - var unembedOnLeave: Bool = true - - init(context: AccountContext, videoNode: OverlayUniversalVideoNode, disableInternalAnimationIn: Bool, interactiveExtensionUpdated: @escaping (ContainedViewLayoutTransition) -> Void, dismissed: @escaping () -> Void, isUIHiddenUpdated: @escaping () -> Void, unembedWhenPortrait: @escaping (OverlayMediaItemNode) -> Bool) { - self.dismissed = dismissed - self.interactiveExtensionUpdated = interactiveExtensionUpdated - self.isUIHiddenUpdated = isUIHiddenUpdated - self.unembedWhenPortrait = unembedWhenPortrait - self.disableInternalAnimationIn = disableInternalAnimationIn - - self.context = context - - self.backgroundNode = ASDisplayNode() - self.backgroundNode.backgroundColor = .black - - self.statusBarBackgroundNode = ASDisplayNode() - self.statusBarBackgroundNode.backgroundColor = .black - - self.videoNode = videoNode - - super.init() - - self.clipsToBounds = true - - self.addSubnode(self.backgroundNode) - self.addSubnode(self.statusBarBackgroundNode) - - self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))) - - self.videoNode.controlsAreShowingUpdated = { [weak self] value in - guard let strongSelf = self else { - return - } - strongSelf.isUIHidden = !value - strongSelf.isUIHiddenUpdated() - } - } - - @objc private func panGesture(_ recognizer: UIPanGestureRecognizer) { - switch recognizer.state { - case .began: - break - case .changed: - let translation = recognizer.translation(in: self.view) - - func rubberBandingOffset(offset: CGFloat, bandingStart: CGFloat) -> CGFloat { - let bandedOffset = offset - bandingStart - let range: CGFloat = 600.0 - let coefficient: CGFloat = 0.4 - return bandingStart + (1.0 - (1.0 / ((bandedOffset * coefficient / range) + 1.0))) * range - } - - let offset = rubberBandingOffset(offset: translation.y, bandingStart: 0.0) - - if translation.y > 80.0 { - self.freezeInteractiveExtension = true - self.expandIntoPiP() - } else { - self.interactiveExtension = max(0.0, offset) - self.interactiveExtensionUpdated(.immediate) - } - case .cancelled, .ended: - if !freezeInteractiveExtension { - self.interactiveExtension = 0.0 - self.interactiveExtensionUpdated(.animated(duration: 0.3, curve: .spring)) - } - default: - break - } - } - - func calculateHeight(width: CGFloat) -> CGFloat { - return self.videoNode.content.dimensions.aspectFilled(CGSize(width: width, height: 16.0)).height - } - - func updateLayout(size: CGSize, actualHeight: CGFloat, topInset: CGFloat, interactiveExtension: CGFloat, transition: ContainedViewLayoutTransition, transitionSurface: ASDisplayNode?, navigationBar: NavigationBar?) { - let isFirstTime = self.validLayout == nil - - self.validLayout = (size, actualHeight, topInset, interactiveExtension) - let videoSize = CGSize(width: size.width, height: actualHeight) - - let videoFrame = CGRect(origin: CGPoint(x: 0.0, y: topInset + interactiveExtension + floor((size.height - actualHeight) / 2.0)), size: CGSize(width: videoSize.width, height: videoSize.height - topInset - interactiveExtension)) - - if isFirstTime, let transitionSurface = transitionSurface { - let sourceFrame = self.videoNode.view.convert(self.videoNode.bounds, to: transitionSurface.view) - let targetFrame = self.view.convert(videoFrame, to: transitionSurface.view) - - var navigationBarCopy: UIView? - var navigationBarContainer: UIView? - var nodeTransition = transition - if self.disableInternalAnimationIn { - nodeTransition = .immediate - } else { - self.context.sharedContext.mediaManager.setOverlayVideoNode(nil) - transitionSurface.addSubnode(self.videoNode) - - navigationBarCopy = navigationBar?.view.snapshotView(afterScreenUpdates: true) - let navigationBarContainerValue = UIView() - navigationBarContainer = navigationBarContainerValue - navigationBarContainerValue.frame = targetFrame - navigationBarContainerValue.clipsToBounds = true - transitionSurface.view.addSubview(navigationBarContainerValue) - } - - if !self.disableInternalAnimationIn { - navigationBarContainer?.layer.animateFrame(from: sourceFrame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring) - } - - if !self.disableInternalAnimationIn { - if let navigationBar = navigationBar, let navigationBarCopy = navigationBarCopy { - let navigationFrame = navigationBar.view.convert(navigationBar.bounds, to: transitionSurface.view) - let navigationSourceFrame = navigationFrame.offsetBy(dx: -sourceFrame.minX, dy: -sourceFrame.minY) - let navigationTargetFrame = navigationFrame.offsetBy(dx: -targetFrame.minX, dy: -targetFrame.minY) - navigationBarCopy.frame = navigationTargetFrame - navigationBarContainer?.addSubview(navigationBarCopy) - - navigationBarCopy.layer.animateFrame(from: navigationSourceFrame, to: navigationTargetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring) - navigationBarCopy.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring) - } - } - - self.videoNode.updateRoundCorners(false, transition: nodeTransition) - if !self.disableInternalAnimationIn { - self.videoNode.showControls() - } - - self.videoNode.updateLayout(targetFrame.size, transition: nodeTransition) - self.videoNode.frame = targetFrame - if self.disableInternalAnimationIn { - self.insertSubnode(self.videoNode, belowSubnode: self.statusBarBackgroundNode) - } else { - self.videoNode.layer.animateFrame(from: sourceFrame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak self] _ in - guard let strongSelf = self else { - return - } - navigationBarContainer?.removeFromSuperview() - strongSelf.insertSubnode(strongSelf.videoNode, belowSubnode: strongSelf.statusBarBackgroundNode) - if let (size, actualHeight, topInset, interactiveExtension) = strongSelf.validLayout { - strongSelf.updateLayout(size: size, actualHeight: actualHeight, topInset: topInset, interactiveExtension: interactiveExtension, transition: .immediate, transitionSurface: nil, navigationBar: nil) - } - }) - self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - } - - self.videoNode.customClose = { [weak self] in - guard let strongSelf = self else { - return - } - strongSelf.videoNode.customClose = nil - strongSelf.dismissed() - } - } - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrame(node: self.statusBarBackgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: topInset))) - - if self.videoNode.supernode == self { - self.videoNode.layer.transform = CATransform3DIdentity - transition.updateFrame(node: self.videoNode, frame: videoFrame) - } - } - - func expand(intoLandscape: Bool) { - if intoLandscape { - let unembedWhenPortrait = self.unembedWhenPortrait - self.videoNode.customUnembedWhenPortrait = { videoNode in - unembedWhenPortrait(videoNode) - } - } - self.videoNode.expand() - } - - func expandIntoPiP() { - let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring) - - self.videoNode.customExpand = nil - self.videoNode.customClose = nil - - let previousFrame = self.videoNode.frame - self.context.sharedContext.mediaManager.setOverlayVideoNode(self.videoNode) - self.videoNode.updateRoundCorners(true, transition: transition) - - if let targetSuperview = self.videoNode.view.superview { - let sourceFrame = self.view.convert(previousFrame, to: targetSuperview) - let targetFrame = self.videoNode.frame - self.videoNode.frame = sourceFrame - self.videoNode.updateLayout(sourceFrame.size, transition: .immediate) - - transition.updateFrame(node: self.videoNode, frame: targetFrame) - self.videoNode.updateLayout(targetFrame.size, transition: transition) - } - - self.dismissed() - } -} - -enum ChatEmbeddedTitlePeekContent: Equatable { - case none - case peek -} - class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { let context: AccountContext let chatLocation: ChatLocation @@ -285,8 +67,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { private weak var controller: ChatControllerImpl? let navigationBar: NavigationBar? - private let navigationBarBackroundNode: ASDisplayNode - private let navigationBarSeparatorNode: ASDisplayNode private var backgroundEffectNode: ASDisplayNode? private var containerBackgroundNode: ASImageNode? @@ -301,7 +81,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } let backgroundNode: WallpaperBackgroundNode - var gradientBackgroundNode: GradientBackgroundNode? let backgroundImageDisposable = MetaDisposable() let historyNode: ChatHistoryListNode var blurredHistoryNode: ASImageNode? @@ -449,15 +228,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { private var displayVideoUnmuteTipDisposable: Disposable? private var onLayoutCompletions: [(ContainedViewLayoutTransition) -> Void] = [] - - private var embeddedTitlePeekContent: ChatEmbeddedTitlePeekContent = .none - private var embeddedTitleContentNode: ChatEmbeddedTitleContentNode? - private var dismissedEmbeddedTitleContentNode: ChatEmbeddedTitleContentNode? - var hasEmbeddedTitleContent: Bool { - return self.embeddedTitleContentNode != nil - } - private var didProcessExperimentalEmbedUrl: String? - + init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, chatPresentationInterfaceState: ChatPresentationInterfaceState, automaticMediaDownloadSettings: MediaAutoDownloadSettings, navigationBar: NavigationBar?, controller: ChatControllerImpl?) { self.context = context self.chatLocation = chatLocation @@ -469,12 +240,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.backgroundNode = WallpaperBackgroundNode() self.backgroundNode.displaysAsynchronously = false - - if chatPresentationInterfaceState.chatWallpaper.isBuiltin { - self.gradientBackgroundNode = createGradientBackgroundNode() - } else { - self.gradientBackgroundNode = nil - } self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer() self.titleAccessoryPanelContainer.clipsToBounds = true @@ -506,12 +271,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme, dateTimeFormat: self.chatPresentationInterfaceState.dateTimeFormat) self.navigateButtons.accessibilityElementsHidden = true - - self.navigationBarBackroundNode = ASDisplayNode() - self.navigationBarBackroundNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.backgroundColor - - self.navigationBarSeparatorNode = ASDisplayNode() - self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor var getContentAreaInScreenSpaceImpl: (() -> CGRect)? var onTransitionEventImpl: ((ContainedViewLayoutTransition) -> Void)? @@ -532,10 +291,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } onTransitionEventImpl = { [weak self] transition in - guard let strongSelf = self, let gradientBackgroundNode = strongSelf.gradientBackgroundNode else { + guard let strongSelf = self else { return } - gradientBackgroundNode.animateEvent(transition: transition) + strongSelf.backgroundNode.animateEvent(transition: transition) } self.controller?.presentationContext.topLevelSubview = { [weak self] in @@ -604,39 +363,28 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { strongSelf.interactiveEmojis = emojis } }) - - if case .gradient = chatPresentationInterfaceState.chatWallpaper { - self.backgroundNode.imageContentMode = .scaleToFill - } else { - self.backgroundNode.imageContentMode = .scaleAspectFill - } - self.backgroundNode.motionEnabled = chatPresentationInterfaceState.chatWallpaper.settings?.motion ?? false + + self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper) self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8) self.historyNode.enableExtractedBackgrounds = true self.addSubnode(self.backgroundNode) - if let gradientBackgroundNode = self.gradientBackgroundNode { - self.addSubnode(gradientBackgroundNode) - } self.addSubnode(self.historyNodeContainer) self.addSubnode(self.navigateButtons) - self.addSubnode(self.titleAccessoryPanelContainer) self.addSubnode(self.inputPanelBackgroundNode) self.addSubnode(self.inputPanelBackgroundSeparatorNode) self.addSubnode(self.inputContextPanelContainer) - - self.addSubnode(self.navigationBarBackroundNode) - self.addSubnode(self.navigationBarSeparatorNode) self.addSubnode(self.messageTransitionNode) - if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding { - self.navigationBarBackroundNode.isHidden = true - self.navigationBarSeparatorNode.isHidden = true + if let navigationBar = self.navigationBar { + self.addSubnode(navigationBar) } + + self.addSubnode(self.titleAccessoryPanelContainer) self.historyNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) @@ -798,8 +546,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.inputMediaNode?.simulateUpdateLayout(isVisible: isInFocus) } - func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition protoTransition: ContainedViewLayoutTransition, listViewTransaction: - (ListViewUpdateSizeAndInsets, CGFloat, Bool, @escaping () -> Void) -> Void) { + func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition protoTransition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets, CGFloat, Bool, @escaping () -> Void) -> Void, updateExtraNavigationBarBackgroundHeight: (CGFloat) -> Void) { let transition: ContainedViewLayoutTransition if let _ = self.scheduledAnimateInAsOverlayFromNode { transition = .immediate @@ -847,9 +594,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { containerNode.clipsToBounds = true containerNode.cornerRadius = 15.0 containerNode.addSubnode(self.backgroundNode) - if let gradientBackgroundNode = self.gradientBackgroundNode { - containerNode.addSubnode(gradientBackgroundNode) - } containerNode.addSubnode(self.historyNodeContainer) if let restrictedNode = self.restrictedNode { containerNode.addSubnode(restrictedNode) @@ -886,9 +630,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.containerNode = nil containerNode.removeFromSupernode() self.insertSubnode(self.backgroundNode, at: 0) - if let gradientBackgroundNode = self.gradientBackgroundNode { - self.insertSubnode(gradientBackgroundNode, at: 1) - } self.insertSubnode(self.historyNodeContainer, aboveSubnode: self.backgroundNode) if let restrictedNode = self.restrictedNode { self.insertSubnode(restrictedNode, aboveSubnode: self.historyNodeContainer) @@ -952,6 +693,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { var dismissedTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode? var immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = false var titleAccessoryPanelHeight: CGFloat? + var titleAccessoryPanelBackgroundHeight: CGFloat? if let titleAccessoryPanelNode = titlePanelForChatPresentationInterfaceState(self.chatPresentationInterfaceState, context: self.context, currentPanel: self.titleAccessoryPanelNode, interfaceInteraction: self.interfaceInteraction) { if self.titleAccessoryPanelNode != titleAccessoryPanelNode { dismissedTitleAccessoryPanelNode = self.titleAccessoryPanelNode @@ -960,7 +702,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.titleAccessoryPanelContainer.addSubnode(titleAccessoryPanelNode) } - titleAccessoryPanelHeight = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState) + let layoutResult = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState) + titleAccessoryPanelHeight = layoutResult.insetHeight + titleAccessoryPanelBackgroundHeight = layoutResult.backgroundHeight } else if let titleAccessoryPanelNode = self.titleAccessoryPanelNode { dismissedTitleAccessoryPanelNode = titleAccessoryPanelNode self.titleAccessoryPanelNode = nil @@ -1052,135 +796,13 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { let statusBarHeight = layout.insets(options: [.statusBar]).top - func extractExperimentalPlaylistUrl(_ text: String) -> String? { - let prefix = "stream: " - if text.hasPrefix(prefix) { - if let url = URL(string: String(text[text.index(text.startIndex, offsetBy: prefix.count)...])), url.absoluteString.hasSuffix(".m3u8") { - return url.absoluteString - } else { - return nil - } - } else { - return nil - } - } - - if let pinnedMessage = self.chatPresentationInterfaceState.pinnedMessage, self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding, self.context.sharedContext.immediateExperimentalUISettings.playlistPlayback, self.embeddedTitleContentNode == nil, let url = extractExperimentalPlaylistUrl(pinnedMessage.message.text), self.didProcessExperimentalEmbedUrl != url { - self.didProcessExperimentalEmbedUrl = url - let context = self.context - let baseNavigationController = self.controller?.navigationController as? NavigationController - let mediaManager = self.context.sharedContext.mediaManager - var expandImpl: (() -> Void)? - let content = PlatformVideoContent(id: .instantPage(MediaId(namespace: 0, id: 0), MediaId(namespace: 0, id: 0)), content: .url(url), streamVideo: true, loopVideo: false) - let overlayNode = OverlayUniversalVideoNode(postbox: self.context.account.postbox, audioSession: self.context.sharedContext.mediaManager.audioSession, manager: self.context.sharedContext.mediaManager.universalVideoManager, content: content, expand: { - expandImpl?() - }, close: { [weak mediaManager] in - mediaManager?.setOverlayVideoNode(nil) - }) - self.embeddedTitleContentNode = ChatEmbeddedTitleContentNode(context: self.context, videoNode: overlayNode, disableInternalAnimationIn: true, interactiveExtensionUpdated: { [weak self] transition in - guard let strongSelf = self else { - return - } - strongSelf.requestLayout(transition) - }, dismissed: { [weak self] in - guard let strongSelf = self else { - return - } - if let embeddedTitleContentNode = strongSelf.embeddedTitleContentNode { - strongSelf.embeddedTitleContentNode = nil - strongSelf.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode - strongSelf.requestLayout(.animated(duration: 0.25, curve: .spring)) - strongSelf.updateHasEmbeddedTitleContent?() - } - }, isUIHiddenUpdated: { [weak self] in - self?.updateHasEmbeddedTitleContent?() - }, unembedWhenPortrait: { [weak self] itemNode in - guard let strongSelf = self, let itemNode = itemNode as? OverlayUniversalVideoNode else { - return false - } - strongSelf.unembedWhenPortrait(contentNode: itemNode) - return true - }) - self.embeddedTitleContentNode?.unembedOnLeave = false - self.updateHasEmbeddedTitleContent?() - overlayNode.controlPlay() - } - - if self.chatPresentationInterfaceState.pinnedMessage == nil { - self.didProcessExperimentalEmbedUrl = nil - } - - if let embeddedTitleContentNode = self.embeddedTitleContentNode, embeddedTitleContentNode.supernode != nil { - if layout.size.width > layout.size.height { - self.embeddedTitleContentNode = nil - self.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode - embeddedTitleContentNode.expand(intoLandscape: true) - self.updateHasEmbeddedTitleContent?() - } - } - - if let embeddedTitleContentNode = self.embeddedTitleContentNode { - let defaultEmbeddedSize = CGSize(width: layout.size.width, height: min(400.0, embeddedTitleContentNode.calculateHeight(width: layout.size.width)) + statusBarHeight + embeddedTitleContentNode.interactiveExtension) - - let embeddedSize: CGSize - if let inputHeight = layout.inputHeight, inputHeight > 100.0 { - embeddedSize = CGSize(width: defaultEmbeddedSize.width, height: floor(defaultEmbeddedSize.height * 0.6)) - } else { - embeddedSize = defaultEmbeddedSize - } - - if embeddedTitleContentNode.supernode == nil { - self.insertSubnode(embeddedTitleContentNode, aboveSubnode: self.navigationBarBackroundNode) - - var previousTopInset = insets.top - if case .overlay = self.chatPresentationInterfaceState.mode { - previousTopInset = 44.0 - } else { - previousTopInset += navigationBarHeight - } - - if case .peek = self.embeddedTitlePeekContent { - previousTopInset += 32.0 - } - - embeddedTitleContentNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: previousTopInset)) - transition.updateFrame(node: embeddedTitleContentNode, frame: CGRect(origin: CGPoint(), size: embeddedSize)) - embeddedTitleContentNode.updateLayout(size: embeddedSize, actualHeight: defaultEmbeddedSize.height, topInset: statusBarHeight, interactiveExtension: embeddedTitleContentNode.interactiveExtension, transition: .immediate, transitionSurface: self, navigationBar: self.navigationBar) - } else { - transition.updateFrame(node: embeddedTitleContentNode, frame: CGRect(origin: CGPoint(), size: embeddedSize)) - embeddedTitleContentNode.updateLayout(size: embeddedSize, actualHeight: defaultEmbeddedSize.height, topInset: statusBarHeight, interactiveExtension: embeddedTitleContentNode.interactiveExtension, transition: transition, transitionSurface: self, navigationBar: self.navigationBar) - } - - insets.top += embeddedSize.height + + if case .overlay = self.chatPresentationInterfaceState.mode { + insets.top = 44.0 } else { - if case .overlay = self.chatPresentationInterfaceState.mode { - insets.top = 44.0 - } else { - insets.top += navigationBarHeight - } - - if case .peek = self.embeddedTitlePeekContent { - insets.top += 32.0 - } + insets.top += navigationBarHeight } - if let dismissedEmbeddedTitleContentNode = self.dismissedEmbeddedTitleContentNode { - self.dismissedEmbeddedTitleContentNode = nil - if transition.isAnimated { - dismissedEmbeddedTitleContentNode.alpha = 0.0 - dismissedEmbeddedTitleContentNode.layer.allowsGroupOpacity = true - dismissedEmbeddedTitleContentNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, completion: { [weak dismissedEmbeddedTitleContentNode] _ in - dismissedEmbeddedTitleContentNode?.removeFromSupernode() - }) - transition.updateFrame(node: dismissedEmbeddedTitleContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: insets.top))) - } else { - dismissedEmbeddedTitleContentNode.removeFromSupernode() - } - } - - transition.updateFrame(node: self.navigationBarBackroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: insets.top))) - transition.updateFrame(node: self.navigationBarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: UIScreenPixel))) - var wrappingInsets = UIEdgeInsets() if case .overlay = self.chatPresentationInterfaceState.mode { let containerWidth = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 8.0 + layout.safeInsets.left) @@ -1286,6 +908,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: panelHeight)) insets.top += panelHeight } + + updateExtraNavigationBarBackgroundHeight(titleAccessoryPanelBackgroundHeight ?? 0.0) var importStatusPanelFrame: CGRect? if let _ = self.chatImportStatusPanel, let panelHeight = importStatusPanelHeight { @@ -1302,11 +926,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { transition.updateFrame(node: self.backgroundNode, frame: contentBounds) self.backgroundNode.updateLayout(size: contentBounds.size, transition: transition) - if let gradientBackgroundNode = self.gradientBackgroundNode { - transition.updateFrame(node: gradientBackgroundNode, frame: contentBounds) - gradientBackgroundNode.updateLayout(size: contentBounds.size, transition: transition) - } - transition.updateFrame(node: self.historyNodeContainer, frame: contentBounds) transition.updateBounds(node: self.historyNode, bounds: CGRect(origin: CGPoint(), size: contentBounds.size)) transition.updatePosition(node: self.historyNode, position: CGPoint(x: contentBounds.size.width / 2.0, y: contentBounds.size.height / 2.0)) @@ -1599,6 +1218,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if layout.additionalInsets.right > 0.0 { apparentNavigateButtonsFrame.origin.y -= 16.0 } + + apparentInputBackgroundFrame.size.height += 41.0 let previousInputPanelBackgroundFrame = self.inputPanelBackgroundNode.frame transition.updateFrame(node: self.inputPanelBackgroundNode, frame: apparentInputBackgroundFrame) @@ -1922,7 +1543,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { let listBottomInset = self.historyNode.insets.top if let previousListBottomInset = previousListBottomInset, listBottomInset != previousListBottomInset { if abs(listBottomInset - previousListBottomInset) > 80.0 { - self.gradientBackgroundNode?.animateEvent(transition: transition) + self.backgroundNode.animateEvent(transition: transition) } //self.historyNode.didScrollWithOffset?(listBottomInset - previousListBottomInset, transition, nil) } @@ -1974,23 +1595,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } })) self.backgroundNode.image = chatControllerBackgroundImage(theme: chatPresentationInterfaceState.theme, wallpaper: chatPresentationInterfaceState.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: self.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper) - if case .gradient = chatPresentationInterfaceState.chatWallpaper { - self.backgroundNode.imageContentMode = .scaleToFill - } else { - self.backgroundNode.imageContentMode = .scaleAspectFill - } - self.backgroundNode.motionEnabled = chatPresentationInterfaceState.chatWallpaper.settings?.motion ?? false - - if chatPresentationInterfaceState.chatWallpaper.isBuiltin { - if self.gradientBackgroundNode == nil { - let gradientBackgroundNode = createGradientBackgroundNode() - self.gradientBackgroundNode = gradientBackgroundNode - self.backgroundNode.supernode?.insertSubnode(gradientBackgroundNode, aboveSubnode: self.backgroundNode) - } - } else if let gradientBackgroundNode = self.gradientBackgroundNode { - self.gradientBackgroundNode = nil - gradientBackgroundNode.removeFromSupernode() - } + self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper) } self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8) @@ -2012,9 +1617,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } self.updatePlainInputSeparator(transition: .immediate) self.inputPanelBackgroundSeparatorNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelSeparatorColor - - self.navigationBarBackroundNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.backgroundColor - self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor } let keepSendButtonEnabled = chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil || chatPresentationInterfaceState.interfaceState.editMessage != nil @@ -2545,6 +2147,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in self.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion) + }, updateExtraNavigationBarBackgroundHeight: { _ in }) } } @@ -2802,124 +2405,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.view.insertSubview(ConfettiView(frame: self.view.bounds), aboveSubview: self.historyNode.view) } - func updateEmbeddedTitlePeekContent(content: NavigationControllerDropContent?) { - if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding { - return - } - - guard let (_, navigationHeight) = self.validLayout else { - return - } - var peekContent: ChatEmbeddedTitlePeekContent = .none - if let content = content, let item = content.item as? VideoNavigationControllerDropContentItem, let _ = item.itemNode as? OverlayUniversalVideoNode { - if content.position.y < navigationHeight + 32.0 { - peekContent = .peek - } - } - if self.embeddedTitlePeekContent != peekContent { - self.embeddedTitlePeekContent = peekContent - self.requestLayout(.animated(duration: 0.3, curve: .spring)) - } - } - - var isEmbeddedTitleContentHidden: Bool { - if let embeddedTitleContentNode = self.embeddedTitleContentNode { - return embeddedTitleContentNode.isUIHidden - } else { - return false - } - } - - var updateHasEmbeddedTitleContent: (() -> Void)? - - func acceptEmbeddedTitlePeekContent(content: NavigationControllerDropContent) -> Bool { - if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding { - return false - } - - guard let (_, navigationHeight) = self.validLayout else { - return false - } - if content.position.y >= navigationHeight + 32.0 { - return false - } - if let item = content.item as? VideoNavigationControllerDropContentItem, let itemNode = item.itemNode as? OverlayUniversalVideoNode { - let embeddedTitleContentNode = ChatEmbeddedTitleContentNode(context: self.context, videoNode: itemNode, disableInternalAnimationIn: false, interactiveExtensionUpdated: { [weak self] transition in - guard let strongSelf = self else { - return - } - strongSelf.requestLayout(transition) - }, dismissed: { [weak self] in - guard let strongSelf = self else { - return - } - if let embeddedTitleContentNode = strongSelf.embeddedTitleContentNode { - strongSelf.embeddedTitleContentNode = nil - strongSelf.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode - strongSelf.requestLayout(.animated(duration: 0.25, curve: .spring)) - strongSelf.updateHasEmbeddedTitleContent?() - } - }, isUIHiddenUpdated: { [weak self] in - self?.updateHasEmbeddedTitleContent?() - }, unembedWhenPortrait: { [weak self] itemNode in - guard let strongSelf = self, let itemNode = itemNode as? OverlayUniversalVideoNode else { - return false - } - strongSelf.unembedWhenPortrait(contentNode: itemNode) - return true - }) - self.embeddedTitleContentNode = embeddedTitleContentNode - self.embeddedTitlePeekContent = .none - self.updateHasEmbeddedTitleContent?() - DispatchQueue.main.async { - self.requestLayout(.animated(duration: 0.25, curve: .spring)) - } - - return true - } - return false - } - - private func unembedWhenPortrait(contentNode: OverlayUniversalVideoNode) { - let embeddedTitleContentNode = ChatEmbeddedTitleContentNode(context: self.context, videoNode: contentNode, disableInternalAnimationIn: true, interactiveExtensionUpdated: { [weak self] transition in - guard let strongSelf = self else { - return - } - strongSelf.requestLayout(transition) - }, dismissed: { [weak self] in - guard let strongSelf = self else { - return - } - if let embeddedTitleContentNode = strongSelf.embeddedTitleContentNode { - strongSelf.embeddedTitleContentNode = nil - strongSelf.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode - strongSelf.requestLayout(.animated(duration: 0.25, curve: .spring)) - strongSelf.updateHasEmbeddedTitleContent?() - } - }, isUIHiddenUpdated: { [weak self] in - self?.updateHasEmbeddedTitleContent?() - }, unembedWhenPortrait: { [weak self] itemNode in - guard let strongSelf = self, let itemNode = itemNode as? OverlayUniversalVideoNode else { - return false - } - strongSelf.unembedWhenPortrait(contentNode: itemNode) - return true - }) - - self.embeddedTitleContentNode = embeddedTitleContentNode - self.embeddedTitlePeekContent = .none - self.updateHasEmbeddedTitleContent?() - self.requestLayout(.immediate) - } - func willNavigateAway() { - if let embeddedTitleContentNode = self.embeddedTitleContentNode, embeddedTitleContentNode.unembedOnLeave { - self.embeddedTitleContentNode = nil - self.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode - embeddedTitleContentNode.expandIntoPiP() - self.requestLayout(.animated(duration: 0.25, curve: .spring)) - self.updateHasEmbeddedTitleContent?() - } } func updateIsBlurred(_ isBlurred: Bool) { diff --git a/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift index 9233bbc5bf..465bda5a41 100644 --- a/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift @@ -126,32 +126,26 @@ private final class ChatInfoTitlePanelButtonNode: HighlightableButtonNode { final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode { private var theme: PresentationTheme? - - private let backgroundNode: ASDisplayNode + private let separatorNode: ASDisplayNode private var buttons: [(ChatInfoTitleButton, ChatInfoTitlePanelButtonNode)] = [] override init() { - self.backgroundNode = ASDisplayNode() - self.backgroundNode.isLayerBacked = true - self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true super.init() - - self.addSubnode(self.backgroundNode) + self.addSubnode(self.separatorNode) } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { let themeUpdated = self.theme !== interfaceState.theme self.theme = interfaceState.theme let panelHeight: CGFloat = 55.0 if themeUpdated { - self.backgroundNode.backgroundColor = interfaceState.theme.rootController.navigationBar.backgroundColor self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor } @@ -205,11 +199,9 @@ final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode { } } - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: panelHeight))) - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) - return panelHeight + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) } @objc func buttonPressed(_ node: HighlightableButtonNode) { diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 2439a7793b..e09ad9ef13 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -423,7 +423,7 @@ final class ChatMediaInputNode: ChatInputNode { private var inputNodeInteraction: ChatMediaInputNodeInteraction! private var trendingInteraction: TrendingPaneInteraction? - private let collectionListPanel: NavigationBackgroundNode + private let collectionListPanel: ASDisplayNode private let collectionListSeparator: ASDisplayNode private let collectionListContainer: CollectionListContainerNode @@ -433,7 +433,9 @@ final class ChatMediaInputNode: ChatInputNode { private let gifListView: ListView private var searchContainerNode: PaneSearchContainerNode? private let searchContainerNodeLoadedDisposable = MetaDisposable() - + + private let paneClippingContainer: ASDisplayNode + private let panesBackgroundNode: ASDisplayNode private let stickerPane: ChatMediaInputStickerPane private var animatingStickerPaneOut = false private let gifPane: ChatMediaInputGifPane @@ -473,14 +475,15 @@ final class ChatMediaInputNode: ChatInputNode { self.strings = strings self.fontSize = fontSize self.gifPaneIsActiveUpdated = gifPaneIsActiveUpdated + + self.paneClippingContainer = ASDisplayNode() + self.paneClippingContainer.clipsToBounds = true + + self.panesBackgroundNode = ASDisplayNode() self.themeAndStringsPromise = Promise((theme, strings)) - - if case let .color(color) = chatWallpaper, UIColor(rgb: color).isEqual(theme.chat.inputPanel.panelBackgroundColorNoWallpaper) { - self.collectionListPanel = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColorNoWallpaper) - } else { - self.collectionListPanel = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColor) - } + + self.collectionListPanel = ASDisplayNode() self.collectionListPanel.clipsToBounds = true self.collectionListSeparator = ASDisplayNode() @@ -687,8 +690,10 @@ final class ChatMediaInputNode: ChatInputNode { return false } - self.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0) - + self.panesBackgroundNode.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0) + + self.addSubnode(self.paneClippingContainer) + self.paneClippingContainer.addSubnode(panesBackgroundNode) self.collectionListPanel.addSubnode(self.listView) self.collectionListPanel.addSubnode(self.gifListView) self.gifListView.isHidden = true @@ -1086,12 +1091,6 @@ final class ChatMediaInputNode: ChatInputNode { self.theme = theme self.strings = strings - if case let .color(color) = chatWallpaper, UIColor(rgb: color).isEqual(theme.chat.inputPanel.panelBackgroundColorNoWallpaper) { - self.collectionListPanel.color = theme.chat.inputPanel.panelBackgroundColorNoWallpaper - } else { - self.collectionListPanel.color = theme.chat.inputPanel.panelBackgroundColor - } - self.collectionListSeparator.backgroundColor = theme.chat.inputMediaPanel.panelSeparatorColor self.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0) @@ -1639,7 +1638,6 @@ final class ChatMediaInputNode: ChatInputNode { transition.updateFrame(node: self.collectionListContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: contentVerticalOffset), size: CGSize(width: width, height: max(0.0, 41.0 + UIScreenPixel)))) transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: collectionListPanelOffset), size: CGSize(width: width, height: 41.0))) - collectionListPanel.update(size: self.collectionListPanel.bounds.size, transition: transition) transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0 + collectionListPanelOffset), size: CGSize(width: width, height: separatorHeight))) self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: 41.0, height: width) @@ -1672,11 +1670,7 @@ final class ChatMediaInputNode: ChatInputNode { case .gifs: if self.gifPane.supernode == nil { if !displaySearch { - if let searchContainerNode = self.searchContainerNode { - self.insertSubnode(self.gifPane, belowSubnode: searchContainerNode) - } else { - self.insertSubnode(self.gifPane, belowSubnode: self.collectionListContainer) - } + self.paneClippingContainer.addSubnode(self.gifPane) if self.searchContainerNode == nil { self.gifPane.frame = CGRect(origin: CGPoint(x: -width, y: 0.0), size: CGSize(width: width, height: panelHeight)) } @@ -1688,11 +1682,7 @@ final class ChatMediaInputNode: ChatInputNode { } case .stickers: if self.stickerPane.supernode == nil { - if let searchContainerNode = self.searchContainerNode { - self.insertSubnode(self.stickerPane, belowSubnode: searchContainerNode) - } else { - self.insertSubnode(self.stickerPane, belowSubnode: self.collectionListContainer) - } + self.paneClippingContainer.addSubnode(self.stickerPane) self.stickerPane.frame = CGRect(origin: CGPoint(x: width, y: 0.0), size: CGSize(width: width, height: panelHeight)) } if self.stickerPane.frame != paneFrame { @@ -1834,6 +1824,10 @@ final class ChatMediaInputNode: ChatInputNode { self?.gifPane.initializeIfNeeded() }) } + + self.updatePaneClippingContainer(size: CGSize(width: width, height: panelHeight), offset: contentVerticalOffset, transition: transition) + + transition.updateFrame(node: self.panesBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: panelHeight))) return (standardInputHeight, max(0.0, panelHeight - standardInputHeight)) } @@ -1974,10 +1968,16 @@ final class ChatMediaInputNode: ChatInputNode { self.updateAppearanceTransition(transition: transition) transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: collectionListPanelOffset), size: self.collectionListPanel.bounds.size)) - collectionListPanel.update(size: self.collectionListPanel.bounds.size, transition: transition) transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0 + collectionListPanelOffset), size: self.collectionListSeparator.bounds.size)) transition.updatePosition(node: self.listView, position: CGPoint(x: self.listView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0)) transition.updatePosition(node: self.gifListView, position: CGPoint(x: self.gifListView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0)) + + self.updatePaneClippingContainer(size: self.paneClippingContainer.bounds.size, offset: collectionListPanelOffset, transition: transition) + } + + private func updatePaneClippingContainer(size: CGSize, offset: CGFloat, transition: ContainedViewLayoutTransition) { + transition.updateFrame(node: self.paneClippingContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: offset + 41.0), size: size)) + transition.updateSublayerTransformOffset(layer: self.paneClippingContainer.layer, offset: CGPoint(x: 0.0, y: -offset - 41.0)) } private func fixPaneScroll(pane: ChatMediaInputPane, state: ChatMediaInputPaneScrollState) { @@ -1996,7 +1996,6 @@ final class ChatMediaInputNode: ChatInputNode { let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .spring) self.updateAppearanceTransition(transition: transition) transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: collectionListPanelOffset), size: self.collectionListPanel.bounds.size)) - collectionListPanel.update(size: self.collectionListPanel.bounds.size, transition: transition) transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0 + collectionListPanelOffset), size: self.collectionListSeparator.bounds.size)) transition.updatePosition(node: self.listView, position: CGPoint(x: self.listView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0)) transition.updatePosition(node: self.gifListView, position: CGPoint(x: self.gifListView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0)) diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index d15e13ab69..2beaf1ea5b 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -55,7 +55,6 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { private let imageNode: TransformImageNode private let imageNodeContainer: ASDisplayNode - private let backgroundNode: NavigationBackgroundNode private let separatorNode: ASDisplayNode private var currentLayout: (CGFloat, CGFloat, CGFloat)? @@ -92,8 +91,6 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.activityIndicatorContainer.addSubnode(self.activityIndicator) self.activityIndicator.alpha = 0.0 ContainedViewLayoutTransition.immediate.updateSublayerTransformScale(node: self.activityIndicatorContainer, scale: 0.1) - - self.backgroundNode = NavigationBackgroundNode(color: .clear) self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -122,8 +119,6 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.imageNodeContainer = ASDisplayNode() super.init() - - self.addSubnode(self.backgroundNode) self.tapButton.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { @@ -187,12 +182,9 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { private var theme: PresentationTheme? - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { let panelHeight: CGFloat = 50.0 var themeUpdated = false - - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) - self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition) self.contextContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)) @@ -201,7 +193,6 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.theme = interfaceState.theme self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(interfaceState.theme), for: []) self.listButton.setImage(PresentationResourcesChat.chatInputPanelPinnedListIconImage(interfaceState.theme), for: []) - self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor } @@ -326,7 +317,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { } } - return panelHeight + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) } private func enqueueTransition(width: CGFloat, panelHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, animation: PinnedMessageAnimation?, pinnedMessage: ChatPinnedMessage, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: PeerId, firstTime: Bool, isReplyThread: Bool) { diff --git a/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift index a26517ad56..9656ca9033 100644 --- a/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift @@ -305,7 +305,6 @@ private final class ChatInfoTitlePanelPeerNearbyInfoNode: ASDisplayNode { } final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { - private let backgroundNode: NavigationBackgroundNode private let separatorNode: ASDisplayNode private let closeButton: HighlightableButtonNode @@ -317,7 +316,6 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { private var peerNearbyInfoNode: ChatInfoTitlePanelPeerNearbyInfoNode? override init() { - self.backgroundNode = NavigationBackgroundNode(color: .clear) self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -326,23 +324,21 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { self.closeButton.displaysAsynchronously = false super.init() - - self.addSubnode(self.backgroundNode) + self.addSubnode(self.separatorNode) self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside]) self.addSubnode(self.closeButton) } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { if interfaceState.theme !== self.theme { self.theme = interfaceState.theme self.closeButton.setImage(PresentationResourcesChat.chatInputPanelEncircledCloseIconImage(interfaceState.theme), for: []) - self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor } - + var panelHeight: CGFloat = 40.0 let contentRightInset: CGFloat = 14.0 + rightInset @@ -436,10 +432,8 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { } } } - - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: panelHeight))) - self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition) - + + let initialPanelHeight = panelHeight transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) var chatPeer: Peer? @@ -502,7 +496,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { }) } - return panelHeight + return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight) } @objc func buttonPressed(_ view: UIButton) { diff --git a/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift index 30549a8227..afddcbec2e 100644 --- a/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift @@ -5,7 +5,6 @@ import AsyncDisplayKit import TelegramPresentationData final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { - private let backgroundNode: NavigationBackgroundNode private let separatorNode: ASDisplayNode private let titleNode: ImmediateTextNode @@ -13,8 +12,6 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { private var strings: PresentationStrings? override init() { - self.backgroundNode = NavigationBackgroundNode(color: .clear) - self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -23,12 +20,11 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { super.init() - self.addSubnode(self.backgroundNode) self.addSubnode(self.titleNode) self.addSubnode(self.separatorNode) } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { if interfaceState.strings !== self.strings { self.strings = interfaceState.strings @@ -38,20 +34,17 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { if interfaceState.theme !== self.theme { self.theme = interfaceState.theme - self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor + self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor } let panelHeight: CGFloat = 40.0 - - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) - self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition) let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset, height: 100.0)) transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize)) transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) - return panelHeight + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) } } diff --git a/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift index 7fa5e72cd4..1f26975cf2 100644 --- a/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift @@ -4,9 +4,14 @@ import Display import AsyncDisplayKit class ChatTitleAccessoryPanelNode: ASDisplayNode { + struct LayoutResult { + var backgroundHeight: CGFloat + var insetHeight: CGFloat + } + var interfaceInteraction: ChatPanelInterfaceInteraction? - func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { - return 0.0 + func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { + preconditionFailure() } } diff --git a/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift b/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift index 269abe87a9..cf2b5203ff 100644 --- a/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift @@ -4,7 +4,6 @@ import Display import AsyncDisplayKit final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { - private let backgroundNode: NavigationBackgroundNode private let separatorNode: ASDisplayNode private let titleNode: ImmediateTextNode @@ -26,8 +25,6 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { } override init() { - self.backgroundNode = NavigationBackgroundNode(color: .clear) - self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -38,19 +35,14 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { super.init() - self.addSubnode(self.backgroundNode) self.addSubnode(self.titleNode) self.addSubnode(self.separatorNode) } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { let panelHeight: CGFloat = 40.0 - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) - self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition) - self.textColor = interfaceState.theme.rootController.navigationBar.primaryTextColor - self.backgroundNode.color = interfaceState.theme.chat.historyNavigation.fillColor self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) @@ -58,6 +50,6 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 20.0, height: 100.0)) self.titleNode.frame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize) - return panelHeight + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) } } diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index acd0e56a21..1d90fe60de 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -806,9 +806,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { override func didLoad() { super.didLoad() - if self.panelNode.backgroundColor == .clear { - self.panelNode.view.addSubview(self.effectView) - } + + self.panelNode.view.addSubview(self.effectView) } @objc private func buttonPressed() { diff --git a/submodules/WallpaperBackgroundNode/BUILD b/submodules/WallpaperBackgroundNode/BUILD new file mode 100644 index 0000000000..64bd9d17c4 --- /dev/null +++ b/submodules/WallpaperBackgroundNode/BUILD @@ -0,0 +1,22 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +swift_library( + name = "WallpaperBackgroundNode", + module_name = "WallpaperBackgroundNode", + srcs = glob([ + "Sources/**/*.swift", + ]), + copts = [ + "-O", + ], + deps = [ + "//submodules/AsyncDisplayKit:AsyncDisplayKit", + "//submodules/Display:Display", + "//submodules/GradientBackground:GradientBackground", + "//submodules/TelegramPresentationData:TelegramPresentationData", + "//submodules/SyncCore:SyncCore", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/submodules/Display/Source/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift similarity index 57% rename from submodules/Display/Source/WallpaperBackgroundNode.swift rename to submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index 65de835a13..4c3b115f16 100644 --- a/submodules/Display/Source/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -1,13 +1,21 @@ import Foundation import UIKit import AsyncDisplayKit +import Display +import GradientBackground +import TelegramPresentationData +import SyncCore private let motionAmount: CGFloat = 32.0 public final class WallpaperBackgroundNode: ASDisplayNode { - let contentNode: ASDisplayNode + private let contentNode: ASDisplayNode + private var gradientBackgroundNode: GradientBackgroundNode? + + private var validLayout: CGSize? + private var wallpaper: TelegramWallpaper? - public var motionEnabled: Bool = false { + private var motionEnabled: Bool = false { didSet { if oldValue != self.motionEnabled { if self.motionEnabled { @@ -51,13 +59,13 @@ public final class WallpaperBackgroundNode: ASDisplayNode { } } - public var imageContentMode: UIView.ContentMode { + private var imageContentMode: UIView.ContentMode { didSet { self.contentNode.contentMode = self.imageContentMode } } - func updateScale() { + private func updateScale() { if self.motionEnabled { let scale = (self.frame.width + motionAmount * 2.0) / self.frame.width self.contentNode.transform = CATransform3DMakeScale(scale, scale, 1.0) @@ -78,14 +86,70 @@ public final class WallpaperBackgroundNode: ASDisplayNode { self.contentNode.frame = self.bounds self.addSubnode(self.contentNode) } + + public func update(wallpaper: TelegramWallpaper) { + if self.wallpaper == wallpaper { + return + } + self.wallpaper = wallpaper + + if wallpaper.isBuiltin { + if self.gradientBackgroundNode == nil { + let gradientBackgroundNode = createGradientBackgroundNode() + self.gradientBackgroundNode = gradientBackgroundNode + self.addSubnode(gradientBackgroundNode) + } + self.contentNode.isHidden = true + } else { + if let gradientBackgroundNode = self.gradientBackgroundNode { + self.gradientBackgroundNode = nil + gradientBackgroundNode.removeFromSupernode() + } + + if case .gradient = wallpaper { + self.imageContentMode = .scaleToFill + } else { + self.imageContentMode = .scaleAspectFill + } + self.motionEnabled = wallpaper.settings?.motion ?? false + + self.contentNode.isHidden = false + } + + if let size = self.validLayout { + self.updateLayout(size: size, transition: .immediate) + } + } public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { - let isFirstLayout = self.contentNode.frame.isEmpty + let isFirstLayout = self.validLayout == nil + self.validLayout = size + transition.updatePosition(node: self.contentNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0)) transition.updateBounds(node: self.contentNode, bounds: CGRect(origin: CGPoint(), size: size)) + + if let gradientBackgroundNode = self.gradientBackgroundNode { + transition.updateFrame(node: gradientBackgroundNode, frame: CGRect(origin: CGPoint(), size: size)) + gradientBackgroundNode.updateLayout(size: size, transition: transition) + } if isFirstLayout && !self.frame.isEmpty { self.updateScale() } } + + public func animateEvent(transition: ContainedViewLayoutTransition) { + guard let wallpaper = self.wallpaper else { + return + } + switch wallpaper { + case let .builtin(settings): + if !settings.motion { + //return + } + default: + break + } + self.gradientBackgroundNode?.animateEvent(transition: transition) + } }