Prepare for chat background optimization

This commit is contained in:
Ali 2021-11-04 21:10:38 +04:00
parent ddb0999af0
commit 146b458f8a
18 changed files with 232 additions and 64 deletions

View File

@ -62,7 +62,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
self.scrollNode = ASScrollNode() self.scrollNode = ASScrollNode()
self.chatBackgroundNode = WallpaperBackgroundNode(context: context) self.chatBackgroundNode = createWallpaperBackgroundNode(context: context)
self.chatBackgroundNode.displaysAsynchronously = false self.chatBackgroundNode.displaysAsynchronously = false
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()

View File

@ -132,7 +132,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in return { item, params, neighbors in
if currentBackgroundNode == nil { if currentBackgroundNode == nil {
currentBackgroundNode = WallpaperBackgroundNode(context: item.context) currentBackgroundNode = createWallpaperBackgroundNode(context: item.context)
} }
currentBackgroundNode?.update(wallpaper: item.wallpaper) currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners) currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)

View File

@ -74,7 +74,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
self.pageControlNode = PageControlNode(dotSpacing: 7.0, dotColor: .white, inactiveDotColor: UIColor.white.withAlphaComponent(0.4)) self.pageControlNode = PageControlNode(dotSpacing: 7.0, dotColor: .white, inactiveDotColor: UIColor.white.withAlphaComponent(0.4))
self.chatListBackgroundNode = ASDisplayNode() self.chatListBackgroundNode = ASDisplayNode()
self.chatBackgroundNode = WallpaperBackgroundNode(context: context) self.chatBackgroundNode = createWallpaperBackgroundNode(context: context)
self.chatBackgroundNode.displaysAsynchronously = false self.chatBackgroundNode.displaysAsynchronously = false
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()

View File

