mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Post-release bug fixes
This commit is contained in:
parent
6739a4a620
commit
a453f2d86e
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
||||
|
||||
include Utils.makefile
|
||||
|
||||
APP_VERSION="6.0"
|
||||
APP_VERSION="6.0.1"
|
||||
CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
|
||||
CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)
|
||||
|
||||
|
@ -5,7 +5,7 @@ set -e
|
||||
BUILD_TELEGRAM_VERSION="1"
|
||||
|
||||
MACOS_VERSION="10.15"
|
||||
XCODE_VERSION="11.4"
|
||||
XCODE_VERSION="11.2"
|
||||
GUEST_SHELL="bash"
|
||||
|
||||
VM_BASE_NAME="macos$(echo $MACOS_VERSION | sed -e 's/\.'/_/g)_Xcode$(echo $XCODE_VERSION | sed -e 's/\.'/_/g)"
|
||||
|
@ -30,9 +30,16 @@ private class AnimatedStickerNodeDisplayEvents: ASDisplayNode {
|
||||
override func didExitHierarchy() {
|
||||
super.didExitHierarchy()
|
||||
|
||||
if self.value {
|
||||
self.value = false
|
||||
self.updated?(false)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !strongSelf.isInHierarchy {
|
||||
if strongSelf.value {
|
||||
strongSelf.value = false
|
||||
strongSelf.updated?(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ private final class ItemNode: ASDisplayNode {
|
||||
width = badgeBackgroundFrame.maxX
|
||||
}
|
||||
|
||||
return (width, shortTitleSize.width - self.shortTitleNode.insets.left - self.shortTitleNode.insets.right + 5.0)
|
||||
return (width, shortTitleSize.width - self.shortTitleNode.insets.left - self.shortTitleNode.insets.right)
|
||||
}
|
||||
|
||||
func updateArea(size: CGSize, sideInset: CGFloat, useShortTitle: Bool, transition: ContainedViewLayoutTransition) {
|
||||
|
@ -715,7 +715,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} else {
|
||||
isRemovedFromTotalUnreadCount = isRemovedFromTotalUnreadCountValue
|
||||
}
|
||||
peerPresence = peerPresenceValue
|
||||
peerPresence = (peerPresenceValue as? TelegramUserPresence).flatMap { presence -> TelegramUserPresence in
|
||||
TelegramUserPresence(status: presence.status, lastActivity: 0)
|
||||
}
|
||||
embeddedState = embeddedStateValue
|
||||
summaryInfo = summaryInfoValue
|
||||
inputActivities = inputActivitiesValue
|
||||
@ -1180,7 +1182,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
switch item.content {
|
||||
case let .peer(_, renderedPeer, _, _, presence, _ ,_ ,_, _, _, displayAsMessage, _):
|
||||
if !displayAsMessage, let peer = renderedPeer.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
||||
let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: timestamp)
|
||||
var updatedPresence = TelegramUserPresence(status: presence.status, lastActivity: 0)
|
||||
let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp)
|
||||
if case .online = relativeStatus {
|
||||
online = true
|
||||
}
|
||||
@ -1608,7 +1611,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: layoutOffset - separatorHeight - topNegativeInset), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height + separatorHeight + topNegativeInset))
|
||||
|
||||
if let peerPresence = peerPresence as? TelegramUserPresence {
|
||||
strongSelf.peerPresenceManager?.reset(presence: peerPresence)
|
||||
strongSelf.peerPresenceManager?.reset(presence: TelegramUserPresence(status: peerPresence.status, lastActivity: 0))
|
||||
}
|
||||
|
||||
strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
|
||||
@ -1739,7 +1742,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
transition.updateFrame(node: self.badgeNode, frame: updatedBadgeFrame)
|
||||
|
||||
var mentionBadgeFrame = self.mentionBadgeNode.frame
|
||||
if updatedBadgeFrame.width.isZero {
|
||||
if updatedBadgeFrame.width.isZero || self.badgeNode.isHidden {
|
||||
mentionBadgeFrame.origin.x = updatedBadgeFrame.minX - mentionBadgeFrame.width
|
||||
} else {
|
||||
mentionBadgeFrame.origin.x = updatedBadgeFrame.minX - 6.0 - mentionBadgeFrame.width
|
||||
|
@ -51,7 +51,7 @@ func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int
|
||||
|
||||
var result: [(ChatListFilter, Int, Bool)] = []
|
||||
|
||||
var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int, Bool, PeerGroupId?)] = [:]
|
||||
var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int, Bool, PeerGroupId?, Bool)] = [:]
|
||||
|
||||
var totalStates: [PeerGroupId: ChatListTotalUnreadState] = [:]
|
||||
for entry in unreadCounts.entries {
|
||||
@ -71,9 +71,9 @@ func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int
|
||||
}
|
||||
|
||||
if let notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings, case .muted = notificationSettings.muteState {
|
||||
peerTagAndCount[peerId] = (tag, peerCount, false, peerView.groupId)
|
||||
peerTagAndCount[peerId] = (tag, peerCount, false, peerView.groupId, true)
|
||||
} else {
|
||||
peerTagAndCount[peerId] = (tag, peerCount, true, peerView.groupId)
|
||||
peerTagAndCount[peerId] = (tag, peerCount, true, peerView.groupId, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,8 +147,15 @@ func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int
|
||||
}
|
||||
}
|
||||
for peerId in filter.data.includePeers.peers {
|
||||
if let (tag, peerCount, hasUnmuted, groupId) = peerTagAndCount[peerId] {
|
||||
if let groupId = groupId, !tags.contains(tag) {
|
||||
if let (tag, peerCount, hasUnmuted, groupIdValue, isMuted) = peerTagAndCount[peerId], peerCount != 0, let groupId = groupIdValue {
|
||||
var matches = true
|
||||
if tags.contains(tag) {
|
||||
if isMuted && filter.data.excludeMuted {
|
||||
} else {
|
||||
matches = false
|
||||
}
|
||||
}
|
||||
if matches {
|
||||
let matchesGroup: Bool
|
||||
switch groupId {
|
||||
case .root:
|
||||
@ -170,8 +177,16 @@ func chatListFilterItems(postbox: Postbox) -> Signal<(Int, [(ChatListFilter, Int
|
||||
}
|
||||
}
|
||||
for peerId in filter.data.excludePeers {
|
||||
if let (tag, peerCount, _, groupId) = peerTagAndCount[peerId] {
|
||||
if let groupId = groupId, tags.contains(tag) {
|
||||
if let (tag, peerCount, _, groupIdValue, isMuted) = peerTagAndCount[peerId], peerCount != 0, let groupId = groupIdValue {
|
||||
var matches = true
|
||||
if tags.contains(tag) {
|
||||
if isMuted && filter.data.excludeMuted {
|
||||
} else {
|
||||
matches = false
|
||||
}
|
||||
}
|
||||
|
||||
if matches {
|
||||
let matchesGroup: Bool
|
||||
switch groupId {
|
||||
case .root:
|
||||
|
@ -512,8 +512,8 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
self.hapticFeedback.impact()
|
||||
|
||||
switch self.source {
|
||||
case let .extracted(source):
|
||||
if let contentAreaInScreenSpace = self.contentAreaInScreenSpace, let maybeContentNode = self.contentContainerNode.contentNode, case let .extracted(_, keepInPlace) = maybeContentNode {
|
||||
case .extracted:
|
||||
if let contentAreaInScreenSpace = self.contentAreaInScreenSpace, let maybeContentNode = self.contentContainerNode.contentNode, case .extracted = maybeContentNode {
|
||||
var updatedContentAreaInScreenSpace = contentAreaInScreenSpace
|
||||
updatedContentAreaInScreenSpace.origin.x = 0.0
|
||||
updatedContentAreaInScreenSpace.size.width = self.bounds.width
|
||||
@ -553,7 +553,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
self.effectView.effect = makeCustomZoomBlurEffect()
|
||||
self.effectView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2 * animationDurationFactor)
|
||||
self.propertyAnimator = UIViewPropertyAnimator(duration: 0.2 * animationDurationFactor * UIView.animationDurationFactor(), curve: .easeInOut, animations: { [weak self] in
|
||||
self.propertyAnimator = UIViewPropertyAnimator(duration: 0.2 * animationDurationFactor * UIView.animationDurationFactor(), curve: .easeInOut, animations: {
|
||||
})
|
||||
}
|
||||
|
||||
@ -601,7 +601,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
|
||||
self.actionsContainerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y)
|
||||
let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y - contentParentNode.contentRect.minY)
|
||||
self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
contentParentNode.applyAbsoluteOffsetSpring?(-contentContainerOffset.y, springDuration, springDamping)
|
||||
}
|
||||
@ -619,8 +619,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
})
|
||||
|
||||
if let originalProjectedContentViewFrame = self.originalProjectedContentViewFrame {
|
||||
let actionsSideInset: CGFloat = (validLayout?.safeInsets.left ?? 0.0) + 11.0
|
||||
|
||||
let localSourceFrame = self.view.convert(CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalProjectedContentViewFrame.1.minY), size: CGSize(width: originalProjectedContentViewFrame.1.width, height: originalProjectedContentViewFrame.1.height)), to: self.scrollNode.view)
|
||||
|
||||
self.contentContainerNode.layer.animateSpring(from: min(localSourceFrame.width / self.contentContainerNode.frame.width, localSourceFrame.height / self.contentContainerNode.frame.height) as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: springDuration, initialVelocity: 0.0, damping: springDamping)
|
||||
@ -1121,13 +1119,13 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
let originalActionsY: CGFloat
|
||||
if keepInPlace {
|
||||
originalActionsY = originalProjectedContentViewFrame.1.minY - contentActionsSpacing - actionsSize.height
|
||||
preferredActionsX = originalProjectedContentViewFrame.1.maxX - actionsSize.width
|
||||
preferredActionsX = max(actionsSideInset, originalProjectedContentViewFrame.1.maxX - actionsSize.width)
|
||||
} else {
|
||||
originalActionsY = min(originalProjectedContentViewFrame.1.maxY + contentActionsSpacing, maximumActionsFrameOrigin)
|
||||
preferredActionsX = originalProjectedContentViewFrame.1.minX
|
||||
}
|
||||
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - actionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: actionsSize)
|
||||
var originalContentX: CGFloat = originalProjectedContentViewFrame.1.minX
|
||||
let originalContentX: CGFloat = originalProjectedContentViewFrame.1.minX
|
||||
let originalContentY: CGFloat
|
||||
if keepInPlace {
|
||||
originalContentY = originalProjectedContentViewFrame.1.minY
|
||||
@ -1152,15 +1150,26 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
}
|
||||
|
||||
var overflowOffset: CGFloat
|
||||
let contentContainerFrame: CGRect
|
||||
var contentContainerFrame: CGRect
|
||||
if keepInPlace {
|
||||
overflowOffset = min(0.0, originalActionsFrame.minY - contentTopInset)
|
||||
contentContainerFrame = originalContentFrame.offsetBy(dx: -contentParentNode.contentRect.minX, dy: -contentParentNode.contentRect.minY)
|
||||
if keepInPlace && !overflowOffset.isZero {
|
||||
let offsetDelta = contentParentNode.contentRect.height + 4.0
|
||||
overflowOffset += offsetDelta
|
||||
overflowOffset = min(0.0, overflowOffset)
|
||||
|
||||
originalActionsFrame.origin.x -= contentParentNode.contentRect.maxX - contentParentNode.contentRect.minX + 14.0
|
||||
originalActionsFrame.origin.x = max(actionsSideInset, originalActionsFrame.origin.x)
|
||||
//originalActionsFrame.origin.y += contentParentNode.contentRect.height
|
||||
if originalActionsFrame.minX < contentContainerFrame.minX {
|
||||
contentContainerFrame.origin.x = min(originalActionsFrame.maxX + 14.0, layout.size.width - actionsSideInset)
|
||||
}
|
||||
originalActionsFrame.origin.y += offsetDelta
|
||||
if originalActionsFrame.maxY < originalContentFrame.maxY {
|
||||
originalActionsFrame.origin.y += contentParentNode.contentRect.height
|
||||
originalActionsFrame.origin.y = min(originalActionsFrame.origin.y, layout.size.height - originalActionsFrame.height - actionsBottomInset)
|
||||
}
|
||||
contentHeight -= offsetDelta
|
||||
}
|
||||
} else {
|
||||
|
@ -56,8 +56,8 @@ public final class ContextControllerSourceNode: ASDisplayNode {
|
||||
targetContentRect = CGRect(origin: CGPoint(), size: targetNode.bounds.size)
|
||||
}
|
||||
|
||||
let scaleSide = max(targetContentRect.width, targetContentRect.height)
|
||||
let minScale: CGFloat = (scaleSide - 10.0) / scaleSide
|
||||
let scaleSide = targetContentRect.width
|
||||
let minScale: CGFloat = (scaleSide - 15.0) / scaleSide
|
||||
let currentScale = 1.0 * (1.0 - progress) + minScale * progress
|
||||
|
||||
let originalCenterOffsetX: CGFloat = targetNode.bounds.width / 2.0 - targetContentRect.midX
|
||||
@ -82,8 +82,6 @@ public final class ContextControllerSourceNode: ASDisplayNode {
|
||||
targetNode.layer.sublayerTransform = sublayerTransform
|
||||
|
||||
targetNode.layer.animate(from: NSValue(caTransform3D: previousTransform), to: NSValue(caTransform3D: sublayerTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.2)
|
||||
|
||||
//targetNode.layer.animateSpring(from: previousScale as NSNumber, to: currentScale as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5, delay: 0.0, initialVelocity: 0.0, damping: 90.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ private class TimerTargetWrapper: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
private let beginDelay: Double = 0.1
|
||||
private let beginDelay: Double = 0.12
|
||||
|
||||
private func cancelParentGestures(view: UIView) {
|
||||
if let gestureRecognizers = view.gestureRecognizers {
|
||||
@ -117,7 +117,7 @@ public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDeleg
|
||||
}
|
||||
strongSelf.isValidated = true
|
||||
if strongSelf.animator == nil {
|
||||
strongSelf.animator = DisplayLinkAnimator(duration: 0.3, from: 0.0, to: 1.0, update: { value in
|
||||
strongSelf.animator = DisplayLinkAnimator(duration: 0.2, from: 0.0, to: 1.0, update: { value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
|
||||
break
|
||||
case .ignore:
|
||||
return .fail
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip:
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults:
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ extension AnimatedStickerNode: GenericAnimatedStickerNode {
|
||||
|
||||
class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
private let contextSourceNode: ContextExtractedContentContainingNode
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
let imageNode: TransformImageNode
|
||||
private var animationNode: GenericAnimatedStickerNode?
|
||||
private var didSetUpAnimationNode = false
|
||||
@ -71,13 +72,54 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
|
||||
required init() {
|
||||
self.contextSourceNode = ContextExtractedContentContainingNode()
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
self.imageNode = TransformImageNode()
|
||||
self.dateAndStatusNode = ChatMessageDateAndStatusNode()
|
||||
|
||||
super.init(layerBacked: false)
|
||||
|
||||
self.containerNode.shouldBegin = { [weak self] location in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
if !strongSelf.imageNode.frame.contains(location) {
|
||||
return false
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .tap, location: location, recognizer: nil) {
|
||||
if case .action = action {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
return false
|
||||
case .openContextMenu:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture, location in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
break
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
item.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, strongSelf, subFrame, gesture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
self.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||
self.addSubnode(self.containerNode)
|
||||
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
|
||||
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
|
||||
}
|
||||
@ -113,8 +155,17 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
return
|
||||
}
|
||||
//strongSelf.reactionRecognizer?.cancel()
|
||||
if strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) {
|
||||
recognizer.cancel()
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) {
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case .openContextMenu:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
self.view.addGestureRecognizer(recognizer)
|
||||
@ -655,6 +706,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
if let strongSelf = self {
|
||||
strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature)
|
||||
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
|
||||
@ -677,6 +729,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
imageApply()
|
||||
|
||||
strongSelf.contextSourceNode.contentRect = strongSelf.imageNode.frame
|
||||
strongSelf.containerNode.targetNodeForActivationProgressContentRect = strongSelf.contextSourceNode.contentRect
|
||||
|
||||
if let updatedShareButtonNode = updatedShareButtonNode {
|
||||
if updatedShareButtonNode !== strongSelf.shareButtonNode {
|
||||
@ -855,48 +908,63 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
let _ = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil)
|
||||
if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) {
|
||||
if case .doubleTap = gesture {
|
||||
self.containerNode.cancelGesture()
|
||||
}
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
self.item?.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, self, subFrame, nil)
|
||||
}
|
||||
} else if case .tap = gesture {
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> Bool {
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> InternalBubbleTapAction? {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
|
||||
if let item = self.item, let author = item.content.firstMessage.author {
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
return .optionalAction({
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
}
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
return true
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) {
|
||||
@ -911,14 +979,15 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
if let botAddressName = botAddressName {
|
||||
item.controllerInteraction.updateInputState { textInputState in
|
||||
return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " "))
|
||||
}
|
||||
item.controllerInteraction.updateInputMode { _ in
|
||||
return .text
|
||||
}
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.updateInputState { textInputState in
|
||||
return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " "))
|
||||
}
|
||||
item.controllerInteraction.updateInputMode { _ in
|
||||
return .text
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -928,8 +997,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
if let item = self.item {
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
return true
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -937,9 +1007,13 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
|
||||
if let item = self.item, self.imageNode.frame.contains(location) {
|
||||
if let _ = self.telegramFile {
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
return .optionalAction({
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
})
|
||||
} else if let _ = self.telegramDice {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_Dice, self, self.imageNode.frame.offsetBy(dx: 0.0, dy: self.imageNode.frame.height / 3.0))
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_Dice, self, self.imageNode.frame.offsetBy(dx: 0.0, dy: self.imageNode.frame.height / 3.0))
|
||||
})
|
||||
} else if let _ = self.emojiFile {
|
||||
if let animationNode = self.animationNode as? AnimatedStickerNode {
|
||||
var startTime: Signal<Double, NoError>
|
||||
@ -955,39 +1029,38 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D]
|
||||
|
||||
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, beatingHearts.contains(firstScalar.value) {
|
||||
let _ = startTime.start(next: { [weak self] time in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let heartbeatHaptic: HeartbeatHaptic
|
||||
if let current = strongSelf.heartbeatHaptic {
|
||||
heartbeatHaptic = current
|
||||
} else {
|
||||
heartbeatHaptic = HeartbeatHaptic()
|
||||
heartbeatHaptic.enabled = true
|
||||
strongSelf.heartbeatHaptic = heartbeatHaptic
|
||||
}
|
||||
if !heartbeatHaptic.active {
|
||||
heartbeatHaptic.start(time: time)
|
||||
}
|
||||
return .optionalAction({
|
||||
let _ = startTime.start(next: { [weak self] time in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let heartbeatHaptic: HeartbeatHaptic
|
||||
if let current = strongSelf.heartbeatHaptic {
|
||||
heartbeatHaptic = current
|
||||
} else {
|
||||
heartbeatHaptic = HeartbeatHaptic()
|
||||
heartbeatHaptic.enabled = true
|
||||
strongSelf.heartbeatHaptic = heartbeatHaptic
|
||||
}
|
||||
if !heartbeatHaptic.active {
|
||||
heartbeatHaptic.start(time: time)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
return nil
|
||||
case .longTap, .doubleTap:
|
||||
if let item = self.item, self.imageNode.frame.contains(location) {
|
||||
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, recognizer)
|
||||
return false
|
||||
return .openContextMenu(tapMessage: item.message, selectAll: false, subFrame: self.imageNode.frame)
|
||||
}
|
||||
case .hold:
|
||||
break
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@objc func shareButtonPressed() {
|
||||
|
@ -84,6 +84,7 @@ enum ChatMessageBubbleContentTapAction {
|
||||
case tooltip(String, ASDisplayNode?, CGRect?)
|
||||
case bankCard(String)
|
||||
case ignore
|
||||
case openPollResults(Data)
|
||||
}
|
||||
|
||||
final class ChatMessageBubbleContentItem {
|
||||
|
@ -23,7 +23,7 @@ import GridMessageSelectionNode
|
||||
import AppBundle
|
||||
import Markdown
|
||||
|
||||
private enum InternalBubbleTapAction {
|
||||
enum InternalBubbleTapAction {
|
||||
case action(() -> Void)
|
||||
case optionalAction(() -> Void)
|
||||
case openContextMenu(tapMessage: Message, selectAll: Bool, subFrame: CGRect)
|
||||
@ -418,7 +418,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
break
|
||||
case .ignore:
|
||||
return .fail
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip:
|
||||
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults:
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
@ -443,7 +443,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case .openContextMenu:
|
||||
//recognizer.cancel()
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -2309,6 +2308,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) {
|
||||
if case .doubleTap = gesture {
|
||||
self.containerNode.cancelGesture()
|
||||
}
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
@ -2546,6 +2548,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
let _ = item.controllerInteraction.displayMessageTooltip(item.message.id, text, node, rect)
|
||||
})
|
||||
}
|
||||
case let .openPollResults(option):
|
||||
if let item = self.item {
|
||||
return .action({
|
||||
item.controllerInteraction.openMessagePollResults(item.message.id, option)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -2608,6 +2616,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
})
|
||||
case .tooltip:
|
||||
break
|
||||
case .openPollResults:
|
||||
break
|
||||
}
|
||||
}
|
||||
if let tapMessage = tapMessage {
|
||||
|
@ -21,6 +21,7 @@ private let inlineBotNameFont = nameFont
|
||||
|
||||
class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
private let contextSourceNode: ContextExtractedContentContainingNode
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
private let interactiveVideoNode: ChatMessageInteractiveInstantVideoNode
|
||||
|
||||
private var selectionNode: ChatMessageSelectionNode?
|
||||
@ -57,11 +58,52 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
|
||||
required init() {
|
||||
self.contextSourceNode = ContextExtractedContentContainingNode()
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
self.interactiveVideoNode = ChatMessageInteractiveInstantVideoNode()
|
||||
|
||||
super.init(layerBacked: false)
|
||||
|
||||
self.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.shouldBegin = { [weak self] location in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
if !strongSelf.interactiveVideoNode.frame.contains(location) {
|
||||
return false
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .tap, location: location, recognizer: nil) {
|
||||
if case .action = action {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
return false
|
||||
case .openContextMenu:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture, location in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
break
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
item.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, strongSelf, subFrame, gesture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.containerNode.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||
self.addSubnode(self.containerNode)
|
||||
self.contextSourceNode.contentNode.addSubnode(self.interactiveVideoNode)
|
||||
}
|
||||
|
||||
@ -219,7 +261,6 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
var updatedReplyBackgroundNode: ASImageNode?
|
||||
var replyBackgroundImage: UIImage?
|
||||
var replyMarkup: ReplyMarkupMessageAttribute?
|
||||
var inlineBotNameString: String?
|
||||
|
||||
let availableWidth = max(60.0, params.width - params.leftInset - params.rightInset - videoLayout.contentSize.width - 20.0 - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left)
|
||||
|
||||
@ -277,12 +318,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
|
||||
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
|
||||
replyInfoApply = makeReplyInfoLayout(item.presentationData, item.presentationData.strings, item.context, .standalone, replyMessage, CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||
} else if let attribute = attribute as? InlineBotMessageAttribute {
|
||||
if let peerId = attribute.peerId, let bot = item.message.peers[peerId] as? TelegramUser {
|
||||
inlineBotNameString = bot.username
|
||||
} else {
|
||||
inlineBotNameString = attribute.title
|
||||
}
|
||||
} else if let _ = attribute as? InlineBotMessageAttribute {
|
||||
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty {
|
||||
replyMarkup = attribute
|
||||
}
|
||||
@ -389,6 +425,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
|
||||
strongSelf.appliedItem = item
|
||||
@ -410,6 +447,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
videoApply(videoLayoutData, transition)
|
||||
|
||||
strongSelf.contextSourceNode.contentRect = videoFrame
|
||||
strongSelf.containerNode.targetNodeForActivationProgressContentRect = strongSelf.contextSourceNode.contentRect
|
||||
|
||||
if let updatedShareButtonNode = updatedShareButtonNode {
|
||||
if updatedShareButtonNode !== strongSelf.shareButtonNode {
|
||||
@ -580,80 +618,20 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
|
||||
if let item = self.item, let author = item.content.firstMessage.author {
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
}
|
||||
}
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) {
|
||||
if let item = self.item {
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(location) {
|
||||
if let item = self.item, let forwardInfo = item.message.forwardInfo {
|
||||
if let sourceMessageId = forwardInfo.sourceMessageId {
|
||||
if let channel = forwardInfo.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
|
||||
item.controllerInteraction.openPeer(id, .chat(textInputState: nil, subject: nil), nil)
|
||||
} else if let _ = forwardInfo.authorSignature {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
case .longTap, .doubleTap:
|
||||
if let item = self.item, let videoContentNode = self.interactiveVideoNode.videoContentNode(at: self.view.convert(location, to: self.interactiveVideoNode.view)) {
|
||||
item.controllerInteraction.openMessageContextMenu(item.message, false, videoContentNode, videoContentNode.bounds, nil)
|
||||
}
|
||||
case .hold:
|
||||
break
|
||||
if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) {
|
||||
if case .doubleTap = gesture {
|
||||
self.containerNode.cancelGesture()
|
||||
}
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
self.item?.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, self, subFrame, nil)
|
||||
}
|
||||
} else if case .tap = gesture {
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -661,6 +639,92 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
||||
}
|
||||
}
|
||||
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> InternalBubbleTapAction? {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
|
||||
if let item = self.item, let author = item.content.firstMessage.author {
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
}
|
||||
}
|
||||
|
||||
return .optionalAction({
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) {
|
||||
if let item = self.item {
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(location) {
|
||||
if let item = self.item, let forwardInfo = item.message.forwardInfo {
|
||||
if let sourceMessageId = forwardInfo.sourceMessageId {
|
||||
if let channel = forwardInfo.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||
})
|
||||
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.openPeer(id, .chat(textInputState: nil, subject: nil), nil)
|
||||
})
|
||||
} else if let _ = forwardInfo.authorSignature {
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case .longTap, .doubleTap:
|
||||
if let item = self.item, let videoContentNode = self.interactiveVideoNode.videoContentNode(at: self.view.convert(location, to: self.interactiveVideoNode.view)) {
|
||||
return .openContextMenu(tapMessage: item.message, selectAll: false, subFrame: videoContentNode.view.convert(videoContentNode.bounds, to: self.view))
|
||||
}
|
||||
case .hold:
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@objc func shareButtonPressed() {
|
||||
if let item = self.item {
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
|
@ -137,13 +137,10 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
let makeDateAndStatusLayout = self.dateAndStatusNode.asyncLayout()
|
||||
|
||||
return { item, width, displaySize, statusDisplayType, automaticDownload in
|
||||
var updatedTheme: ChatPresentationThemeData?
|
||||
|
||||
var secretVideoPlaceholderBackgroundImage: UIImage?
|
||||
var updatedInfoBackgroundImage: UIImage?
|
||||
var updatedMuteIconImage: UIImage?
|
||||
if item.presentationData.theme != currentItem?.presentationData.theme {
|
||||
updatedTheme = item.presentationData.theme
|
||||
updatedInfoBackgroundImage = PresentationResourcesChat.chatInstantMessageInfoBackgroundImage(item.presentationData.theme.theme)
|
||||
updatedMuteIconImage = PresentationResourcesChat.chatInstantMessageMuteIconImage(item.presentationData.theme.theme)
|
||||
}
|
||||
@ -382,13 +379,11 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
})
|
||||
}
|
||||
let mediaManager = item.context.sharedContext.mediaManager
|
||||
let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: ChatBubbleInstantVideoDecoration(diameter: displaySize.width + 2.0, backgroundImage: instantVideoBackgroundImage, tapped: {
|
||||
let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: ChatBubbleInstantVideoDecoration(inset: 2.0, backgroundImage: instantVideoBackgroundImage, tapped: {
|
||||
if let strongSelf = self {
|
||||
if let item = strongSelf.item {
|
||||
if strongSelf.infoBackgroundNode.alpha.isZero {
|
||||
item.context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice)
|
||||
} else {
|
||||
//let _ = item.controllerInteraction.openMessage(item.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -670,9 +665,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
case .longTap, .doubleTap:
|
||||
if let item = self.item, let videoNode = self.videoNode, videoNode.frame.contains(location) {
|
||||
item.controllerInteraction.openMessageContextMenu(item.message, false, self, videoNode.frame, nil)
|
||||
}
|
||||
break
|
||||
case .hold:
|
||||
break
|
||||
}
|
||||
|
@ -1489,8 +1489,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
if hasNonZeroVoters {
|
||||
if !isEstimating {
|
||||
item.controllerInteraction.openMessagePollResults(item.message.id, option.opaqueIdentifier)
|
||||
return .ignore
|
||||
return .openPollResults(option.opaqueIdentifier)
|
||||
}
|
||||
return .openMessage
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ private let inlineBotNameFont = nameFont
|
||||
|
||||
class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
private let contextSourceNode: ContextExtractedContentContainingNode
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
let imageNode: TransformImageNode
|
||||
var textNode: TextNode?
|
||||
|
||||
@ -45,13 +46,54 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
|
||||
required init() {
|
||||
self.contextSourceNode = ContextExtractedContentContainingNode()
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
self.imageNode = TransformImageNode()
|
||||
self.dateAndStatusNode = ChatMessageDateAndStatusNode()
|
||||
|
||||
super.init(layerBacked: false)
|
||||
|
||||
self.containerNode.shouldBegin = { [weak self] location in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
if !strongSelf.imageNode.frame.contains(location) {
|
||||
return false
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .tap, location: location, recognizer: nil) {
|
||||
if case .action = action {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
return false
|
||||
case .openContextMenu:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture, location in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: location, recognizer: nil) {
|
||||
switch action {
|
||||
case .action, .optionalAction:
|
||||
break
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
item.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, strongSelf, subFrame, gesture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
self.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.addSubnode(self.contextSourceNode)
|
||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||
self.addSubnode(self.containerNode)
|
||||
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
|
||||
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
|
||||
}
|
||||
@ -87,8 +129,17 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
return
|
||||
}
|
||||
//strongSelf.reactionRecognizer?.cancel()
|
||||
if strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) {
|
||||
recognizer.cancel()
|
||||
if let action = strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) {
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
recognizer.cancel()
|
||||
case .openContextMenu:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
self.view.addGestureRecognizer(recognizer)
|
||||
@ -409,9 +460,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
|
||||
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
|
||||
var transition: ContainedViewLayoutTransition = .immediate
|
||||
if case let .System(duration) = animation {
|
||||
transition = .animated(duration: duration, curve: .spring)
|
||||
@ -421,7 +469,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: updatedImageFrame)
|
||||
imageApply()
|
||||
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||
strongSelf.contextSourceNode.contentRect = strongSelf.imageNode.frame
|
||||
strongSelf.containerNode.targetNodeForActivationProgressContentRect = strongSelf.contextSourceNode.contentRect
|
||||
|
||||
dateAndStatusApply(false)
|
||||
|
||||
@ -589,48 +641,65 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
let _ = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil)
|
||||
if case .doubleTap = gesture {
|
||||
self.containerNode.cancelGesture()
|
||||
}
|
||||
if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) {
|
||||
if case .doubleTap = gesture {
|
||||
self.containerNode.cancelGesture()
|
||||
}
|
||||
switch action {
|
||||
case let .action(f):
|
||||
f()
|
||||
case let .optionalAction(f):
|
||||
f()
|
||||
case let .openContextMenu(tapMessage, selectAll, subFrame):
|
||||
self.item?.controllerInteraction.openMessageContextMenu(tapMessage, selectAll, self, subFrame, nil)
|
||||
}
|
||||
} else if case .tap = gesture {
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> Bool {
|
||||
private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> InternalBubbleTapAction? {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
|
||||
if let item = self.item, let author = item.content.firstMessage.author {
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
return .optionalAction({
|
||||
var openPeerId = item.effectiveAuthorId ?? author.id
|
||||
var navigate: ChatControllerInteractionNavigateToPeer
|
||||
|
||||
if item.content.firstMessage.id.peerId == item.context.account.peerId {
|
||||
navigate = .chat(textInputState: nil, subject: nil)
|
||||
} else {
|
||||
navigate = .info
|
||||
}
|
||||
}
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
return true
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(attribute.messageId))
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
|
||||
if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty {
|
||||
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
|
||||
} else {
|
||||
if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
|
||||
if case .member = channel.participationStatus {
|
||||
} else {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) {
|
||||
@ -645,14 +714,15 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
|
||||
if let botAddressName = botAddressName {
|
||||
item.controllerInteraction.updateInputState { textInputState in
|
||||
return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " "))
|
||||
}
|
||||
item.controllerInteraction.updateInputMode { _ in
|
||||
return .text
|
||||
}
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.updateInputState { textInputState in
|
||||
return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " "))
|
||||
}
|
||||
item.controllerInteraction.updateInputMode { _ in
|
||||
return .text
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -662,29 +732,29 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
if let item = self.item {
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
return true
|
||||
return .optionalAction({
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let item = self.item, self.imageNode.frame.contains(location) {
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
return true
|
||||
return .optionalAction({
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
})
|
||||
}
|
||||
|
||||
self.item?.controllerInteraction.clickThroughMessage()
|
||||
return nil
|
||||
case .longTap, .doubleTap:
|
||||
if let item = self.item, self.imageNode.frame.contains(location) {
|
||||
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, recognizer)
|
||||
return false
|
||||
return .openContextMenu(tapMessage: item.message, selectAll: false, subFrame: self.imageNode.frame)
|
||||
}
|
||||
case .hold:
|
||||
break
|
||||
}
|
||||
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@objc func shareButtonPressed() {
|
||||
|
@ -86,7 +86,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
|
||||
if case let .chatSelection(_, selectedChats, additionalCategories) = mode {
|
||||
placeholder = self.presentationData.strings.ChatListFilter_AddChatsTitle
|
||||
let chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: [], isSelecting: true, additionalCategories: additionalCategories?.categories ?? []), theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
let chatListNode = ChatListNode(context: context, groupId: .root, previewing: false, fillPreloadItems: false, mode: .peers(filter: [.excludeSecretChats], isSelecting: true, additionalCategories: additionalCategories?.categories ?? []), theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
chatListNode.updateState { state in
|
||||
var state = state
|
||||
for peerId in selectedChats {
|
||||
@ -171,12 +171,15 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
var searchGroups = false
|
||||
var searchChannels = false
|
||||
var globalSearch = false
|
||||
if case let .peerSelection(peerSelection) = mode {
|
||||
searchChatList = peerSelection.searchChatList
|
||||
searchGroups = peerSelection.searchGroups
|
||||
searchChannels = peerSelection.searchChannels
|
||||
switch mode {
|
||||
case .groupCreation, .channelCreation:
|
||||
globalSearch = true
|
||||
} else if case .chatSelection = mode {
|
||||
case let .peerSelection(searchChatListValue, searchGroupsValue, searchChannelsValue):
|
||||
searchChatList = searchChatListValue
|
||||
searchGroups = searchGroupsValue
|
||||
searchChannels = searchChannelsValue
|
||||
globalSearch = true
|
||||
case .chatSelection:
|
||||
searchChatList = true
|
||||
searchGroups = true
|
||||
searchChannels = true
|
||||
|
@ -61,6 +61,8 @@ func textStringForForwardedMessage(_ message: Message, strings: PresentationStri
|
||||
return ("", true)
|
||||
case _ as TelegramMediaPoll:
|
||||
return (strings.ForwardedPolls(1), true)
|
||||
case _ as TelegramMediaDice:
|
||||
return ("🎲", false)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -14,10 +14,12 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
private let tapped: () -> Void
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
private let inset: CGFloat
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
|
||||
public init(diameter: CGFloat, backgroundImage: UIImage?, tapped: @escaping () -> Void) {
|
||||
public init(inset: CGFloat, backgroundImage: UIImage?, tapped: @escaping () -> Void) {
|
||||
self.inset = inset
|
||||
self.tapped = tapped
|
||||
|
||||
let backgroundNode = ASImageNode()
|
||||
@ -29,7 +31,6 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
self.contentContainerNode.clipsToBounds = true
|
||||
self.contentContainerNode.cornerRadius = (diameter - 3.0) / 2.0
|
||||
|
||||
let foregroundNode = ASDisplayNode()
|
||||
self.foregroundNode = foregroundNode
|
||||
@ -65,6 +66,9 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
|
||||
let diameter = size.width + inset
|
||||
self.contentContainerNode.cornerRadius = (diameter - 3.0) / 2.0
|
||||
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
transition.updateFrame(node: backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user