import Foundation import UIKit import AsyncDisplayKit import Display import SwiftSignalKit private func attributedStringForDebugInfo(_ info: String, version: String) -> NSAttributedString { guard !info.isEmpty else { return NSAttributedString(string: "") } var string = info string = "libtgvoip v\(version)\n" + string string = string.replacingOccurrences(of: "Remote endpoints: \n", with: "") string = string.replacingOccurrences(of: "Jitter ", with: "\nJitter ") string = string.replacingOccurrences(of: "Key fingerprint:\n", with: "Key fingerprint: ") let attributedString = NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.font: Font.monospace(10), NSAttributedString.Key.foregroundColor: UIColor.white]) let titleStyle = NSMutableParagraphStyle() titleStyle.alignment = .center titleStyle.lineSpacing = 7.0 let style = NSMutableParagraphStyle() style.lineHeightMultiple = 1.15 let secondaryColor = UIColor(rgb: 0xa6a9a8) let activeColor = UIColor(rgb: 0xa0d875) let titleAttributes = [NSAttributedString.Key.font: Font.semiboldMonospace(15), NSAttributedString.Key.paragraphStyle: titleStyle] let nameAttributes = [NSAttributedString.Key.font: Font.semiboldMonospace(10), NSAttributedString.Key.foregroundColor: secondaryColor] let styleAttributes = [NSAttributedString.Key.paragraphStyle: style] let typeAttributes = [NSAttributedString.Key.foregroundColor: secondaryColor] let activeAttributes = [NSAttributedString.Key.font: Font.semiboldMonospace(10), NSAttributedString.Key.foregroundColor: activeColor] let range = string.startIndex ..< string.endIndex string.enumerateSubstrings(in: range, options: NSString.EnumerationOptions.byLines) { (line, range, _, _) in guard let line = line else { return } if range.lowerBound == string.startIndex { attributedString.addAttributes(titleAttributes, range: NSRange(range, in: string)) } else { if let semicolonRange = line.range(of: ":") { if let bracketRange = line.range(of: "[") { if let _ = line.range(of: "IN_USE") { attributedString.addAttributes(activeAttributes, range: NSRange(range, in: string)) } else { let offset = line.distance(from: line.startIndex, to: bracketRange.lowerBound) let distance = line.distance(from: line.startIndex, to: line.endIndex) attributedString.addAttributes(typeAttributes, range: NSRange(string.index(range.lowerBound, offsetBy: offset) ..< string.index(range.lowerBound, offsetBy: distance), in: string)) } } else { attributedString.addAttributes(styleAttributes, range: NSRange(range, in: string)) let offset = line.distance(from: line.startIndex, to: semicolonRange.upperBound) attributedString.addAttributes(nameAttributes, range: NSRange(range.lowerBound ..< string.index(range.lowerBound, offsetBy: offset), in: string)) } } } } return attributedString } final class CallDebugNode: ASDisplayNode { private let disposable = MetaDisposable() private let dimNode: ASDisplayNode private let textNode: ASTextNode private let timestamp = CACurrentMediaTime() public var dismiss: (() -> Void)? init(signal: Signal<(String, String), NoError>) { self.dimNode = ASDisplayNode() self.dimNode.isLayerBacked = true self.dimNode.backgroundColor = UIColor(rgb: 0x26282c, alpha: 0.95) self.dimNode.isUserInteractionEnabled = false self.textNode = ASTextNode() self.textNode.isUserInteractionEnabled = false super.init() self.addSubnode(self.dimNode) self.addSubnode(self.textNode) self.disposable.set((signal |> deliverOnMainQueue).start(next: { [weak self] (version, info) in self?.update(info, version: version) })) } deinit { self.disposable.dispose() } override func didLoad() { super.didLoad() let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))) self.view.addGestureRecognizer(tapRecognizer) } private func update(_ info: String, version: String) { self.textNode.attributedText = attributedStringForDebugInfo(info, version: version) self.setNeedsLayout() } @objc func tapGesture(_ recognizer: UITapGestureRecognizer) { if CACurrentMediaTime() - self.timestamp > 1.0 { self.dismiss?() } } override func layout() { super.layout() let size = self.bounds.size self.dimNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height)) let textSize = textNode.measure(CGSize(width: size.width - 20.0, height: size.height)) self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize) } }