@ -285,7 +285,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
self.backgroundContainerNode = ASDisplayNode() self.backgroundContainerNode = ASDisplayNode()
self.backgroundContainerNode.clipsToBounds = true self.backgroundContainerNode.clipsToBounds = true
self.backgroundWrapperNode = ASDisplayNode() self.backgroundWrapperNode = ASDisplayNode()
self.backgroundNode = WallpaperBackgroundNode(context: context) self.backgroundNode = createWallpaperBackgroundNode(context: context)
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()
self.messagesContainerNode.clipsToBounds = true self.messagesContainerNode.clipsToBounds = true
@ -1354,7 +1354,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
@objc private func playPressed() { @objc private func playPressed() {
if self.state.backgroundColors.count >= 3 || self.state.messagesColors.count >= 3 { if self.state.backgroundColors.count >= 3 || self.state.messagesColors.count >= 3 {
self.backgroundNode.animateEvent(transition: .animated(duration: 0.5, curve: .spring)) self.backgroundNode.animateEvent(transition: .animated(duration: 0.5, curve: .spring), extendAnimation: false)
} else { } else {
self.updateState({ state in self.updateState({ state in
var state = state var state = state

View File

@ -107,7 +107,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.messagesContainerNode.clipsToBounds = true self.messagesContainerNode.clipsToBounds = true
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
self.instantChatBackgroundNode = WallpaperBackgroundNode(context: context) self.instantChatBackgroundNode = createWallpaperBackgroundNode(context: context)
self.instantChatBackgroundNode.displaysAsynchronously = false self.instantChatBackgroundNode.displaysAsynchronously = false
self.ready.set(.single(true)) self.ready.set(.single(true))
@ -121,7 +121,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.blurredNode = BlurredImageNode() self.blurredNode = BlurredImageNode()
self.blurredNode.blurView.contentMode = .scaleAspectFill self.blurredNode.blurView.contentMode = .scaleAspectFill
self.wallpaperNode = WallpaperBackgroundNode(context: context) self.wallpaperNode = createWallpaperBackgroundNode(context: context)
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings, doneButtonType: .set) self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings, doneButtonType: .set)

View File

@ -138,7 +138,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
return { item, params, neighbors in return { item, params, neighbors in
if currentBackgroundNode == nil { if currentBackgroundNode == nil {
currentBackgroundNode = WallpaperBackgroundNode(context: item.context) currentBackgroundNode = createWallpaperBackgroundNode(context: item.context)
} }
currentBackgroundNode?.update(wallpaper: item.wallpaper) currentBackgroundNode?.update(wallpaper: item.wallpaper)
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.componentTheme, bubbleCorners: item.chatBubbleCorners) currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.componentTheme, bubbleCorners: item.chatBubbleCorners)

View File

@ -136,7 +136,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.wrapperNode = ASDisplayNode() self.wrapperNode = ASDisplayNode()
self.imageNode = TransformImageNode() self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = .subsequentUpdates self.imageNode.contentAnimations = .subsequentUpdates
self.nativeNode = WallpaperBackgroundNode(context: context) self.nativeNode = createWallpaperBackgroundNode(context: context)
self.cropNode = WallpaperCropNode() self.cropNode = WallpaperCropNode()
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6)) 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) self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
@ -812,7 +812,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
switch wallpaper { switch wallpaper {
case let .gradient(gradient): case let .gradient(gradient):
if gradient.colors.count >= 3 { if gradient.colors.count >= 3 {
self.nativeNode.animateEvent(transition: .animated(duration: 0.5, curve: .spring)) self.nativeNode.animateEvent(transition: .animated(duration: 0.5, curve: .spring), extendAnimation: false)
} else { } else {
let rotation = gradient.settings.rotation ?? 0 let rotation = gradient.settings.rotation ?? 0
self.requestRotateGradient?((rotation + 90) % 360) self.requestRotateGradient?((rotation + 90) % 360)
@ -820,7 +820,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
case let .file(file): case let .file(file):
if file.isPattern { if file.isPattern {
if file.settings.colors.count >= 3 { if file.settings.colors.count >= 3 {
self.nativeNode.animateEvent(transition: .animated(duration: 0.5, curve: .spring)) self.nativeNode.animateEvent(transition: .animated(duration: 0.5, curve: .spring), extendAnimation: false)
} else { } else {
let rotation = file.settings.rotation ?? 0 let rotation = file.settings.rotation ?? 0
self.requestRotateGradient?((rotation + 90) % 360) self.requestRotateGradient?((rotation + 90) % 360)

View File

@ -964,7 +964,7 @@ final class MessageStoryRenderer {
self.containerNode = ASDisplayNode() self.containerNode = ASDisplayNode()
self.instantChatBackgroundNode = WallpaperBackgroundNode(context: context) self.instantChatBackgroundNode = createWallpaperBackgroundNode(context: context)
self.instantChatBackgroundNode.displaysAsynchronously = false self.instantChatBackgroundNode.displaysAsynchronously = false
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()

View File

@ -508,7 +508,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
default: default:
break break
} }
self.chatBackgroundNode = WallpaperBackgroundNode(context: context, useSharedAnimationPhase: useSharedAnimationPhase) self.chatBackgroundNode = createWallpaperBackgroundNode(context: context, useSharedAnimationPhase: useSharedAnimationPhase)
self.wallpaperReady.set(self.chatBackgroundNode.isReady) self.wallpaperReady.set(self.chatBackgroundNode.isReady)
var locationBroadcastPanelSource: LocationBroadcastPanelSource var locationBroadcastPanelSource: LocationBroadcastPanelSource

View File

@ -370,7 +370,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion { if (strongSelf.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
return return
} }
strongSelf.backgroundNode.animateEvent(transition: transition) strongSelf.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
} }
getMessageTransitionNode = { [weak self] in getMessageTransitionNode = { [weak self] in
@ -1648,7 +1648,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion { if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
return return
} }
self.backgroundNode.animateEvent(transition: transition) self.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
} }
//self.historyNode.didScrollWithOffset?(listBottomInset - previousListBottomInset, transition, nil) //self.historyNode.didScrollWithOffset?(listBottomInset - previousListBottomInset, transition, nil)
} }

View File

@ -24,7 +24,7 @@ private func attributedServiceMessageString(theme: ChatPresentationThemeData, st
class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
let labelNode: TextNode let labelNode: TextNode
var backgroundNode: WallpaperBackgroundNode.BubbleBackgroundNode? var backgroundNode: WallpaperBubbleBackgroundNode?
var backgroundColorNode: ASDisplayNode var backgroundColorNode: ASDisplayNode
let backgroundMaskNode: ASImageNode let backgroundMaskNode: ASImageNode
var linkHighlightingNode: LinkHighlightingNode? var linkHighlightingNode: LinkHighlightingNode?
@ -327,7 +327,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
var backgroundFrame = backgroundNode.frame var backgroundFrame = backgroundNode.frame
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundNode.update(rect: backgroundFrame, within: containerSize) backgroundNode.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
} }
} }

View File

@ -165,7 +165,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
private let containerNode: ContextControllerSourceNode private let containerNode: ContextControllerSourceNode
let imageNode: TransformImageNode let imageNode: TransformImageNode
private var enableSynchronousImageApply: Bool = false private var enableSynchronousImageApply: Bool = false
private var backgroundNode: WallpaperBackgroundNode.BubbleBackgroundNode? private var backgroundNode: WallpaperBubbleBackgroundNode?
private(set) var placeholderNode: StickerShimmerEffectNode private(set) var placeholderNode: StickerShimmerEffectNode
private(set) var animationNode: GenericAnimatedStickerNode? private(set) var animationNode: GenericAnimatedStickerNode?
private var animationSize: CGSize? private var animationSize: CGSize?
@ -650,7 +650,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self.placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize) self.placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize)
if let backgroundNode = self.backgroundNode { if let backgroundNode = self.backgroundNode {
backgroundNode.update(rect: CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize) backgroundNode.update(rect: CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize, transition: .immediate)
} }
} }
} }

