mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
135 lines
3.5 KiB
Swift
135 lines
3.5 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import SwiftSignalKit
|
|
import AsyncDisplayKit
|
|
import Accelerate
|
|
import ImageBlur
|
|
|
|
private class BlurLayer: CALayer {
|
|
private static let blurRadiusKey = "blurRadius"
|
|
@NSManaged var blurRadius: CGFloat
|
|
|
|
private var fromBlurRadius: CGFloat?
|
|
var presentationRadius: CGFloat {
|
|
if let radius = self.fromBlurRadius {
|
|
if let layer = presentation() {
|
|
return layer.blurRadius
|
|
} else {
|
|
return radius
|
|
}
|
|
} else {
|
|
return self.blurRadius
|
|
}
|
|
}
|
|
|
|
override class func needsDisplay(forKey key: String) -> Bool {
|
|
if key == blurRadiusKey {
|
|
return true
|
|
}
|
|
return super.needsDisplay(forKey: key)
|
|
}
|
|
|
|
open override func action(forKey event: String) -> CAAction? {
|
|
if event == BlurLayer.blurRadiusKey {
|
|
self.fromBlurRadius = nil
|
|
|
|
if let action = super.action(forKey: "opacity") as? CABasicAnimation {
|
|
self.fromBlurRadius = (presentation() ?? self).blurRadius
|
|
|
|
action.keyPath = event
|
|
action.fromValue = self.fromBlurRadius
|
|
return action
|
|
}
|
|
}
|
|
|
|
return super.action(forKey: event)
|
|
}
|
|
|
|
func draw(_ image: UIImage) {
|
|
self.contents = image.cgImage
|
|
self.contentsScale = image.scale
|
|
self.contentsGravity = .resizeAspectFill
|
|
}
|
|
|
|
func render(in context: CGContext, for layer: CALayer) {
|
|
layer.render(in: context)
|
|
}
|
|
}
|
|
|
|
class BlurView: UIView {
|
|
override class var layerClass : AnyClass {
|
|
return BlurLayer.self
|
|
}
|
|
|
|
private var blurLayer: BlurLayer {
|
|
return self.layer as! BlurLayer
|
|
}
|
|
|
|
var image: UIImage?
|
|
|
|
private let queue: Queue = {
|
|
return Queue(name: nil, qos: .userInteractive)
|
|
}()
|
|
|
|
open var blurRadius: CGFloat {
|
|
set { self.blurLayer.blurRadius = newValue }
|
|
get { return self.blurLayer.blurRadius }
|
|
}
|
|
|
|
public override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
self.isUserInteractionEnabled = false
|
|
}
|
|
|
|
public required init?(coder aDecoder: NSCoder) {
|
|
super.init(coder: aDecoder)
|
|
self.isUserInteractionEnabled = false
|
|
}
|
|
|
|
private func async(on queue: DispatchQueue, actions: @escaping () -> Void) {
|
|
queue.async(execute: actions)
|
|
}
|
|
|
|
private func sync(on queue: DispatchQueue, actions: () -> Void) {
|
|
queue.sync(execute: actions)
|
|
}
|
|
|
|
private func draw(_ image: UIImage, blurRadius: CGFloat) {
|
|
self.queue.async { [weak self] in
|
|
if let strongSelf = self, let blurredImage = blurredImage(image, radius: blurRadius) {
|
|
Queue.mainQueue().sync {
|
|
strongSelf.blurLayer.draw(blurredImage)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override func display(_ layer: CALayer) {
|
|
let blurRadius = self.blurLayer.presentationRadius
|
|
if let image = self.image {
|
|
self.draw(image, blurRadius: blurRadius)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class BlurredImageNode: ASDisplayNode {
|
|
var image: UIImage? {
|
|
didSet {
|
|
self.blurView.image = self.image
|
|
self.blurView.layer.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
var blurView: BlurView {
|
|
return (self.view as? BlurView)!
|
|
}
|
|
|
|
override init() {
|
|
super.init()
|
|
|
|
self.setViewBlock({
|
|
return BlurView()
|
|
})
|
|
}
|
|
}
|