This commit is contained in:
Ali 2023-04-06 12:22:33 +04:00
commit dc9e1b7e2e
8 changed files with 107 additions and 62 deletions

View file

@ -131,6 +131,12 @@ public final class AnimationNode: ASDisplayNode {
}
}
public func setColors(colors: [String: UIColor]) {
for (key, value) in colors {
self.animationView()?.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color"))
}
}
public func setAnimation(data: Data) {
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let animation = try? Animation(dictionary: json)

View file

@ -276,7 +276,7 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
croppedImage = TGPhotoEditorCrop(image, nil, .up, 0.0, finalCropRect, false, CGSize(width: 1440.0, height: 2960.0), image.size, true)
if mode.contains(.blur) {
croppedImage = blurredImage(croppedImage, radius: 30.0)!
croppedImage = blurredImage(croppedImage, radius: 20.0)!
}
let thumbnailDimensions = finalCropRect.size.fitted(CGSize(width: 320.0, height: 320.0))
@ -284,12 +284,12 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
if let data = croppedImage.jpegData(compressionQuality: 0.8), let thumbnailImage = thumbnailImage, let thumbnailData = thumbnailImage.jpegData(compressionQuality: 0.4) {
let thumbnailResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
context.sharedContext.accountManager.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData)
context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData)
context.sharedContext.accountManager.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData, synchronous: true)
context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData, synchronous: true)
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: nil)
let temporaryWallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailDimensions), resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), TelegramMediaImageRepresentation(dimensions: PixelDimensions(croppedImage.size), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)], settings)

View file

@ -840,6 +840,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return true
case let .setChatWallpaper(wallpaper):
guard message.effectivelyIncoming(strongSelf.context.account.peerId), let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
strongSelf.presentThemeSelection()
return true
}
strongSelf.chatDisplayNode.dismissInput()

View file

@ -198,11 +198,7 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
strongSelf.buttonTitleNode.isHidden = fromYou
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - imageSize.width) / 2.0), y: 13.0), size: imageSize)
if let media {
if mediaUpdated {
// strongSelf.fetchDisposable.set(chatMessagePhotoInteractiveFetched(context: item.context, userLocation: .peer(item.message.id.peerId), photoReference: .message(message: MessageReference(item.message), media: photo), displayAtSize: nil, storeToDownloadsPeerId: nil).start())
}
if let media, mediaUpdated {
let boundingSize = imageSize
var imageSize = boundingSize
let updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>

View file

@ -726,6 +726,16 @@ private func iconColors(theme: PresentationTheme) -> [String: UIColor] {
return colors
}
private func interpolateColors(from: [String: UIColor], to: [String: UIColor], fraction: CGFloat) -> [String: UIColor] {
var colors: [String: UIColor] = [:]
for (key, fromValue) in from {
if let toValue = to[key] {
colors[key] = fromValue.interpolateTo(toValue, fraction: fraction)
}
}
return colors
}
private let defaultEmoticon = "🏠"
private func generateShadowImage() -> UIImage? {
@ -1149,11 +1159,11 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
self.switchThemeButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.animationNode.layer.removeAnimation(forKey: "opacity")
strongSelf.animationNode.alpha = 0.4
strongSelf.animationContainerNode.layer.removeAnimation(forKey: "opacity")
strongSelf.animationContainerNode.alpha = 0.4
} else {
strongSelf.animationNode.alpha = 1.0
strongSelf.animationNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
strongSelf.animationContainerNode.alpha = 1.0
strongSelf.animationContainerNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
@ -1233,6 +1243,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
})
}
private var switchThemeIconAnimator: DisplayLinkAnimator?
func updatePresentationData(_ presentationData: PresentationData) {
guard !self.animatedOut else {
return
@ -1250,22 +1261,20 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal)
self.doneButton.updateTheme(SolidRoundedButtonTheme(theme: self.presentationData.theme))
if self.animationNode.isPlaying {
if let animationNode = self.animationNode.makeCopy(colors: iconColors(theme: self.presentationData.theme), progress: 0.2) {
let previousAnimationNode = self.animationNode
self.animationNode = animationNode
animationNode.completion = { [weak previousAnimationNode] in
previousAnimationNode?.removeFromSupernode()
}
animationNode.isUserInteractionEnabled = false
animationNode.frame = previousAnimationNode.frame
previousAnimationNode.supernode?.insertSubnode(animationNode, belowSubnode: previousAnimationNode)
previousAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatQrCodeScreen.themeCrossfadeDuration, removeOnCompletion: false)
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
let previousIconColors = iconColors(theme: previousTheme)
let newIconColors = iconColors(theme: self.presentationData.theme)
if !self.switchThemeButton.isUserInteractionEnabled {
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay) {
self.switchThemeIconAnimator = DisplayLinkAnimator(duration: ChatThemeScreen.themeCrossfadeDuration * UIView.animationDurationFactor(), from: 0.0, to: 1.0, update: { [weak self] value in
self?.animationNode.setColors(colors: interpolateColors(from: previousIconColors, to: newIconColors, fraction: value))
}, completion: { [weak self] in
self?.switchThemeIconAnimator?.invalidate()
self?.switchThemeIconAnimator = nil
})
}
} else {
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: iconColors(theme: self.presentationData.theme))
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: newIconColors)
}
}
@ -1292,7 +1301,9 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
self.animateCrossfade(animateIcon: false)
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: iconColors(theme: self.presentationData.theme))
self.animationNode.playOnce()
Queue.mainQueue().justDispatch {
self.animationNode.playOnce()
}
let isDarkAppearance = !self.isDarkAppearance
@ -1437,7 +1448,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
let switchThemeFrame = CGRect(origin: CGPoint(x: 3.0, y: 6.0), size: switchThemeSize)
transition.updateFrame(node: self.switchThemeButton, frame: switchThemeFrame)
transition.updateFrame(node: self.animationContainerNode, frame: switchThemeFrame.insetBy(dx: 9.0, dy: 9.0))
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(), size: self.animationContainerNode.frame.size))
transition.updateFrameAsPositionAndBounds(node: self.animationNode, frame: CGRect(origin: CGPoint(), size: self.animationContainerNode.frame.size))
let cancelSize = CGSize(width: 44.0, height: 44.0)
let cancelFrame = CGRect(origin: CGPoint(x: contentFrame.width - cancelSize.width - 3.0, y: 6.0), size: cancelSize)