View File

@ -55,7 +55,7 @@ func bubbleMaskForType(_ type: ChatMessageBackgroundType, graphics: PrincipalThe
} }
final class ChatMessageBubbleBackdrop: ASDisplayNode { final class ChatMessageBubbleBackdrop: ASDisplayNode {
private var backgroundContent: WallpaperBackgroundNode.BubbleBackgroundNode? private var backgroundContent: WallpaperBubbleBackgroundNode?
private var currentType: ChatMessageBackgroundType? private var currentType: ChatMessageBackgroundType?
private var currentMaskMode: Bool? private var currentMaskMode: Bool?
@ -86,7 +86,7 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
var backgroundFrame = backgroundContent.frame var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize) backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
} }
} }
} }
@ -142,7 +142,7 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
var backgroundFrame = backgroundContent.frame var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize) backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
} }
} }
@ -162,7 +162,7 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
var backgroundFrame = backgroundContent.frame var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize) backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
} }
self.backgroundContent = backgroundContent self.backgroundContent = backgroundContent
self.insertSubnode(backgroundContent, at: 0) self.insertSubnode(backgroundContent, at: 0)
@ -174,7 +174,7 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
var backgroundFrame = backgroundContent.frame var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize) backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
} }
self.backgroundContent = backgroundContent self.backgroundContent = backgroundContent
self.insertSubnode(backgroundContent, at: 0) self.insertSubnode(backgroundContent, at: 0)

View File

@ -22,7 +22,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
let contextSourceNode: ContextExtractedContentContainingNode let contextSourceNode: ContextExtractedContentContainingNode
private let containerNode: ContextControllerSourceNode private let containerNode: ContextControllerSourceNode
let imageNode: TransformImageNode let imageNode: TransformImageNode
private var backgroundNode: WallpaperBackgroundNode.BubbleBackgroundNode? private var backgroundNode: WallpaperBubbleBackgroundNode?
private var placeholderNode: StickerShimmerEffectNode private var placeholderNode: StickerShimmerEffectNode
var textNode: TextNode? var textNode: TextNode?
@ -250,7 +250,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
self.placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + placeholderNode.frame.minX, y: rect.minY + placeholderNode.frame.minY), size: placeholderNode.frame.size), within: containerSize) self.placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + placeholderNode.frame.minX, y: rect.minY + placeholderNode.frame.minY), size: placeholderNode.frame.size), within: containerSize)
if let backgroundNode = self.backgroundNode { if let backgroundNode = self.backgroundNode {
backgroundNode.update(rect: CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize) backgroundNode.update(rect: CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize, transition: .immediate)
} }
} }
} }

View File

