mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Cache wallpaper
This commit is contained in:
parent
03a030942f
commit
70f39e2f02
@ -18,6 +18,8 @@ public func selectDateFillStaticColor(theme: PresentationTheme, wallpaper: Teleg
|
|||||||
public func dateFillNeedsBlur(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> Bool {
|
public func dateFillNeedsBlur(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> Bool {
|
||||||
if case .builtin = wallpaper {
|
if case .builtin = wallpaper {
|
||||||
return false
|
return false
|
||||||
|
} else if case .color = wallpaper {
|
||||||
|
return false
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
private let cachedDataReady = Promise<Bool>()
|
private let cachedDataReady = Promise<Bool>()
|
||||||
private var didSetCachedDataReady = false
|
private var didSetCachedDataReady = false
|
||||||
|
|
||||||
|
private let wallpaperReady = Promise<Bool>()
|
||||||
|
|
||||||
private var presentationInterfaceState: ChatPresentationInterfaceState
|
private var presentationInterfaceState: ChatPresentationInterfaceState
|
||||||
private var presentationInterfaceStatePromise: ValuePromise<ChatPresentationInterfaceState>
|
private var presentationInterfaceStatePromise: ValuePromise<ChatPresentationInterfaceState>
|
||||||
|
|
||||||
@ -433,6 +435,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.peekData = peekData
|
self.peekData = peekData
|
||||||
|
|
||||||
self.chatBackgroundNode = WallpaperBackgroundNode(context: context, useSharedAnimationPhase: true)
|
self.chatBackgroundNode = WallpaperBackgroundNode(context: context, useSharedAnimationPhase: true)
|
||||||
|
self.wallpaperReady.set(chatBackgroundNode.isReady)
|
||||||
|
|
||||||
var locationBroadcastPanelSource: LocationBroadcastPanelSource
|
var locationBroadcastPanelSource: LocationBroadcastPanelSource
|
||||||
var groupCallPanelSource: GroupCallPanelSource
|
var groupCallPanelSource: GroupCallPanelSource
|
||||||
@ -4451,11 +4454,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.chatDisplayNode.historyNode.historyState.get(),
|
self.chatDisplayNode.historyNode.historyState.get(),
|
||||||
self._chatLocationInfoReady.get(),
|
self._chatLocationInfoReady.get(),
|
||||||
effectiveCachedDataReady,
|
effectiveCachedDataReady,
|
||||||
initialData
|
initialData,
|
||||||
|
self.wallpaperReady.get()
|
||||||
)
|
)
|
||||||
|> map { _, chatLocationInfoReady, cachedDataReady, _ in
|
|> map { _, chatLocationInfoReady, cachedDataReady, _, wallpaperReady in
|
||||||
return chatLocationInfoReady && cachedDataReady
|
return chatLocationInfoReady && cachedDataReady && wallpaperReady
|
||||||
})
|
}
|
||||||
|
|> distinctUntilChanged)
|
||||||
|
|
||||||
if self.context.sharedContext.immediateExperimentalUISettings.crashOnLongQueries {
|
if self.context.sharedContext.immediateExperimentalUISettings.crashOnLongQueries {
|
||||||
let _ = (self.ready.get()
|
let _ = (self.ready.get()
|
||||||
|
@ -243,13 +243,33 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
|
|
||||||
private let contentNode: ASDisplayNode
|
private let contentNode: ASDisplayNode
|
||||||
private var gradientBackgroundNode: GradientBackgroundNode?
|
private var gradientBackgroundNode: GradientBackgroundNode?
|
||||||
private let patternImageNode: TransformImageNode
|
private let patternImageNode: ASImageNode
|
||||||
private var invertPattern: Bool = false
|
|
||||||
private var patternIsLight: Bool = false
|
|
||||||
|
|
||||||
private var validLayout: CGSize?
|
private var validLayout: CGSize?
|
||||||
private var wallpaper: TelegramWallpaper?
|
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 let patternImageDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var bubbleTheme: PresentationTheme?
|
private var bubbleTheme: PresentationTheme?
|
||||||
@ -258,6 +278,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
|
|
||||||
private let wallpaperDisposable = MetaDisposable()
|
private let wallpaperDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private let imageDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var motionEnabled: Bool = false {
|
private var motionEnabled: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if oldValue != self.motionEnabled {
|
if oldValue != self.motionEnabled {
|
||||||
@ -330,7 +352,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
self.contentNode = ASDisplayNode()
|
self.contentNode = ASDisplayNode()
|
||||||
self.contentNode.contentMode = self.imageContentMode
|
self.contentNode.contentMode = self.imageContentMode
|
||||||
|
|
||||||
self.patternImageNode = TransformImageNode()
|
self.patternImageNode = ASImageNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -343,10 +365,10 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
deinit {
|
deinit {
|
||||||
self.patternImageDisposable.dispose()
|
self.patternImageDisposable.dispose()
|
||||||
self.wallpaperDisposable.dispose()
|
self.wallpaperDisposable.dispose()
|
||||||
|
self.imageDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(wallpaper: TelegramWallpaper) {
|
public func update(wallpaper: TelegramWallpaper) {
|
||||||
let previousWallpaper = self.wallpaper
|
|
||||||
if self.wallpaper == wallpaper {
|
if self.wallpaper == wallpaper {
|
||||||
return
|
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 {
|
switch wallpaper {
|
||||||
case let .file(_, _, _, _, isPattern, _, _, file, settings) where isPattern:
|
case let .file(_, _, _, _, isPattern, _, _, file, settings) where isPattern:
|
||||||
var updated = true
|
var updated = true
|
||||||
let isLight = UIColor.average(of: settings.colors.map(UIColor.init(rgb:))).hsb.b > 0.3
|
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 {
|
switch previousWallpaper {
|
||||||
case let .file(_, _, _, _, _, _, _, previousFile, _):
|
case let .file(_, _, _, _, _, _, _, previousFile, _):
|
||||||
if file.id == previousFile.id {
|
if file.id == previousFile.id {
|
||||||
@ -444,35 +480,43 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.patternIsLight = isLight
|
patternIsLight = isLight
|
||||||
|
|
||||||
if updated {
|
if updated {
|
||||||
/*let cacheKey = PatternKey(mediaId: file.id ?? MediaId(namespace: 0, id: 0), isLight: isLight)
|
self.validPatternGeneratedImage = nil
|
||||||
if let (currentKey, currentImage) = WallpaperBackgroundNode.cachedSharedPattern, currentKey == cacheKey {
|
self.validPatternImage = nil
|
||||||
}*/
|
|
||||||
|
|
||||||
func reference(for resource: MediaResource, media: Media, message: Message?) -> MediaResourceReference {
|
if let cachedValidPatternImage = WallpaperBackgroundNode.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper {
|
||||||
if let message = message {
|
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, generate: cachedValidPatternImage.generate)
|
||||||
return .media(media: .message(message: MessageReference(message), media: media), resource: resource)
|
} 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] = []
|
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||||
for representation in file.previewRepresentations {
|
for representation in file.previewRepresentations {
|
||||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: representation.resource, media: file, message: nil)))
|
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
|
|
||||||
}
|
}
|
||||||
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
|
let intensity = CGFloat(settings.intensity ?? 50) / 100.0
|
||||||
if intensity < 0 {
|
if intensity < 0 {
|
||||||
@ -483,8 +527,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
self.patternImageNode.layer.compositingFilter = "softLightBlendMode"
|
self.patternImageNode.layer.compositingFilter = "softLightBlendMode"
|
||||||
}
|
}
|
||||||
self.patternImageNode.isHidden = false
|
self.patternImageNode.isHidden = false
|
||||||
self.invertPattern = intensity < 0
|
invertPattern = intensity < 0
|
||||||
if self.invertPattern {
|
if invertPattern {
|
||||||
self.backgroundColor = .black
|
self.backgroundColor = .black
|
||||||
let contentAlpha = abs(intensity)
|
let contentAlpha = abs(intensity)
|
||||||
self.gradientBackgroundNode?.contentView.alpha = contentAlpha
|
self.gradientBackgroundNode?.contentView.alpha = contentAlpha
|
||||||
@ -495,6 +539,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
self.contentNode.alpha = 1.0
|
self.contentNode.alpha = 1.0
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
self.patternImageDisposable.set(nil)
|
||||||
|
self.validPatternImage = nil
|
||||||
self.patternImageNode.isHidden = true
|
self.patternImageNode.isHidden = true
|
||||||
self.backgroundColor = nil
|
self.backgroundColor = nil
|
||||||
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
self.gradientBackgroundNode?.contentView.alpha = 1.0
|
||||||
@ -502,11 +548,46 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
self._isReady.set(true)
|
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 {
|
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb)
|
||||||
self.updateLayout(size: size, transition: .immediate)
|
|
||||||
|
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) {
|
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||||
@ -521,23 +602,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
gradientBackgroundNode.updateLayout(size: size, transition: transition)
|
gradientBackgroundNode.updateLayout(size: size, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
let makeImageLayout = self.patternImageNode.asyncLayout()
|
self.loadPatternForSizeIfNeeded(size: size, transition: transition)
|
||||||
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))
|
|
||||||
|
|
||||||
if isFirstLayout && !self.frame.isEmpty {
|
if isFirstLayout && !self.frame.isEmpty {
|
||||||
self.updateScale()
|
self.updateScale()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user