import Foundation import UIKit import AsyncDisplayKit import Display import SwiftSignalKit import TelegramPresentationData import AccountContext private final class ChatTextInputAudioRecordingTimeNodeParameters: NSObject { let timestamp: Double let theme: PresentationTheme init(timestamp: Double, theme: PresentationTheme) { self.timestamp = timestamp self.theme = theme super.init() } } private let textFont = Font.regular(15.0) final class ChatTextInputAudioRecordingTimeNode: ASDisplayNode { private let textNode: TextNode private var timestamp: Double = 0.0 { didSet { self.setNeedsDisplay() } } private let stateDisposable = MetaDisposable() var audioRecorder: ManagedAudioRecorder? { didSet { if self.audioRecorder !== oldValue { if let audioRecorder = self.audioRecorder { self.stateDisposable.set(audioRecorder.recordingState.start(next: { [weak self] state in if let strongSelf = self { switch state { case let .paused(duration): strongSelf.timestamp = duration case let .recording(duration, _): strongSelf.timestamp = duration case .stopped: break } } })) } else { self.stateDisposable.set(nil) } } } } private var durationDisposable: MetaDisposable? var videoRecordingStatus: InstantVideoControllerRecordingStatus? { didSet { if self.videoRecordingStatus !== oldValue { if self.durationDisposable == nil { durationDisposable = MetaDisposable() } if let videoRecordingStatus = self.videoRecordingStatus { self.durationDisposable?.set(videoRecordingStatus.duration.start(next: { [weak self] duration in Queue.mainQueue().async { [weak self] in self?.timestamp = duration } })) } else if self.audioRecorder == nil { self.durationDisposable?.set(nil) } } } } private var theme: PresentationTheme init(theme: PresentationTheme) { self.theme = theme self.textNode = TextNode() super.init() self.isOpaque = false } deinit { self.stateDisposable.dispose() } func updateTheme(theme: PresentationTheme) { self.theme = theme self.setNeedsDisplay() } override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { let makeLayout = TextNode.asyncLayout(self.textNode) let (size, apply) = makeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "00:00,00", font: Font.regular(15.0), textColor: theme.chat.inputPanel.primaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 200.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let _ = apply() self.textNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 1.0 + UIScreenPixel), size: size.size) return size.size } override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? { return ChatTextInputAudioRecordingTimeNodeParameters(timestamp: self.timestamp, theme: self.theme) } @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? ChatTextInputAudioRecordingTimeNodeParameters { let currentAudioDurationSeconds = Int(parameters.timestamp) let currentAudioDurationMilliseconds = Int(parameters.timestamp * 100.0) % 100 let text = String(format: "%d:%02d,%02d", currentAudioDurationSeconds / 60, currentAudioDurationSeconds % 60, currentAudioDurationMilliseconds) let string = NSAttributedString(string: text, font: textFont, textColor: parameters.theme.chat.inputPanel.primaryTextColor) string.draw(at: CGPoint()) } } }