import Foundation import UIKit import AsyncDisplayKit import Display import SwiftSignalKit import TelegramPresentationData final class MinimizedHeaderNode: ASDisplayNode { var theme: NavigationControllerTheme let strings: PresentationStrings private let minimizedBackgroundNode: ASDisplayNode private let minimizedTitleNode: ImmediateTextNode private let minimizedCloseButton: HighlightableButtonNode private var minimizedTitleDisposable: Disposable? private var _controllers: [Weak] = [] var controllers: [ViewController] { get { return self._controllers.compactMap { $0.value } } set { if !newValue.isEmpty { if newValue.count != self.controllers.count { self._controllers = newValue.map { Weak($0) } self.minimizedTitleDisposable?.dispose() self.minimizedTitleDisposable = nil var signals: [Signal] = [] for controller in newValue { signals.append(controller.titleSignal) } self.minimizedTitleDisposable = (combineLatest(signals) |> deliverOnMainQueue).start(next: { [weak self] titles in guard let self else { return } let titles = titles.compactMap { $0 } if titles.count == 1, let title = titles.first { self.title = title } else if let title = titles.last { let othersString = self.strings.WebApp_MinimizedTitle_Others(Int32(titles.count - 1)) self.title = self.strings.WebApp_MinimizedTitleFormat(title, othersString).string } else { self.title = nil } }) } } else { self.minimizedTitleDisposable?.dispose() self.minimizedTitleDisposable = nil } } } var title: String? { didSet { if let (size, insets) = self.validLayout { self.update(size: size, insets: insets, transition: .immediate) } } } var requestClose: () -> Void = {} var requestMaximize: () -> Void = {} private var validLayout: (CGSize, UIEdgeInsets)? init(theme: NavigationControllerTheme, strings: PresentationStrings) { self.theme = theme self.strings = strings self.minimizedBackgroundNode = ASDisplayNode() self.minimizedBackgroundNode.cornerRadius = 10.0 self.minimizedBackgroundNode.clipsToBounds = true self.minimizedBackgroundNode.backgroundColor = theme.navigationBar.opaqueBackgroundColor if #available(iOS 11.0, *) { self.minimizedBackgroundNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] } self.minimizedTitleNode = ImmediateTextNode() self.minimizedCloseButton = HighlightableButtonNode() self.minimizedCloseButton.setImage(UIImage(bundleImageName: "Instant View/Close"), for: .normal) super.init() self.clipsToBounds = true self.addSubnode(self.minimizedBackgroundNode) self.minimizedBackgroundNode.addSubnode(self.minimizedTitleNode) self.minimizedBackgroundNode.addSubnode(self.minimizedCloseButton) self.minimizedCloseButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: .touchUpInside) applySmoothRoundedCorners(self.minimizedBackgroundNode.layer) } deinit { self.minimizedTitleDisposable?.dispose() } override func didLoad() { super.didLoad() self.minimizedBackgroundNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.maximizeTapGesture(_:)))) } @objc private func closePressed() { self.requestClose() } @objc private func maximizeTapGesture(_ recognizer: UITapGestureRecognizer) { if case .ended = recognizer.state { let location = recognizer.location(in: self.view) if location.x < 48.0 { self.requestClose() } else { self.requestMaximize() } } } func update(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) { self.validLayout = (size, insets) let headerHeight: CGFloat = 44.0 let titleSideInset: CGFloat = 56.0 + insets.left self.minimizedTitleNode.attributedText = NSAttributedString(string: title ?? "", font: Font.bold(17.0), textColor: self.theme.navigationBar.primaryTextColor) let titleSize = self.minimizedTitleNode.updateLayout(CGSize(width: size.width - titleSideInset * 2.0, height: headerHeight)) let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: floorToScreenPixels((headerHeight - titleSize.height) / 2.0)), size: titleSize) self.minimizedTitleNode.bounds = CGRect(origin: .zero, size: titleFrame.size) transition.updatePosition(node: self.minimizedTitleNode, position: titleFrame.center) transition.updateFrame(node: self.minimizedCloseButton, frame: CGRect(origin: CGPoint(x: insets.left, y: 0.0), size: CGSize(width: 44.0, height: 44.0))) transition.updateFrame(node: self.minimizedBackgroundNode, frame: CGRect(origin: .zero, size: CGSize(width: size.width, height: 243.0))) } }