Cache wallpaper

This commit is contained in:
Ali 2021-06-11 19:01:12 +04:00
parent 03a030942f
commit 70f39e2f02
3 changed files with 126 additions and 54 deletions

View File

@ -18,6 +18,8 @@ public func selectDateFillStaticColor(theme: PresentationTheme, wallpaper: Teleg
public func dateFillNeedsBlur(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> Bool {
if case .builtin = wallpaper {
return false
} else if case .color = wallpaper {
return false
} else {
return true
}

View File

@ -202,6 +202,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private let cachedDataReady = Promise<Bool>()
private var didSetCachedDataReady = false
private let wallpaperReady = Promise<Bool>()
private var presentationInterfaceState: ChatPresentationInterfaceState
private var presentationInterfaceStatePromise: ValuePromise<ChatPresentationInterfaceState>
@ -433,6 +435,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.peekData = peekData
self.chatBackgroundNode = WallpaperBackgroundNode(context: context, useSharedAnimationPhase: true)
self.wallpaperReady.set(chatBackgroundNode.isReady)
var locationBroadcastPanelSource: LocationBroadcastPanelSource
var groupCallPanelSource: GroupCallPanelSource
@ -4451,11 +4454,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatDisplayNode.historyNode.historyState.get(),
self._chatLocationInfoReady.get(),
effectiveCachedDataReady,
initialData
initialData,
self.wallpaperReady.get()
)
|> map { _, chatLocationInfoReady, cachedDataReady, _ in
return chatLocationInfoReady && cachedDataReady
})
|> map { _, chatLocationInfoReady, cachedDataReady, _, wallpaperReady in
return chatLocationInfoReady && cachedDataReady && wallpaperReady
}
|> distinctUntilChanged)
if self.context.sharedContext.immediateExperimentalUISettings.crashOnLongQueries {
let _ = (self.ready.get()

View File

@ -243,13 +243,33 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
private let contentNode: ASDisplayNode
private var gradientBackgroundNode: GradientBackgroundNode?
private let patternImageNode: TransformImageNode
private var invertPattern: Bool = false
private var patternIsLight: Bool = false
private let patternImageNode: ASImageNode
private var validLayout: CGSize?
private var wallpaper: TelegramWallpaper?
private struct CachedValidPatternImage {
let generate: (TransformImageArguments) -> DrawingContext?
let generated: ValidPatternGeneratedImage
let image: UIImage
}
private static var cachedValidPatternImage: CachedValidPatternImage?
private struct ValidPatternImage {
let wallpaper: TelegramWallpaper
let generate: (TransformImageArguments) -> DrawingContext?
}
private var validPatternImage: ValidPatternImage?
private struct ValidPatternGeneratedImage: Equatable {
let wallpaper: TelegramWallpaper
let size: CGSize
let patternColor: UInt32
let backgroundColor: UInt32
}
private var validPatternGeneratedImage: ValidPatternGeneratedImage?
private let patternImageDisposable = MetaDisposable()
private var bubbleTheme: PresentationTheme?
@ -258,6 +278,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
private let wallpaperDisposable = MetaDisposable()
private let imageDisposable = MetaDisposable()
private var motionEnabled: Bool = false {
didSet {
if oldValue != self.motionEnabled {
@ -330,7 +352,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.contentNode = ASDisplayNode()
self.contentNode.contentMode = self.imageContentMode
self.patternImageNode = TransformImageNode()
self.patternImageNode = ASImageNode()
super.init()
@ -343,10 +365,10 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
deinit {
self.patternImageDisposable.dispose()
self.wallpaperDisposable.dispose()
self.imageDisposable.dispose()
}
public func update(wallpaper: TelegramWallpaper) {
let previousWallpaper = self.wallpaper
if self.wallpaper == wallpaper {
return
}
@ -430,11 +452,25 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
}
}
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
self.updateBubbles()
}
}
private func loadPatternForSizeIfNeeded(size: CGSize, transition: ContainedViewLayoutTransition) {
guard let wallpaper = self.wallpaper else {
return
}
var invertPattern: Bool = false
var patternIsLight: Bool = false
switch wallpaper {
case let .file(_, _, _, _, isPattern, _, _, file, settings) where isPattern:
var updated = true
let isLight = UIColor.average(of: settings.colors.map(UIColor.init(rgb:))).hsb.b > 0.3
if let previousWallpaper = previousWallpaper {
if let previousWallpaper = self.validPatternImage?.wallpaper {
switch previousWallpaper {
case let .file(_, _, _, _, _, _, _, previousFile, _):
if file.id == previousFile.id {
@ -444,35 +480,43 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
break
}
}
self.patternIsLight = isLight
patternIsLight = isLight
if updated {
/*let cacheKey = PatternKey(mediaId: file.id ?? MediaId(namespace: 0, id: 0), isLight: isLight)
if let (currentKey, currentImage) = WallpaperBackgroundNode.cachedSharedPattern, currentKey == cacheKey {
}*/
self.validPatternGeneratedImage = nil
self.validPatternImage = nil
func reference(for resource: MediaResource, media: Media, message: Message?) -> MediaResourceReference {
if let message = message {
return .media(media: .message(message: MessageReference(message), media: media), resource: resource)
if let cachedValidPatternImage = WallpaperBackgroundNode.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper {
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, generate: cachedValidPatternImage.generate)
} else {
func reference(for resource: MediaResource, media: Media, message: Message?) -> MediaResourceReference {
if let message = message {
return .media(media: .message(message: MessageReference(message), media: media), resource: resource)
}
return .wallpaper(wallpaper: nil, resource: resource)
}
return .wallpaper(wallpaper: nil, resource: resource)
}
var convertedRepresentations: [ImageRepresentationWithReference] = []
for representation in file.previewRepresentations {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: representation.resource, media: file, message: nil)))
}
let dimensions = file.dimensions ?? PixelDimensions(width: 2000, height: 4000)
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: file.resource, media: file, message: nil)))
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
self.patternImageNode.imageUpdated = { [weak self] _ in
guard let strongSelf = self else {
return
var convertedRepresentations: [ImageRepresentationWithReference] = []
for representation in file.previewRepresentations {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: representation.resource, media: file, message: nil)))
}
strongSelf._isReady.set(true)
let dimensions = file.dimensions ?? PixelDimensions(width: 2000, height: 4000)
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: file.resource, media: file, message: nil)))
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
self.patternImageDisposable.set((signal
|> deliverOnMainQueue).start(next: { [weak self] generator in
guard let strongSelf = self else {
return
}
strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, generate: generator)
if let size = strongSelf.validLayout {
strongSelf.loadPatternForSizeIfNeeded(size: size, transition: .immediate)
} else {
strongSelf._isReady.set(true)
}
}))
}
self.patternImageNode.setSignal(signal)
}
let intensity = CGFloat(settings.intensity ?? 50) / 100.0
if intensity < 0 {
@ -483,8 +527,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.patternImageNode.layer.compositingFilter = "softLightBlendMode"
}
self.patternImageNode.isHidden = false
self.invertPattern = intensity < 0
if self.invertPattern {
invertPattern = intensity < 0
if invertPattern {
self.backgroundColor = .black
let contentAlpha = abs(intensity)
self.gradientBackgroundNode?.contentView.alpha = contentAlpha
@ -495,6 +539,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.contentNode.alpha = 1.0
}
default:
self.patternImageDisposable.set(nil)
self.validPatternImage = nil
self.patternImageNode.isHidden = true
self.backgroundColor = nil
self.gradientBackgroundNode?.contentView.alpha = 1.0
@ -502,11 +548,46 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self._isReady.set(true)
}
self.updateBubbles()
if let validPatternImage = self.validPatternImage {
let patternBackgroundColor: UIColor
let patternColor: UIColor
if invertPattern {
patternColor = .clear
patternBackgroundColor = .clear
} else {
if patternIsLight {
patternColor = .black
} else {
patternColor = .white
}
patternBackgroundColor = .clear
}
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb)
if self.validPatternGeneratedImage != updatedGeneratedImage {
self.validPatternGeneratedImage = updatedGeneratedImage
if let cachedValidPatternImage = WallpaperBackgroundNode.cachedValidPatternImage, cachedValidPatternImage.generated == updatedGeneratedImage {
self.patternImageNode.image = cachedValidPatternImage.image
} else {
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false), scale: min(2.0, UIScreenScale))
if let drawingContext = validPatternImage.generate(patternArguments) {
if let image = drawingContext.generateImage() {
self.patternImageNode.image = image
if self.useSharedAnimationPhase {
WallpaperBackgroundNode.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
}
}
}
}
self._isReady.set(true)
}
}
transition.updateFrame(node: self.patternImageNode, frame: CGRect(origin: CGPoint(), size: size))
}
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
@ -521,23 +602,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
gradientBackgroundNode.updateLayout(size: size, transition: transition)
}
let makeImageLayout = self.patternImageNode.asyncLayout()
let patternBackgroundColor: UIColor
let patternColor: UIColor
if self.invertPattern {
patternColor = .clear
patternBackgroundColor = .clear
} else {
if self.patternIsLight {
patternColor = .black
} else {
patternColor = .white
}
patternBackgroundColor = .clear
}
let applyImage = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false), scale: min(2.0, UIScreenScale)))
applyImage()
transition.updateFrame(node: self.patternImageNode, frame: CGRect(origin: CGPoint(), size: size))
self.loadPatternForSizeIfNeeded(size: size, transition: transition)
if isFirstLayout && !self.frame.isEmpty {
self.updateScale()