Files
ghostgram/submodules/TelegramCallsUI/Sources/VoiceChatShareScreenContextItem.swift

196 lines
8.5 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import TelegramPresentationData
import AppBundle
import ContextUI
import TelegramStringFormatting
import ReplayKit
import AccountContext
final class VoiceChatShareScreenContextItem: ContextMenuCustomItem {
fileprivate let context: AccountContext
fileprivate let text: String
fileprivate let icon: (PresentationTheme) -> UIImage?
fileprivate let action: (ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void
init(context: AccountContext, text: String, icon: @escaping (PresentationTheme) -> UIImage?, action: @escaping (ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void) {
self.context = context
self.text = text
self.icon = icon
self.action = action
}
func node(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) -> ContextMenuCustomNode {
return VoiceChatShareScreenContextItemNode(presentationData: presentationData, item: self, getController: getController, actionSelected: actionSelected)
}
}
private let textFont = Font.regular(17.0)
private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextMenuCustomNode {
private let item: VoiceChatShareScreenContextItem
private let presentationData: PresentationData
private let getController: () -> ContextControllerProtocol?
private let actionSelected: (ContextMenuActionResult) -> Void
private let backgroundNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
private let textNode: ImmediateTextNode
private let iconNode: ASImageNode
private var timer: SwiftSignalKit.Timer?
private var pointerInteraction: PointerInteraction?
private var broadcastPickerView: UIView?
private var applicationStateDisposable: Disposable?
init(presentationData: PresentationData, item: VoiceChatShareScreenContextItem, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) {
self.item = item
self.presentationData = presentationData
self.getController = getController
self.actionSelected = actionSelected
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize)
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isAccessibilityElement = false
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isAccessibilityElement = false
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
self.highlightedBackgroundNode.alpha = 0.0
self.textNode = ImmediateTextNode()
self.textNode.isAccessibilityElement = false
self.textNode.isUserInteractionEnabled = false
self.textNode.displaysAsynchronously = false
self.textNode.attributedText = NSAttributedString(string: item.text, font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
self.textNode.maximumNumberOfLines = 1
if #available(iOS 12.0, *) {
let broadcastPickerView = RPSystemBroadcastPickerView(frame: CGRect(x: 0, y: 0, width: 50, height: 52.0))
broadcastPickerView.alpha = 0.02
broadcastPickerView.preferredExtension = "\(item.context.sharedContext.applicationBindings.appBundleId).BroadcastUpload"
broadcastPickerView.showsMicrophoneButton = false
self.broadcastPickerView = broadcastPickerView
}
self.iconNode = ASImageNode()
self.iconNode.isAccessibilityElement = false
self.iconNode.displaysAsynchronously = false
self.iconNode.displayWithoutProcessing = true
self.iconNode.isUserInteractionEnabled = false
self.iconNode.image = item.icon(presentationData.theme)
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.highlightedBackgroundNode)
if let broadcastPickerView = self.broadcastPickerView {
self.view.addSubview(broadcastPickerView)
}
self.addSubnode(self.textNode)
self.addSubnode(self.iconNode)
}
deinit {
self.timer?.invalidate()
self.applicationStateDisposable?.dispose()
}
override func didLoad() {
super.didLoad()
self.applicationStateDisposable = (self.item.context.sharedContext.applicationBindings.applicationIsActive
|> filter { !$0 }
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.getController()?.dismiss(completion: nil)
})
}
private var validLayout: CGSize?
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
let sideInset: CGFloat = 16.0
let iconSideInset: CGFloat = 12.0
let verticalInset: CGFloat = 12.0
let iconSize = self.iconNode.image.flatMap({ $0.size }) ?? CGSize()
let standardIconWidth: CGFloat = 32.0
var rightTextInset: CGFloat = sideInset
if !iconSize.width.isZero {
rightTextInset = max(iconSize.width, standardIconWidth) + iconSideInset + sideInset
}
let textSize = self.textNode.updateLayout(CGSize(width: constrainedWidth - sideInset - rightTextInset, height: .greatestFiniteMagnitude))
let verticalSpacing: CGFloat = 2.0
let combinedTextHeight = textSize.height + verticalSpacing
return (CGSize(width: textSize.width + sideInset + rightTextInset, height: verticalInset * 2.0 + combinedTextHeight), { size, transition in
self.validLayout = size
let verticalOrigin = floor((size.height - combinedTextHeight) / 2.0)
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
if !iconSize.width.isZero {
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
transition.updateFrame(node: self.highlightedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
if let broadcastPickerView = self.broadcastPickerView {
broadcastPickerView.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))
}
})
}
func updateTheme(presentationData: PresentationData) {
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize)
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
}
@objc private func buttonPressed() {
self.performAction()
}
func canBeHighlighted() -> Bool {
return true
}
func updateIsHighlighted(isHighlighted: Bool) {
self.setIsHighlighted(isHighlighted)
}
func performAction() {
guard let controller = self.getController() else {
return
}
self.item.action(controller, { [weak self] result in
self?.actionSelected(result)
})
}
func setIsHighlighted(_ value: Bool) {
if value {
self.highlightedBackgroundNode.alpha = 1.0
} else {
self.highlightedBackgroundNode.alpha = 0.0
}
}
}