View file

@ -708,6 +708,16 @@ private func iconColors(theme: PresentationTheme) -> [String: UIColor] {
return colors
}
private func interpolateColors(from: [String: UIColor], to: [String: UIColor], fraction: CGFloat) -> [String: UIColor] {
var colors: [String: UIColor] = [:]
for (key, fromValue) in from {
if let toValue = to[key] {
colors[key] = fromValue.interpolateTo(toValue, fraction: fraction)
}
}
return colors
}
private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelegate {
private let context: AccountContext
private var presentationData: PresentationData
@ -938,11 +948,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.switchThemeButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.animationNode.layer.removeAnimation(forKey: "opacity")
strongSelf.animationNode.alpha = 0.4
strongSelf.animationContainerNode.layer.removeAnimation(forKey: "opacity")
strongSelf.animationContainerNode.alpha = 0.4
} else {
strongSelf.animationNode.alpha = 1.0
strongSelf.animationNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
strongSelf.animationContainerNode.alpha = 1.0
strongSelf.animationContainerNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
@ -982,14 +992,19 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
})
}
private var skipButtonsUpdate = false
private func setEmoticon(_ emoticon: String?) {
self.animateCrossfade(animateIcon: true)
self.skipButtonsUpdate = true
self.previewTheme?(emoticon, self.isDarkAppearance)
self.selectedEmoticon = emoticon
let _ = ensureThemeVisible(listNode: self.listNode, emoticon: emoticon, animated: true)
self.updateButtons()
UIView.transition(with: self.buttonsContentContainerNode.view, duration: ChatThemeScreen.themeCrossfadeDuration, options: [.transitionCrossDissolve, .curveLinear]) {
self.updateButtons()
}
self.skipButtonsUpdate = false
self.themeSelectionsCount += 1
if self.themeSelectionsCount == 2 {
@ -1017,16 +1032,18 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
if accentButtonTheme {
buttonTheme = SolidRoundedButtonTheme(theme: self.presentationData.theme)
} else {
buttonTheme = SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.actionSheet.itemBackgroundColor, foregroundColor: self.presentationData.theme.actionSheet.controlAccentColor)
buttonTheme = SolidRoundedButtonTheme(backgroundColor: .clear, foregroundColor: self.presentationData.theme.actionSheet.controlAccentColor)
}
UIView.performWithoutAnimation {
self.doneButton.title = doneButtonTitle
self.doneButton.font = accentButtonTheme ? .bold : .regular
}
self.doneButton.title = doneButtonTitle
self.doneButton.font = accentButtonTheme ? .bold : .regular
self.doneButton.updateTheme(buttonTheme)
self.otherButton.setTitle(otherButtonTitle, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
}
private var switchThemeIconAnimator: DisplayLinkAnimator?
func updatePresentationData(_ presentationData: PresentationData) {
guard !self.animatedOut else {
return
@ -1042,25 +1059,28 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
}
self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal)
self.doneButton.updateTheme(SolidRoundedButtonTheme(theme: self.presentationData.theme))
self.updateButtons()
if self.animationNode.isPlaying {
if let animationNode = self.animationNode.makeCopy(colors: iconColors(theme: self.presentationData.theme), progress: 0.2) {
let previousAnimationNode = self.animationNode
self.animationNode = animationNode
let previousIconColors = iconColors(theme: previousTheme)
let newIconColors = iconColors(theme: self.presentationData.theme)
if !self.switchThemeButton.isUserInteractionEnabled {
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay * UIView.animationDurationFactor()) {
self.switchThemeIconAnimator = DisplayLinkAnimator(duration: ChatThemeScreen.themeCrossfadeDuration * UIView.animationDurationFactor(), from: 0.0, to: 1.0, update: { [weak self] value in
self?.animationNode.setColors(colors: interpolateColors(from: previousIconColors, to: newIconColors, fraction: value))
}, completion: { [weak self] in
self?.switchThemeIconAnimator?.invalidate()
self?.switchThemeIconAnimator = nil
})
animationNode.completion = { [weak previousAnimationNode] in
previousAnimationNode?.removeFromSupernode()
UIView.transition(with: self.buttonsContentContainerNode.view, duration: ChatThemeScreen.themeCrossfadeDuration, options: [.transitionCrossDissolve, .curveLinear]) {
self.updateButtons()
}
animationNode.isUserInteractionEnabled = false
animationNode.frame = previousAnimationNode.frame
previousAnimationNode.supernode?.insertSubnode(animationNode, belowSubnode: previousAnimationNode)
previousAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, removeOnCompletion: false)
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
} else {
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: iconColors(theme: self.presentationData.theme))
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: newIconColors)
if !self.skipButtonsUpdate {
self.updateButtons()
}
}
}
@ -1107,7 +1127,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.animateCrossfade(animateIcon: false)
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: iconColors(theme: self.presentationData.theme))
self.animationNode.playOnce()
Queue.mainQueue().justDispatch {
self.animationNode.playOnce()
}
let isDarkAppearance = !self.isDarkAppearance
self.previewTheme?(self.selectedEmoticon, isDarkAppearance)
@ -1129,8 +1151,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
snapshotView?.removeFromSuperview()
})
}
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay) {
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay * UIView.animationDurationFactor()) {
if let effectView = self.effectNode.view as? UIVisualEffectView {
UIView.animate(withDuration: ChatThemeScreen.themeCrossfadeDuration, delay: 0.0, options: .curveLinear) {
effectView.effect = UIBlurEffect(style: self.presentationData.theme.actionSheet.backgroundType == .light ? .light : .dark)
@ -1151,6 +1173,15 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
snapshotView?.removeFromSuperview()
})
}
if !animateIcon, let snapshotView = self.otherButton.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.otherButton.frame
self.otherButton.view.superview?.insertSubview(snapshotView, aboveSubview: self.otherButton.view)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
}
self.listNode.forEachVisibleItemNode { node in
if let node = node as? ThemeSettingsThemeItemIconNode {
@ -1293,7 +1324,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
let switchThemeFrame = CGRect(origin: CGPoint(x: 3.0, y: 6.0), size: switchThemeSize)
transition.updateFrame(node: self.switchThemeButton, frame: switchThemeFrame)
transition.updateFrame(node: self.animationContainerNode, frame: switchThemeFrame.insetBy(dx: 9.0, dy: 9.0))
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(), size: self.animationContainerNode.frame.size))
transition.updateFrameAsPositionAndBounds(node: self.animationNode, frame: CGRect(origin: .zero, size: self.animationContainerNode.frame.size))
let cancelSize = CGSize(width: 44.0, height: 44.0)
let cancelFrame = CGRect(origin: CGPoint(x: contentFrame.width - cancelSize.width - 3.0, y: 6.0), size: cancelSize)

