mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-15 18:59:54 +00:00
Video Chat Improvements
This commit is contained in:
parent
e0f9f4614d
commit
a434c891a2
@ -147,7 +147,23 @@ final class GroupVideoNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var aspectRatio: CGFloat {
|
||||
return self.videoView.getAspect()
|
||||
let orientation = self.videoView.getOrientation()
|
||||
var aspect = self.videoView.getAspect()
|
||||
if aspect <= 0.01 {
|
||||
aspect = 3.0 / 4.0
|
||||
}
|
||||
let rotatedAspect: CGFloat
|
||||
switch orientation {
|
||||
case .rotation0:
|
||||
rotatedAspect = 1.0 / aspect
|
||||
case .rotation90:
|
||||
rotatedAspect = aspect
|
||||
case .rotation180:
|
||||
rotatedAspect = 1.0 / aspect
|
||||
case .rotation270:
|
||||
rotatedAspect = aspect
|
||||
}
|
||||
return rotatedAspect
|
||||
}
|
||||
|
||||
var keepBackdropSize = false
|
||||
@ -247,7 +263,7 @@ final class GroupVideoNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
if let backdropEffectView = self.backdropEffectView {
|
||||
let maxSide = max(bounds.width, bounds.height)
|
||||
let maxSide = max(bounds.width, bounds.height) * 2.0
|
||||
let squareBounds = CGRect(x: (bounds.width - maxSide) / 2.0, y: (bounds.width - maxSide) / 2.0, width: maxSide, height: maxSide)
|
||||
transition.animateView {
|
||||
backdropEffectView.frame = squareBounds
|
||||
|
||||
@ -701,8 +701,9 @@ public final class VoiceChatController: ViewController {
|
||||
fileprivate let actionButton: VoiceChatActionButton
|
||||
private let leftBorderNode: ASDisplayNode
|
||||
private let rightBorderNode: ASDisplayNode
|
||||
private let mainStageNode: VoiceChatMainStageNode
|
||||
private let mainStageContainerNode: ASDisplayNode
|
||||
private let mainStageBackgroundNode: ASDisplayNode
|
||||
private let mainStageNode: VoiceChatMainStageNode
|
||||
private let transitionContainerNode: ASDisplayNode
|
||||
|
||||
private var isScheduling = false
|
||||
@ -807,7 +808,7 @@ public final class VoiceChatController: ViewController {
|
||||
private var endpointToPeerId: [String: PeerId] = [:]
|
||||
private var peerIdToEndpoint: [PeerId: String] = [:]
|
||||
|
||||
private var currentDominantSpeaker: PeerId?
|
||||
private var currentDominantSpeaker: (PeerId, Double)?
|
||||
private var currentForcedSpeaker: PeerId?
|
||||
private var effectiveSpeaker: (PeerId, String?)?
|
||||
|
||||
@ -969,13 +970,18 @@ public final class VoiceChatController: ViewController {
|
||||
self.rightBorderNode.isUserInteractionEnabled = false
|
||||
self.rightBorderNode.clipsToBounds = false
|
||||
|
||||
self.mainStageNode = VoiceChatMainStageNode(context: self.context, call: self.call)
|
||||
|
||||
self.mainStageContainerNode = ASDisplayNode()
|
||||
self.mainStageContainerNode.clipsToBounds = true
|
||||
self.mainStageContainerNode.isUserInteractionEnabled = false
|
||||
self.mainStageContainerNode.isHidden = true
|
||||
|
||||
self.mainStageBackgroundNode = ASDisplayNode()
|
||||
// self.mainStageBackgroundNode.backgroundColor = .black
|
||||
self.mainStageBackgroundNode.alpha = 0.0
|
||||
self.mainStageBackgroundNode.isUserInteractionEnabled = false
|
||||
|
||||
self.mainStageNode = VoiceChatMainStageNode(context: self.context, call: self.call)
|
||||
|
||||
self.transitionContainerNode = ASDisplayNode()
|
||||
self.transitionContainerNode.clipsToBounds = true
|
||||
self.transitionContainerNode.isUserInteractionEnabled = false
|
||||
@ -1032,13 +1038,13 @@ public final class VoiceChatController: ViewController {
|
||||
}, switchToPeer: { [weak self] peerId, videoEndpointId, expand in
|
||||
if let strongSelf = self {
|
||||
if expand, let videoEndpointId = videoEndpointId {
|
||||
strongSelf.currentDominantSpeaker = peerId
|
||||
strongSelf.currentDominantSpeaker = (peerId, CACurrentMediaTime())
|
||||
strongSelf.effectiveSpeaker = (peerId, videoEndpointId)
|
||||
strongSelf.updateDisplayMode(.fullscreen(controlsHidden: false))
|
||||
} else {
|
||||
strongSelf.currentForcedSpeaker = nil
|
||||
if peerId != strongSelf.currentDominantSpeaker {
|
||||
strongSelf.currentDominantSpeaker = peerId
|
||||
if peerId != strongSelf.currentDominantSpeaker?.0 {
|
||||
strongSelf.currentDominantSpeaker = (peerId, CACurrentMediaTime())
|
||||
}
|
||||
strongSelf.updateMainVideo(waitForFullSize: false, updateMembers: true, force: true)
|
||||
}
|
||||
@ -1657,6 +1663,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.contentContainer.addSubnode(self.fullscreenListNode)
|
||||
self.addSubnode(self.transitionContainerNode)
|
||||
|
||||
self.mainStageContainerNode.addSubnode(self.mainStageBackgroundNode)
|
||||
self.mainStageContainerNode.addSubnode(self.mainStageNode)
|
||||
|
||||
self.updateDecorationsColors()
|
||||
@ -1801,7 +1808,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
if maxLevelWithVideo == nil {
|
||||
if let peerId = strongSelf.currentDominantSpeaker {
|
||||
maxLevelWithVideo = (peerId, 0.0)
|
||||
maxLevelWithVideo = (peerId.0, 0.0)
|
||||
} else if strongSelf.peerIdToEndpoint.count > 0 {
|
||||
for entry in strongSelf.currentEntries {
|
||||
if case let .peer(peerEntry) = entry {
|
||||
@ -1816,7 +1823,10 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
if case .fullscreen = strongSelf.displayMode {
|
||||
if let (peerId, _) = maxLevelWithVideo {
|
||||
strongSelf.currentDominantSpeaker = peerId
|
||||
if let peer = strongSelf.currentDominantSpeaker, CACurrentMediaTime() - peer.1 < 5.0 {
|
||||
} else {
|
||||
strongSelf.currentDominantSpeaker = (peerId, CACurrentMediaTime())
|
||||
}
|
||||
strongSelf.updateMainVideo(waitForFullSize: false)
|
||||
}
|
||||
}
|
||||
@ -1962,7 +1972,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.mainStageNode.togglePin = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let peerId = strongSelf.currentForcedSpeaker {
|
||||
strongSelf.currentDominantSpeaker = peerId
|
||||
strongSelf.currentDominantSpeaker = (peerId, CACurrentMediaTime())
|
||||
strongSelf.currentForcedSpeaker = nil
|
||||
} else {
|
||||
strongSelf.currentForcedSpeaker = strongSelf.effectiveSpeaker?.0
|
||||
@ -3137,6 +3147,7 @@ public final class VoiceChatController: ViewController {
|
||||
let videoBottomEdgeY = self.isLandscape ? layout.size.height : layout.size.height - layout.intrinsicInsets.bottom - 84.0
|
||||
let videoFrame = CGRect(x: 0.0, y: videoTopEdgeY, width: isLandscape ? layout.size.width - layout.safeInsets.right - 84.0 : layout.size.width, height: videoBottomEdgeY - videoTopEdgeY)
|
||||
transition.updateFrame(node: self.mainStageContainerNode, frame: videoFrame)
|
||||
transition.updateFrame(node: self.mainStageBackgroundNode, frame: CGRect(origin: CGPoint(), size: videoFrame.size))
|
||||
if !self.mainStageNode.animating {
|
||||
transition.updateFrame(node: self.mainStageNode, frame: CGRect(origin: CGPoint(), size: videoFrame.size))
|
||||
}
|
||||
@ -4331,26 +4342,12 @@ public final class VoiceChatController: ViewController {
|
||||
if !validSources.contains(videoEndpointId) {
|
||||
self.videoNodes[videoEndpointId] = nil
|
||||
self.readyVideoDisposables.set(nil, forKey: videoEndpointId)
|
||||
|
||||
// loop: for j in 0 ..< self.currentFullscreenEntries.count {
|
||||
// let fullscreenEntry = self.currentFullscreenEntries[j]
|
||||
// switch fullscreenEntry {
|
||||
// case let .peer(peerEntry):
|
||||
// if peerEntry.effectiveVideoEndpointId == videoEndpointId {
|
||||
// let presentationData = self.presentationData.withUpdated(theme: self.darkTheme)
|
||||
// self.fullscreenListNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [ListViewUpdateItem(index: j, previousIndex: j, item: fullscreenEntry.item(context: self.context, presentationData: presentationData, interaction: self.itemInteraction!), directionHint: nil)], options: [.Synchronous], updateOpaqueState: nil)
|
||||
// break loop
|
||||
// }
|
||||
// default:
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMainVideo(waitForFullSize: Bool, updateMembers: Bool = true, force: Bool = false, completion: (() -> Void)? = nil) {
|
||||
let effectiveMainSpeaker = self.currentForcedSpeaker ?? self.currentDominantSpeaker
|
||||
let effectiveMainSpeaker = self.currentForcedSpeaker ?? self.currentDominantSpeaker?.0
|
||||
guard effectiveMainSpeaker != self.effectiveSpeaker?.0 || force else {
|
||||
return
|
||||
}
|
||||
@ -4473,42 +4470,46 @@ public final class VoiceChatController: ViewController {
|
||||
if self.isScheduled && translation < 0.0 {
|
||||
return
|
||||
}
|
||||
|
||||
if case let .modal(isExpanded, previousIsFilled) = self.effectiveDisplayMode {
|
||||
var topInset: CGFloat = 0.0
|
||||
if let (currentTopInset, currentPanOffset) = self.panGestureArguments {
|
||||
topInset = currentTopInset
|
||||
|
||||
if case let .known(value) = contentOffset, value <= 0.5 {
|
||||
|
||||
switch self.effectiveDisplayMode {
|
||||
case let .modal(isExpanded, previousIsFilled):
|
||||
var topInset: CGFloat = 0.0
|
||||
if let (currentTopInset, currentPanOffset) = self.panGestureArguments {
|
||||
topInset = currentTopInset
|
||||
|
||||
if case let .known(value) = contentOffset, value <= 0.5 {
|
||||
} else {
|
||||
translation = currentPanOffset
|
||||
if self.isExpanded {
|
||||
recognizer.setTranslation(CGPoint(), in: self.contentContainer.view)
|
||||
}
|
||||
}
|
||||
|
||||
self.panGestureArguments = (currentTopInset, translation)
|
||||
}
|
||||
|
||||
let currentOffset = topInset + translation
|
||||
|
||||
var isFilled = previousIsFilled
|
||||
if currentOffset < 20.0 {
|
||||
isFilled = true
|
||||
} else if currentOffset > 40.0 {
|
||||
isFilled = false
|
||||
}
|
||||
if isFilled != previousIsFilled {
|
||||
self.displayMode = .modal(isExpanded: isExpanded, isFilled: isFilled)
|
||||
self.updateDecorationsColors()
|
||||
}
|
||||
|
||||
if self.isExpanded {
|
||||
} else {
|
||||
translation = currentPanOffset
|
||||
if self.isExpanded {
|
||||
recognizer.setTranslation(CGPoint(), in: self.contentContainer.view)
|
||||
if currentOffset > 0.0 {
|
||||
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||
}
|
||||
}
|
||||
case let .fullscreen(controlsHidden):
|
||||
break
|
||||
|
||||
self.panGestureArguments = (currentTopInset, translation)
|
||||
}
|
||||
|
||||
let currentOffset = topInset + translation
|
||||
|
||||
var isFilled = previousIsFilled
|
||||
if currentOffset < 20.0 {
|
||||
isFilled = true
|
||||
} else if currentOffset > 40.0 {
|
||||
isFilled = false
|
||||
}
|
||||
if isFilled != previousIsFilled {
|
||||
self.displayMode = .modal(isExpanded: isExpanded, isFilled: isFilled)
|
||||
self.updateDecorationsColors()
|
||||
}
|
||||
|
||||
if self.isExpanded {
|
||||
} else {
|
||||
if currentOffset > 0.0 {
|
||||
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
@ -5051,6 +5052,9 @@ public final class VoiceChatController: ViewController {
|
||||
let effectiveSpeakerPeerId = self.effectiveSpeaker?.0
|
||||
if let effectiveSpeakerPeerId = effectiveSpeakerPeerId, let otherItemNode = verticalItemNodes[effectiveSpeakerPeerId] {
|
||||
self.mainStageNode.animateTransitionIn(from: otherItemNode, transition: transition)
|
||||
|
||||
self.mainStageBackgroundNode.alpha = 1.0
|
||||
self.mainStageBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
self.fullscreenListNode.forEachItemNode { itemNode in
|
||||
@ -5125,6 +5129,8 @@ public final class VoiceChatController: ViewController {
|
||||
self?.mainStageContainerNode.isHidden = true
|
||||
})
|
||||
|
||||
self.mainStageBackgroundNode.alpha = 0.0
|
||||
self.mainStageBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
|
||||
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: transition)
|
||||
|
||||
@ -253,12 +253,15 @@ final class VoiceChatMainStageNode: ASDisplayNode {
|
||||
transition.updateFrame(view: snapshotView, frame: infoFrame)
|
||||
}
|
||||
|
||||
sourceNode.alpha = 0.0
|
||||
|
||||
self.animatingIn = true
|
||||
let startLocalFrame = sourceNode.view.convert(sourceNode.bounds, to: self.supernode?.view)
|
||||
self.update(size: startLocalFrame.size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, force: true, transition: .immediate)
|
||||
self.frame = startLocalFrame
|
||||
self.update(size: targetFrame.size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, force: true, transition: transition)
|
||||
transition.updateFrame(node: self, frame: targetFrame, completion: { [weak self] _ in
|
||||
sourceNode.alpha = 1.0
|
||||
self?.animatingIn = false
|
||||
})
|
||||
}
|
||||
@ -300,12 +303,15 @@ final class VoiceChatMainStageNode: ASDisplayNode {
|
||||
transition.updateFrame(view: snapshotView, frame: CGRect(origin: CGPoint(), size: targetFrame.size))
|
||||
}
|
||||
|
||||
targetNode.alpha = 0.0
|
||||
|
||||
self.update(size: targetFrame.size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, force: true, transition: transition)
|
||||
transition.updateFrame(node: self, frame: targetFrame, completion: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
completion()
|
||||
|
||||
infoView?.removeFromSuperview()
|
||||
targetNode.alpha = 1.0
|
||||
strongSelf.animatingOut = false
|
||||
strongSelf.frame = initialFrame
|
||||
strongSelf.update(size: initialFrame.size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, transition: .immediate)
|
||||
|
||||
@ -0,0 +1,184 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import AppBundle
|
||||
import ContextUI
|
||||
import TelegramStringFormatting
|
||||
|
||||
final class VoiceChatShareScreenContextItem: ContextMenuCustomItem {
|
||||
fileprivate let text: String
|
||||
fileprivate let icon: (PresentationTheme) -> UIImage?
|
||||
fileprivate let action: (ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void
|
||||
|
||||
init(text: String, icon: @escaping (PresentationTheme) -> UIImage?, action: @escaping (ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void) {
|
||||
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: VoiceChatRecordingIconNode
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
|
||||
private var pointerInteraction: PointerInteraction?
|
||||
|
||||
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)
|
||||
let subtextFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
|
||||
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
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
self.buttonNode.isAccessibilityElement = true
|
||||
self.buttonNode.accessibilityLabel = presentationData.strings.VoiceChat_StopRecording
|
||||
|
||||
self.iconNode = VoiceChatRecordingIconNode(hasBackground: true)
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.highlightedBackgroundNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.buttonNode.highligthedChanged = { [weak self] highligted in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if highligted {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
strongSelf.highlightedBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.timer?.invalidate()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.pointerInteraction = PointerInteraction(node: self.buttonNode, style: .hover, willEnter: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.75
|
||||
}
|
||||
}, willExit: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private var validLayout: CGSize?
|
||||
func updateLayout(constrainedWidth: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let verticalInset: CGFloat = 12.0
|
||||
|
||||
let iconSide = 16.0 + (1.0 + UIScreenPixel) * 2.0
|
||||
let iconSize: CGSize = CGSize(width: iconSide, height: iconSide)
|
||||
|
||||
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
|
||||
let hadLayout = self.validLayout != nil
|
||||
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)))
|
||||
transition.updateFrame(node: self.buttonNode, 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)
|
||||
let subtextFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
self.performAction()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user