mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
178 lines
5.5 KiB
Swift
178 lines
5.5 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import AsyncDisplayKit
|
|
|
|
private final class LiveLocationWavesNodeParams: NSObject {
|
|
let color: UIColor
|
|
let extend: Bool
|
|
let progress: CGFloat
|
|
|
|
init(color: UIColor, extend: Bool, progress: CGFloat) {
|
|
self.color = color
|
|
self.extend = extend
|
|
self.progress = progress
|
|
|
|
super.init()
|
|
}
|
|
}
|
|
|
|
private func degToRad(_ degrees: CGFloat) -> CGFloat {
|
|
return degrees * CGFloat.pi / 180.0
|
|
}
|
|
|
|
public final class LiveLocationWavesNode: ASDisplayNode {
|
|
public var color: UIColor {
|
|
didSet {
|
|
self.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
public var extend: Bool {
|
|
didSet {
|
|
self.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
private var effectiveProgress: CGFloat = 0.0 {
|
|
didSet {
|
|
self.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
var animator: ConstantDisplayLinkAnimator?
|
|
|
|
public init(color: UIColor, extend: Bool = false) {
|
|
self.color = color
|
|
self.extend = extend
|
|
|
|
super.init()
|
|
|
|
self.isLayerBacked = true
|
|
self.isOpaque = false
|
|
}
|
|
|
|
deinit {
|
|
self.animator?.invalidate()
|
|
}
|
|
|
|
private var previousAnimationStart: Double?
|
|
private func updateAnimations(inHierarchy: Bool) {
|
|
let timestamp = CACurrentMediaTime()
|
|
|
|
let animating: Bool
|
|
|
|
if inHierarchy {
|
|
animating = true
|
|
|
|
let animator: ConstantDisplayLinkAnimator
|
|
if let current = self.animator {
|
|
animator = current
|
|
} else {
|
|
animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
|
self?.updateAnimations(inHierarchy: true)
|
|
})
|
|
self.animator = animator
|
|
}
|
|
animator.isPaused = false
|
|
} else {
|
|
animating = false
|
|
self.animator?.isPaused = true
|
|
self.previousAnimationStart = nil
|
|
}
|
|
|
|
if animating {
|
|
let animationDuration: Double = 2.5
|
|
if var startTimestamp = self.previousAnimationStart {
|
|
if timestamp > startTimestamp + animationDuration {
|
|
while timestamp > startTimestamp + animationDuration {
|
|
startTimestamp += animationDuration
|
|
}
|
|
startTimestamp -= animationDuration
|
|
}
|
|
|
|
let t = min(1.0, max(0.0, (timestamp - startTimestamp) / animationDuration))
|
|
self.effectiveProgress = CGFloat(t)
|
|
} else {
|
|
self.previousAnimationStart = timestamp
|
|
}
|
|
}
|
|
}
|
|
|
|
public override func willEnterHierarchy() {
|
|
super.willEnterHierarchy()
|
|
|
|
self.updateAnimations(inHierarchy: true)
|
|
}
|
|
|
|
public override func didExitHierarchy() {
|
|
super.didExitHierarchy()
|
|
|
|
self.updateAnimations(inHierarchy: false)
|
|
}
|
|
|
|
public override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
|
let t = CACurrentMediaTime()
|
|
let value: CGFloat = CGFloat(t.truncatingRemainder(dividingBy: 2.0)) / 2.0
|
|
return LiveLocationWavesNodeParams(color: self.color, extend: self.extend, progress: value)
|
|
}
|
|
|
|
@objc public override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
|
let context = UIGraphicsGetCurrentContext()!
|
|
|
|
if !isRasterizing {
|
|
context.setBlendMode(.copy)
|
|
context.setFillColor(UIColor.clear.cgColor)
|
|
context.fill(bounds)
|
|
}
|
|
|
|
if let parameters = parameters as? LiveLocationWavesNodeParams {
|
|
let center = CGPoint(x: bounds.width / 2.0, y: bounds.height / 2.0)
|
|
let length: CGFloat = 9.0
|
|
|
|
context.setFillColor(parameters.color.cgColor)
|
|
|
|
let draw: (CGContext, CGFloat, Bool) -> Void = { context, pos, right in
|
|
let path = CGMutablePath()
|
|
|
|
path.addArc(center: center, radius: length * pos + 7.0, startAngle: right ? degToRad(-26.0) : degToRad(154.0), endAngle: right ? degToRad(26.0) : degToRad(206.0), clockwise: false)
|
|
|
|
let strokedArc = path.copy(strokingWithWidth: 1.65, lineCap: .round, lineJoin: .miter, miterLimit: 10.0)
|
|
|
|
context.addPath(strokedArc)
|
|
|
|
context.fillPath()
|
|
}
|
|
|
|
let position = parameters.progress
|
|
var alpha = position / 0.5
|
|
if alpha > 1.0 {
|
|
alpha = 2.0 - alpha
|
|
}
|
|
context.setAlpha(alpha * 0.7)
|
|
|
|
if !parameters.extend {
|
|
draw(context, position, false)
|
|
}
|
|
draw(context, position, true)
|
|
|
|
var progress = parameters.progress + 0.5
|
|
if progress > 1.0 {
|
|
progress = progress - 1.0
|
|
}
|
|
|
|
let largerPos = progress
|
|
var largerAlpha = largerPos / 0.5
|
|
if largerAlpha > 1.0 {
|
|
largerAlpha = 2.0 - largerAlpha
|
|
}
|
|
context.setAlpha(largerAlpha * 0.7)
|
|
|
|
if !parameters.extend {
|
|
draw(context, largerPos, false)
|
|
}
|
|
draw(context, largerPos, true)
|
|
}
|
|
}
|
|
}
|