@ -353,7 +353,7 @@ final class BadgeComponent: CombinedComponent {
if lhs.withinSize != rhs.withinSize { if lhs.withinSize != rhs.withinSize {
return false return false
} }
if lhs.wallpaperNode != rhs.wallpaperNode { if lhs.wallpaperNode !== rhs.wallpaperNode {
return false return false
} }
return true return true
@ -564,7 +564,7 @@ final class AvatarComponent: Component {
} }
private final class WallpaperBlurNode: ASDisplayNode { private final class WallpaperBlurNode: ASDisplayNode {
private var backgroundNode: WallpaperBackgroundNode.BubbleBackgroundNode? private var backgroundNode: WallpaperBubbleBackgroundNode?
private let colorNode: ASDisplayNode private let colorNode: ASDisplayNode
override init() { override init() {

View File

@ -99,7 +99,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 } self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings.with { $0 }
self.backgroundNode = WallpaperBackgroundNode(context: context) self.backgroundNode = createWallpaperBackgroundNode(context: context)
self.backgroundNode.isUserInteractionEnabled = false self.backgroundNode.isUserInteractionEnabled = false
self.panelBackgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.chat.inputPanel.panelBackgroundColor) self.panelBackgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.chat.inputPanel.panelBackgroundColor)

View File

@ -64,7 +64,7 @@ class ChatReplyCountItem: ListViewItem {
class ChatReplyCountItemNode: ListViewItemNode { class ChatReplyCountItemNode: ListViewItemNode {
var item: ChatReplyCountItem? var item: ChatReplyCountItem?
private let labelNode: TextNode private let labelNode: TextNode
private var backgroundNode: WallpaperBackgroundNode.BubbleBackgroundNode? private var backgroundNode: WallpaperBubbleBackgroundNode?
private let backgroundColorNode: ASDisplayNode private let backgroundColorNode: ASDisplayNode
private var theme: ChatPresentationThemeData? private var theme: ChatPresentationThemeData?
@ -201,7 +201,7 @@ class ChatReplyCountItemNode: ListViewItemNode {
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundNode.update(rect: backgroundFrame, within: containerSize) backgroundNode.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
} }
} }

View File

@ -27,25 +27,47 @@ private func generateBlurredContents(image: UIImage) -> UIImage? {
return context.generateImage() return context.generateImage()
} }
public final class WallpaperBackgroundNode: ASDisplayNode { public enum WallpaperBubbleType {
public final class BubbleBackgroundNode: ASDisplayNode { case incoming
public enum BubbleType { case outgoing
case incoming case free
case outgoing }
case free
}
private let bubbleType: BubbleType public protocol WallpaperBubbleBackgroundNode: ASDisplayNode {
var frame: CGRect { get set }
func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition)
func update(rect: CGRect, within containerSize: CGSize, transition: CombinedTransition)
func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double)
func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat)
}
public protocol WallpaperBackgroundNode: ASDisplayNode {
var isReady: Signal<Bool, NoError> { get }
var rotation: CGFloat { get set }
func update(wallpaper: TelegramWallpaper)
func _internalUpdateIsSettingUpWallpaper()
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
func animateEvent(transition: ContainedViewLayoutTransition, extendAnimation: Bool)
func updateBubbleTheme(bubbleTheme: PresentationTheme, bubbleCorners: PresentationChatBubbleCorners)
func hasBubbleBackground(for type: WallpaperBubbleType) -> Bool
func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode?
}
final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode {
final class BubbleBackgroundNodeImpl: ASDisplayNode, WallpaperBubbleBackgroundNode {
private let bubbleType: WallpaperBubbleType
private let contentNode: ASImageNode private let contentNode: ASImageNode
private var cleanWallpaperNode: ASDisplayNode? private var cleanWallpaperNode: ASDisplayNode?
private var gradientWallpaperNode: GradientBackgroundNode.CloneNode? private var gradientWallpaperNode: GradientBackgroundNode.CloneNode?
private weak var backgroundNode: WallpaperBackgroundNode? private weak var backgroundNode: WallpaperBackgroundNodeImpl?
private var index: SparseBag<BubbleBackgroundNode>.Index? private var index: SparseBag<BubbleBackgroundNodeImpl>.Index?
private var currentLayout: (rect: CGRect, containerSize: CGSize)? private var currentLayout: (rect: CGRect, containerSize: CGSize)?
public override var frame: CGRect { override var frame: CGRect {
didSet { didSet {
if oldValue.size != self.bounds.size { if oldValue.size != self.bounds.size {
self.contentNode.frame = self.bounds self.contentNode.frame = self.bounds
@ -59,7 +81,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
init(backgroundNode: WallpaperBackgroundNode, bubbleType: BubbleType) { init(backgroundNode: WallpaperBackgroundNodeImpl, bubbleType: WallpaperBubbleType) {
self.backgroundNode = backgroundNode self.backgroundNode = backgroundNode
self.bubbleType = bubbleType self.bubbleType = bubbleType
@ -210,7 +232,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) { func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) {
self.currentLayout = (rect, containerSize) self.currentLayout = (rect, containerSize)
let shiftedContentsRect = CGRect(origin: CGPoint(x: rect.minX / containerSize.width, y: rect.minY / containerSize.height), size: CGSize(width: rect.width / containerSize.width, height: rect.height / containerSize.height)) let shiftedContentsRect = CGRect(origin: CGPoint(x: rect.minX / containerSize.width, y: rect.minY / containerSize.height), size: CGSize(width: rect.width / containerSize.width, height: rect.height / containerSize.height))
@ -233,7 +255,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func update(rect: CGRect, within containerSize: CGSize, transition: CombinedTransition) { func update(rect: CGRect, within containerSize: CGSize, transition: CombinedTransition) {
self.currentLayout = (rect, containerSize) self.currentLayout = (rect, containerSize)
let shiftedContentsRect = CGRect(origin: CGPoint(x: rect.minX / containerSize.width, y: rect.minY / containerSize.height), size: CGSize(width: rect.width / containerSize.width, height: rect.height / containerSize.height)) let shiftedContentsRect = CGRect(origin: CGPoint(x: rect.minX / containerSize.width, y: rect.minY / containerSize.height), size: CGSize(width: rect.width / containerSize.width, height: rect.height / containerSize.height))
@ -250,7 +272,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) { func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
guard let (_, containerSize) = self.currentLayout else { guard let (_, containerSize) = self.currentLayout else {
return return
} }
@ -267,7 +289,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) { func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
guard let (_, containerSize) = self.currentLayout else { guard let (_, containerSize) = self.currentLayout else {
return return
} }
@ -285,9 +307,9 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
private final class BubbleBackgroundNodeReference { private final class BubbleBackgroundNodeReference {
weak var node: BubbleBackgroundNode? weak var node: BubbleBackgroundNodeImpl?
init(node: BubbleBackgroundNode) { init(node: BubbleBackgroundNodeImpl) {
self.node = node self.node = node
} }
} }
@ -303,6 +325,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
private let patternImageNode: ASImageNode private let patternImageNode: ASImageNode
private var isGeneratingPatternImage: Bool = false private var isGeneratingPatternImage: Bool = false
private let bakedBackgroundView: UIImageView
private var validLayout: CGSize? private var validLayout: CGSize?
private var wallpaper: TelegramWallpaper? private var wallpaper: TelegramWallpaper?
private var isSettingUpWallpaper: Bool = false private var isSettingUpWallpaper: Bool = false
@ -367,7 +391,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public var rotation: CGFloat = 0.0 { var rotation: CGFloat = 0.0 {
didSet { didSet {
var fromValue: CGFloat = 0.0 var fromValue: CGFloat = 0.0
if let value = (self.layer.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue { if let value = (self.layer.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
@ -400,11 +424,11 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
private static var cachedSharedPattern: (PatternKey, UIImage)? private static var cachedSharedPattern: (PatternKey, UIImage)?
private let _isReady = ValuePromise<Bool>(false, ignoreRepeated: true) private let _isReady = ValuePromise<Bool>(false, ignoreRepeated: true)
public var isReady: Signal<Bool, NoError> { var isReady: Signal<Bool, NoError> {
return self._isReady.get() return self._isReady.get()
} }
public init(context: AccountContext, useSharedAnimationPhase: Bool = false) { init(context: AccountContext, useSharedAnimationPhase: Bool) {
self.context = context self.context = context
self.useSharedAnimationPhase = useSharedAnimationPhase self.useSharedAnimationPhase = useSharedAnimationPhase
self.imageContentMode = .scaleAspectFill self.imageContentMode = .scaleAspectFill
@ -413,6 +437,9 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.contentNode.contentMode = self.imageContentMode self.contentNode.contentMode = self.imageContentMode
self.patternImageNode = ASImageNode() self.patternImageNode = ASImageNode()
self.bakedBackgroundView = UIImageView()
self.bakedBackgroundView.isHidden = true
super.init() super.init()
@ -420,6 +447,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.contentNode.frame = self.bounds self.contentNode.frame = self.bounds
self.addSubnode(self.contentNode) self.addSubnode(self.contentNode)
self.addSubnode(self.patternImageNode) self.addSubnode(self.patternImageNode)
//self.view.addSubview(self.bakedBackgroundView)
} }
deinit { deinit {
@ -428,7 +457,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.imageDisposable.dispose() self.imageDisposable.dispose()
} }
public func update(wallpaper: TelegramWallpaper) { func update(wallpaper: TelegramWallpaper) {
if self.wallpaper == wallpaper { if self.wallpaper == wallpaper {
return return
} }
@ -539,7 +568,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func _internalUpdateIsSettingUpWallpaper() { func _internalUpdateIsSettingUpWallpaper() {
self.isSettingUpWallpaper = true self.isSettingUpWallpaper = true
} }
@ -622,7 +651,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.validPatternGeneratedImage = nil self.validPatternGeneratedImage = nil
self.validPatternImage = nil self.validPatternImage = nil
if let cachedValidPatternImage = WallpaperBackgroundNode.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper { if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper {
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, generate: cachedValidPatternImage.generate) self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, generate: cachedValidPatternImage.generate)
} else { } else {
func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference { func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference {
@ -688,7 +717,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
if self.validPatternGeneratedImage != updatedGeneratedImage { if self.validPatternGeneratedImage != updatedGeneratedImage {
self.validPatternGeneratedImage = updatedGeneratedImage self.validPatternGeneratedImage = updatedGeneratedImage
if let cachedValidPatternImage = WallpaperBackgroundNode.cachedValidPatternImage, cachedValidPatternImage.generated == updatedGeneratedImage { if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated == updatedGeneratedImage {
self.patternImageNode.image = cachedValidPatternImage.image self.patternImageNode.image = cachedValidPatternImage.image
self.updatePatternPresentation() self.updatePatternPresentation()
} else { } else {
@ -700,7 +729,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.updatePatternPresentation() self.updatePatternPresentation()
if self.useSharedAnimationPhase { if self.useSharedAnimationPhase {
WallpaperBackgroundNode.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image) WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
} }
} else { } else {
self.updatePatternPresentation() self.updatePatternPresentation()
@ -721,7 +750,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
strongSelf.updatePatternPresentation() strongSelf.updatePatternPresentation()
if let image = image, strongSelf.useSharedAnimationPhase { if let image = image, strongSelf.useSharedAnimationPhase {
WallpaperBackgroundNode.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image) WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
} }
} }
} }
@ -743,7 +772,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
transition.updateFrame(node: self.patternImageNode, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(node: self.patternImageNode, frame: CGRect(origin: CGPoint(), size: size))
} }
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
let isFirstLayout = self.validLayout == nil let isFirstLayout = self.validLayout == nil
self.validLayout = size self.validLayout = size
@ -767,12 +796,25 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func animateEvent(transition: ContainedViewLayoutTransition, extendAnimation: Bool = false) { func animateEvent(transition: ContainedViewLayoutTransition, extendAnimation: Bool) {
self.gradientBackgroundNode?.animateEvent(transition: transition, extendAnimation: extendAnimation) self.gradientBackgroundNode?.animateEvent(transition: transition, extendAnimation: extendAnimation)
self.outgoingBubbleGradientBackgroundNode?.animateEvent(transition: transition, extendAnimation: extendAnimation) self.outgoingBubbleGradientBackgroundNode?.animateEvent(transition: transition, extendAnimation: extendAnimation)
} }
public func updateBubbleTheme(bubbleTheme: PresentationTheme, bubbleCorners: PresentationChatBubbleCorners) { private func updateBakedBackground() {
guard let size = self.validLayout else {
return
}
let context = DrawingContext(size: size, scale: UIScreenScale, opaque: true)
context.withContext { context in
context.clear(CGRect(origin: CGPoint(), size: size))
}
self.bakedBackgroundView.image = context.generateImage()
}
func updateBubbleTheme(bubbleTheme: PresentationTheme, bubbleCorners: PresentationChatBubbleCorners) {
if self.bubbleTheme !== bubbleTheme || self.bubbleCorners != bubbleCorners { if self.bubbleTheme !== bubbleTheme || self.bubbleCorners != bubbleCorners {
self.bubbleTheme = bubbleTheme self.bubbleTheme = bubbleTheme
self.bubbleCorners = bubbleCorners self.bubbleCorners = bubbleCorners
@ -801,7 +843,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
} }
} }
public func hasBubbleBackground(for type: WallpaperBackgroundNode.BubbleBackgroundNode.BubbleType) -> Bool { func hasBubbleBackground(for type: WallpaperBubbleType) -> Bool {
guard let bubbleTheme = self.bubbleTheme, let bubbleCorners = self.bubbleCorners else { guard let bubbleTheme = self.bubbleTheme, let bubbleCorners = self.bubbleCorners else {
return false return false
} }
@ -846,12 +888,138 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
return false return false
} }
public func makeBubbleBackground(for type: WallpaperBackgroundNode.BubbleBackgroundNode.BubbleType) -> WallpaperBackgroundNode.BubbleBackgroundNode? { func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode? {
if !self.hasBubbleBackground(for: type) { if !self.hasBubbleBackground(for: type) {
return nil return nil
} }
let node = WallpaperBackgroundNode.BubbleBackgroundNode(backgroundNode: self, bubbleType: type) let node = WallpaperBackgroundNodeImpl.BubbleBackgroundNodeImpl(backgroundNode: self, bubbleType: type)
node.updateContents() node.updateContents()
return node return node
} }
} }
final class WallpaperBackgroundNodeMergedImpl: ASDisplayNode, WallpaperBackgroundNode {
final class SharedStorage {
}
private class WallpaperComponentView: UIView {
let updated: () -> Void
init(updated: @escaping () -> Void) {
self.updated = updated
super.init(frame: CGRect())
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
private final class WallpaperGradiendComponentView: WallpaperComponentView {
struct Spec {
var colors: [UInt32]
}
}
private final class WallpaperPatternComponentView: WallpaperComponentView {
struct Spec {
}
}
private let context: AccountContext
private let storage: SharedStorage
private let staticView: UIImageView
private var gradient: WallpaperGradiendComponentView?
private var pattern: WallpaperPatternComponentView?
private let _isReady = ValuePromise<Bool>(false, ignoreRepeated: true)
var isReady: Signal<Bool, NoError> {
return self._isReady.get()
}
var rotation: CGFloat = 0.0 {
didSet {
}
}
init(context: AccountContext, storage: SharedStorage?) {
self.context = context
self.storage = storage ?? SharedStorage()
self.staticView = UIImageView()
super.init()
self.view.addSubview(self.staticView)
}
func update(wallpaper: TelegramWallpaper) {
var gradientSpec: WallpaperGradiendComponentView.Spec?
switch wallpaper {
case let .builtin(wallpaperSettings):
let _ = wallpaperSettings
case let .color(color):
let _ = color
case let .gradient(gradient):
if gradient.colors.count >= 3 {
gradientSpec = WallpaperGradiendComponentView.Spec(colors: gradient.colors)
}
case let .image(representations, settings):
let _ = representations
let _ = settings
case let .file(file):
if file.settings.colors.count >= 3 {
gradientSpec = WallpaperGradiendComponentView.Spec(colors: file.settings.colors)
}
}
if let gradientSpec = gradientSpec {
let gradient: WallpaperGradiendComponentView
if let current = self.gradient {
gradient = current
} else {
gradient = WallpaperGradiendComponentView(updated: { [weak self] in
self?.componentsUpdated()
})
}
let _ = gradient
let _ = gradientSpec
} else if let gradient = self.gradient {
self.gradient = nil
gradient.removeFromSuperview()
}
}
private func componentsUpdated() {
}
func _internalUpdateIsSettingUpWallpaper() {
}
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
}
func animateEvent(transition: ContainedViewLayoutTransition, extendAnimation: Bool) {
}
func updateBubbleTheme(bubbleTheme: PresentationTheme, bubbleCorners: PresentationChatBubbleCorners) {
}
func hasBubbleBackground(for type: WallpaperBubbleType) -> Bool {
return false
}
func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode? {
return nil
}
}
public func createWallpaperBackgroundNode(context: AccountContext, useSharedAnimationPhase: Bool = false) -> WallpaperBackgroundNode {
return WallpaperBackgroundNodeImpl(context: context, useSharedAnimationPhase: useSharedAnimationPhase)
}