View file

@ -398,7 +398,7 @@ private func fetchCachedBlurredWallpaperRepresentation(resource: MediaResource,
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
let url = URL(fileURLWithPath: path)
if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
if let colorImage = blurredImage(image, radius: 20.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
let colorQuality: Float = 0.5
@ -447,7 +447,7 @@ private func fetchCachedBlurredWallpaperRepresentation(account: Account, resourc
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
let url = URL(fileURLWithPath: path)
if let colorImage = blurredImage(image, radius: 30.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
if let colorImage = blurredImage(image, radius: 20.0), let colorDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
CGImageDestinationSetProperties(colorDestination, [:] as CFDictionary)
let colorQuality: Float = 0.5

View file

@ -289,14 +289,14 @@ public func wallpaperImage(account: Account, accountManager: AccountManager<Tele
}
if let blurredThumbnailImage = blurredThumbnailImage, fullSizeImage == nil {
guard let context = DrawingContext(size: blurredThumbnailImage.size, scale: blurredThumbnailImage.scale, clear: true) else {
guard let context = DrawingContext(size: arguments.drawingSize, clear: true) else {
return nil
}
context.withFlippedContext { c in
c.setBlendMode(.copy)
if let cgImage = blurredThumbnailImage.cgImage {
c.interpolationQuality = .none
drawImage(context: c, image: cgImage, orientation: imageOrientation, in: CGRect(origin: CGPoint(), size: blurredThumbnailImage.size))
c.interpolationQuality = .medium
drawImage(context: c, image: cgImage, orientation: imageOrientation, in: fittedRect)
c.setBlendMode(.normal)
}
}