From 4a3c5e4089a5464f8fc7e6569b2a33fd8ef6f8b4 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 24 Nov 2023 13:52:21 +0400 Subject: [PATCH] Peer header blur --- .../Sources/PeerInfoAvatarListNode.swift | 67 +++++++++++++++++-- .../Sources/PeerInfoCoverComponent.swift | 24 +++---- ...PeerInfoAvatarTransformContainerNode.swift | 1 + .../Sources/PeerInfoHeaderNode.swift | 10 ++- 4 files changed, 83 insertions(+), 19 deletions(-) diff --git a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift index ae72b2baab..3577811d39 100644 --- a/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift +++ b/submodules/PeerInfoAvatarListNode/Sources/PeerInfoAvatarListNode.swift @@ -570,6 +570,64 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode { private let fadeWidth: CGFloat = 70.0 +public final class PeerAvatarBottomShadowNode: ASDisplayNode { + let backgroundNode: NavigationBackgroundNode + let backgroundGradientMaskLayer: SimpleGradientLayer + let imageView: UIImageView + + override init() { + self.backgroundNode = NavigationBackgroundNode(color: .black, enableBlur: true) + self.backgroundGradientMaskLayer = SimpleGradientLayer() + self.backgroundNode.layer.mask = self.backgroundGradientMaskLayer + + self.imageView = UIImageView() + self.imageView.contentMode = .scaleToFill + + super.init() + + //self.backgroundColor = .blue + + self.backgroundGradientMaskLayer.type = .axial + self.backgroundGradientMaskLayer.startPoint = CGPoint(x: 0.0, y: 1.0) + self.backgroundGradientMaskLayer.endPoint = CGPoint(x: 0.0, y: 0.0) + + let baseGradientAlpha: CGFloat = 1.0 + let numSteps = 8 + let firstStep = 1 + let firstLocation = 0.6 + self.backgroundGradientMaskLayer.colors = (0 ..< numSteps).map { i in + if i < firstStep { + return UIColor(white: 1.0, alpha: 1.0).cgColor + } else { + let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1) + return UIColor(white: 1.0, alpha: baseGradientAlpha * (1.0 - pow(step, 3.0))).cgColor + } + } + self.backgroundGradientMaskLayer.locations = (0 ..< numSteps).map { i -> NSNumber in + if i < firstStep { + return 0.0 as NSNumber + } else { + let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1) + return (firstLocation + (1.0 - firstLocation) * step) as NSNumber + } + } + + self.backgroundNode.updateColor(color: UIColor(white: 0.0, alpha: 0.1), enableSaturation: false, forceKeepBlur: true, transition: .immediate) + + self.addSubnode(self.backgroundNode) + //self.layer.addSublayer(self.backgroundGradientMaskLayer) + //self.view.addSubview(self.imageView) + } + + public func update(size: CGSize, transition: ContainedViewLayoutTransition) { + transition.updateFrame(view: self.imageView, frame: CGRect(origin: CGPoint(), size: size), beginWithCurrentState: true) + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size), beginWithCurrentState: true) + transition.updateFrame(layer: self.backgroundGradientMaskLayer, frame: CGRect(origin: CGPoint(), size: size), beginWithCurrentState: true) + self.backgroundNode.update(size: size, transition: transition) + } +} + public final class PeerInfoAvatarListContainerNode: ASDisplayNode { private let context: AccountContext private let isSettings: Bool @@ -579,7 +637,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode { public let controlsClippingNode: ASDisplayNode public let controlsClippingOffsetNode: ASDisplayNode public let topShadowNode: ASImageNode - public let bottomShadowNode: ASImageNode + public let bottomShadowNode: PeerAvatarBottomShadowNode public var storyParams: (peer: EnginePeer, items: [EngineStoryItem], count: Int, hasUnseen: Bool, hasUnseenPrivate: Bool)? private var expandedStorySetIndicator: ComponentView? @@ -793,10 +851,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.topShadowNode.displayWithoutProcessing = true self.topShadowNode.contentMode = .scaleToFill - self.bottomShadowNode = ASImageNode() - self.bottomShadowNode.displaysAsynchronously = false - self.bottomShadowNode.displayWithoutProcessing = true - self.bottomShadowNode.contentMode = .scaleToFill + self.bottomShadowNode = PeerAvatarBottomShadowNode() do { let size = CGSize(width: 88.0, height: 88.0) @@ -825,7 +880,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode { context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0) context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size)) }) - self.bottomShadowNode.image = generateImage(image.size, contextGenerator: { size, context in + self.bottomShadowNode.imageView.image = generateImage(image.size, contextGenerator: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) context.translateBy(x: size.width / 2.0, y: size.height / 2.0) context.rotate(by: CGFloat.pi / 2.0) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift index 8f8ff31c34..27904746c6 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift @@ -136,7 +136,17 @@ public final class PeerInfoCoverComponent: Component { override public init(frame: CGRect) { self.backgroundView = UIView() self.backgroundGradientLayer = SimpleGradientLayer() + self.avatarBackgroundGradientLayer = SimpleGradientLayer() + let baseAvatarGradientAlpha: CGFloat = 0.4 + let numSteps = 6 + self.avatarBackgroundGradientLayer.colors = (0 ..< numSteps).map { i in + let step: CGFloat = 1.0 - CGFloat(i) / CGFloat(numSteps - 1) + return UIColor(white: 1.0, alpha: baseAvatarGradientAlpha * pow(step, 2.0)).cgColor + } + self.avatarBackgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5) + self.avatarBackgroundGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0) + self.avatarBackgroundGradientLayer.type = .radial self.avatarBackgroundPatternContentsLayer = SimpleGradientLayer() self.avatarBackgroundPatternContentsLayer.compositingFilter = "overlayBlendMode" @@ -282,7 +292,6 @@ public final class PeerInfoCoverComponent: Component { self.backgroundGradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0) self.backgroundGradientLayer.type = .axial self.backgroundGradientLayer.colors = [backgroundColor.cgColor, secondaryBackgroundColor.cgColor] - //self.backgroundGradientLayer.colors = [UIColor.green.cgColor, UIColor.blue.cgColor] self.backgroundGradientLayer.anchorPoint = CGPoint(x: 0.0, y: 1.0) let gradientHeight: CGFloat = component.defaultHeight @@ -306,7 +315,7 @@ public final class PeerInfoCoverComponent: Component { //transition.setFrame(view: self.avatarBackgroundPatternView, frame: CGSize(width: 200.0, height: 200.0).centered(around: CGPoint())) - let avatarPatternFrame = CGSize(width: 400.0, height: 400.0).centered(around: component.avatarCenter) + let avatarPatternFrame = CGSize(width: 380.0, height: 380.0).centered(around: component.avatarCenter) transition.setFrame(layer: self.avatarBackgroundPatternContentsLayer, frame: avatarPatternFrame) self.avatarBackgroundPatternContentsLayer.type = .radial @@ -317,16 +326,7 @@ public final class PeerInfoCoverComponent: Component { UIColor(white: 0.0, alpha: 0.0).cgColor ] - let baseAvatarGradientAlpha: CGFloat = 0.24 - let numSteps = 10 - self.avatarBackgroundGradientLayer.colors = (0 ..< 10).map { i in - let step: CGFloat = 1.0 - CGFloat(i) / CGFloat(numSteps - 1) - return UIColor(white: 1.0, alpha: baseAvatarGradientAlpha * pow(step, 3.0)).cgColor - } - self.avatarBackgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5) - self.avatarBackgroundGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0) - self.avatarBackgroundGradientLayer.type = .radial - transition.setFrame(layer: self.avatarBackgroundGradientLayer, frame: CGSize(width: 260.0, height: 260.0).centered(around: component.avatarCenter)) + transition.setFrame(layer: self.avatarBackgroundGradientLayer, frame: CGSize(width: 300.0, height: 300.0).centered(around: component.avatarCenter)) transition.setAlpha(layer: self.avatarBackgroundGradientLayer, alpha: 1.0 - component.avatarTransitionFraction) let backgroundPatternContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height), size: CGSize(width: availableSize.width, height: 0.0)) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoAvatarTransformContainerNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoAvatarTransformContainerNode.swift index 242b545995..7eb9cac165 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoAvatarTransformContainerNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoAvatarTransformContainerNode.swift @@ -100,6 +100,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { } colors.unseenColors = unseenColors colors.unseenCloseFriendsColors = colors.unseenColors + colors.seenColors = colors.unseenColors } else { regularNavigationContentsSecondaryColor = theme.list.controlSecondaryColor } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift index e3b663fa7f..e748af5675 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift @@ -173,6 +173,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.avatarClippingNode = SparseNode() self.avatarClippingNode.alpha = 0.996 self.avatarClippingNode.clipsToBounds = true + self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded, isSettings: isSettings) self.titleNodeContainer = ASDisplayNode() @@ -262,6 +263,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.regularContentNode.addSubnode(self.avatarClippingNode) self.avatarClippingNode.addSubnode(self.avatarListNode) + self.regularContentNode.addSubnode(self.avatarListNode.listContainerNode.controlsClippingOffsetNode) self.regularContentNode.addSubnode(self.titleNodeContainer) self.regularContentNode.addSubnode(self.subtitleNodeContainer) @@ -1101,7 +1103,13 @@ final class PeerInfoHeaderNode: ASDisplayNode { let expandedTitleScale: CGFloat = 0.8 - transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: expandedAvatarHeight - 70.0), size: CGSize(width: width, height: 70.0))) + var bottomShadowHeight: CGFloat = 72.0 + if !self.isSettings { + bottomShadowHeight += 80.0 + } + let bottomShadowFrame = CGRect(origin: CGPoint(x: 0.0, y: expandedAvatarHeight - bottomShadowHeight), size: CGSize(width: width, height: bottomShadowHeight)) + transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: bottomShadowFrame, beginWithCurrentState: true) + self.avatarListNode.listContainerNode.bottomShadowNode.update(size: bottomShadowFrame.size, transition: transition) if self.isAvatarExpanded { let minTitleSize = CGSize(width: titleSize.width * expandedTitleScale, height: titleSize.height * expandedTitleScale)