mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
156 lines
6.3 KiB
Swift
156 lines
6.3 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import TelegramPresentationData
|
|
|
|
private let infinityFont = Font.with(size: 15.0, design: .round, weight: .bold)
|
|
private let textFont = Font.with(size: 13.0, design: .round, weight: .bold)
|
|
private let smallTextFont = Font.with(size: 11.0, design: .round, weight: .bold)
|
|
|
|
private class ChatMessageLiveLocationTimerNodeParams: NSObject {
|
|
let backgroundColor: UIColor
|
|
let foregroundColor: UIColor
|
|
let textColor: UIColor
|
|
let value: CGFloat
|
|
let string: String
|
|
|
|
init(backgroundColor: UIColor, foregroundColor: UIColor, textColor: UIColor, value: CGFloat, string: String) {
|
|
self.backgroundColor = backgroundColor
|
|
self.foregroundColor = foregroundColor
|
|
self.textColor = textColor
|
|
self.value = value
|
|
self.string = string
|
|
|
|
super.init()
|
|
}
|
|
}
|
|
|
|
private final class RadialTimeoutNodeTimer: NSObject {
|
|
let action: () -> Void
|
|
init(_ action: @escaping () -> Void) {
|
|
self.action = action
|
|
|
|
super.init()
|
|
}
|
|
|
|
@objc func event() {
|
|
self.action()
|
|
}
|
|
}
|
|
|
|
public final class ChatMessageLiveLocationTimerNode: ASDisplayNode {
|
|
private var timeoutAndColors: (UIColor, UIColor, UIColor, Double, Double, PresentationStrings)?
|
|
private var animationTimer: Timer?
|
|
|
|
override public init() {
|
|
super.init()
|
|
|
|
self.isOpaque = false
|
|
}
|
|
|
|
deinit {
|
|
self.animationTimer?.invalidate()
|
|
}
|
|
|
|
public func update(backgroundColor: UIColor, foregroundColor: UIColor, textColor: UIColor, beginTimestamp: Double, timeout: Double, strings: PresentationStrings) {
|
|
if self.timeoutAndColors?.3 != beginTimestamp || self.timeoutAndColors?.4 != timeout {
|
|
self.animationTimer?.invalidate()
|
|
self.timeoutAndColors = (backgroundColor, foregroundColor, textColor, beginTimestamp, timeout, strings)
|
|
|
|
let animationTimer = Timer(timeInterval: 10.0, target: RadialTimeoutNodeTimer({ [weak self] in
|
|
self?.setNeedsDisplay()
|
|
}), selector: #selector(RadialTimeoutNodeTimer.event), userInfo: nil, repeats: true)
|
|
self.animationTimer = animationTimer
|
|
RunLoop.main.add(animationTimer, forMode: .common)
|
|
|
|
self.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
public override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
|
var value: CGFloat = 0.0
|
|
if let (backgroundColor, foregroundColor, textColor, beginTimestamp, timeout, strings) = self.timeoutAndColors {
|
|
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
|
let remaining = beginTimestamp + timeout - timestamp
|
|
value = CGFloat(max(0.0, 1.0 - min(1.0, remaining / timeout)))
|
|
|
|
let string: String
|
|
if timeout < 0.0 {
|
|
value = 0.0
|
|
string = "∞"
|
|
} else {
|
|
let intRemaining = Int32(remaining)
|
|
if intRemaining > 60 * 60 {
|
|
let hours = Int32(round(remaining / (60.0 * 60.0)))
|
|
string = strings.Map_LiveLocationShortHour("\(hours)").string
|
|
} else {
|
|
let minutes = Int32(round(remaining / (60.0)))
|
|
string = "\(minutes)"
|
|
}
|
|
}
|
|
|
|
return ChatMessageLiveLocationTimerNodeParams(backgroundColor: backgroundColor, foregroundColor: foregroundColor, textColor: textColor, value: value, string: string)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
@objc override public 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? ChatMessageLiveLocationTimerNodeParams {
|
|
let lineWidth: CGFloat = 1.5
|
|
|
|
context.setBlendMode(.copy)
|
|
context.setFillColor(parameters.backgroundColor.cgColor)
|
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: bounds.size.width, height: bounds.size.height)))
|
|
context.setFillColor(UIColor.clear.cgColor)
|
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: lineWidth, y: lineWidth), size: CGSize(width: bounds.size.width - lineWidth * 2.0, height: bounds.size.height - lineWidth * 2.0)))
|
|
context.setBlendMode(.normal)
|
|
|
|
context.setStrokeColor(parameters.foregroundColor.cgColor)
|
|
|
|
let progress = 1.0 - parameters.value
|
|
let startAngle = -CGFloat(progress) * 2.0 * CGFloat.pi - CGFloat.pi / 2.0
|
|
let endAngle = CGFloat(progress) * 2.0 * CGFloat.pi + startAngle
|
|
|
|
let pathDiameter = bounds.size.width - lineWidth
|
|
|
|
let path = UIBezierPath(arcCenter: CGPoint(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0), radius: pathDiameter / 2.0, startAngle: startAngle, endAngle: endAngle, clockwise:true)
|
|
path.lineWidth = lineWidth
|
|
path.lineCapStyle = .round
|
|
path.stroke()
|
|
|
|
let font: UIFont
|
|
if parameters.string == "∞" {
|
|
font = infinityFont
|
|
} else if parameters.string.count > 2 {
|
|
font = smallTextFont
|
|
} else {
|
|
font = textFont
|
|
}
|
|
|
|
let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: parameters.foregroundColor]
|
|
let nsString = parameters.string as NSString
|
|
let size = nsString.size(withAttributes: attributes)
|
|
|
|
var offset = CGPoint()
|
|
if parameters.string == "∞" {
|
|
offset = CGPoint(x: 1.0, y: -1.0)
|
|
} else if parameters.string.count > 2 {
|
|
offset = CGPoint(x: 0.0, y: UIScreenPixel)
|
|
}
|
|
|
|
nsString.draw(at: CGPoint(x: floor((bounds.size.width - size.width) / 2.0) + offset.x, y: floor((bounds.size.height - size.height) / 2.0) + offset.y), withAttributes: attributes)
|
|
}
|
|
}
|
|
}
|
|
|