diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index 72292568a5..d52e425248 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -2958,7 +2958,7 @@ extension Customoji { if let cg = (image as UIImage).cgImage { return cg } var rendered: CGImage? - let work = { rendered = renderCGImage(image as! UIImage) } + let work = { rendered = renderCGImage(image) } if Thread.isMainThread { work() } else { diff --git a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift index 1ada4ace6f..19df7c4f3d 100644 --- a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift +++ b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift @@ -580,7 +580,7 @@ final class AvatarEditorScreenComponent: Component { if installed { return .complete() } else { - return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) + return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) |> map { _ in return Void() } } case .fetching: break @@ -718,7 +718,7 @@ final class AvatarEditorScreenComponent: Component { if installed { return .complete() } else { - return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) + return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) |> map { _ in return Void() } } case .fetching: break diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index e161ea06b6..8fb75e72b5 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -329,7 +329,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ messageText = updatingMedia.text } - if !messageText.isEmpty || isUnsupportedMedia || isStoryWithText { + if !messageText.isEmpty || message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) || isUnsupportedMedia || isStoryWithText { if !skipText { if case .group = item.content, !isFile { messageWithCaptionToAdd = (message, itemAttributes) @@ -2262,7 +2262,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI bubbleReactions = ReactionsMessageAttribute(canViewList: false, isTags: false, reactions: [], recentPeers: [], topPeers: []) } if !bubbleReactions.reactions.isEmpty && !item.presentationData.isPreview { - bottomNodeMergeStatus = .Both + bottomNodeMergeStatus = .Right } var currentCredibilityIcon: (EmojiStatusComponent.Content, UIColor?)? @@ -6259,7 +6259,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI if strongSelf.backgroundNode.supernode != nil, let backgroundView = strongSelf.backgroundNode.view.snapshotContentTree(unhide: true) { let backgroundContainer = UIView() - let backdropView = strongSelf.backgroundWallpaperNode.view.snapshotContentTree(unhide: true) + let backdropView = strongSelf.backgroundWallpaperNode.view.snapshotContentTree(unhide: true, keepPortals: true) if let backdropView = backdropView { let backdropFrame = strongSelf.backgroundWallpaperNode.layer.convert(strongSelf.backgroundWallpaperNode.bounds, to: strongSelf.backgroundNode.layer) backdropView.frame = backdropFrame diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift index 379bac9399..8d8872ccd6 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift @@ -698,6 +698,15 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { } } + var hasDraft = false + if item.message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) { + hasDraft = true + } + var hadDraft = false + if let previousItem, previousItem.message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) { + hadDraft = true + } + let textInsets = UIEdgeInsets(top: 2.0, left: 2.0, bottom: 5.0, right: 2.0) let (textLayout, textApply) = textLayout(InteractiveTextNodeLayoutArguments( attributedString: attributedText, @@ -712,18 +721,10 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { displayContentsUnderSpoilers: displayContentsUnderSpoilers.value, customTruncationToken: customTruncationToken, expandedBlocks: expandedBlockIds, - computeCharacterRects: true + computeCharacterRects: true, + minWidth: (attributedText.string.isEmpty && hasDraft) ? 40.0 : nil )) - var hasDraft = false - if item.message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) { - hasDraft = true - } - var hadDraft = false - if let previousItem, previousItem.message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) { - hadDraft = true - } - var maxGlyphCount = currentMaxGlyphCount if maxGlyphCount == nil && (hasDraft || hadDraft) { maxGlyphCount = previousGlyphCount diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift index 0a453ead98..1569743128 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift @@ -173,6 +173,10 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag public var customSendColor: UIColor? public var isSendDisabled: Bool = false + private var slowmodeProgressTimestamp: (duration: Int32, timestamp: Int32)? + private var slowmodeProgressTimer: Foundation.Timer? + private var slowmodeProgressLayer: SimpleShapeLayer? + public init(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) { self.context = context self.presentationContext = presentationContext @@ -255,6 +259,10 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag } } + deinit { + self.slowmodeProgressTimer?.invalidate() + } + override public func didLoad() { super.didLoad() @@ -357,8 +365,72 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(), size: size)) self.micButton.layoutItems() + var sendSlowmodeTimerTimestamp: (duration: Int32, timestamp: Int32)? + if let slowmodeState = interfaceState.slowmodeState { + switch slowmodeState.variant { + case .pendingMessages: + break + case let .timestamp(timeoutTimestamp): + sendSlowmodeTimerTimestamp = (slowmodeState.timeout, timeoutTimestamp) + } + } + let sendButtonBackgroundFrame = CGRect(origin: CGPoint(), size: innerSize).insetBy(dx: 3.0, dy: 3.0) - transition.updateFrame(view: self.sendButtonBackgroundView, frame: sendButtonBackgroundFrame) + + let slowmodeInset: CGFloat = 4.0 + + self.slowmodeProgressTimestamp = sendSlowmodeTimerTimestamp + if sendSlowmodeTimerTimestamp != nil { + let slowmodeProgressLayer: SimpleShapeLayer + var slowmodeProgressTransition = transition + if let current = self.slowmodeProgressLayer { + slowmodeProgressLayer = current + } else { + slowmodeProgressTransition = .immediate + slowmodeProgressLayer = SimpleShapeLayer() + self.slowmodeProgressLayer = slowmodeProgressLayer + self.sendButtonBackgroundView.layer.superlayer?.insertSublayer(slowmodeProgressLayer, below: self.sendButtonBackgroundView.layer) + + slowmodeProgressLayer.fillColor = nil + slowmodeProgressLayer.lineWidth = 2.0 + slowmodeProgressLayer.lineCap = .round + } + + slowmodeProgressLayer.strokeColor = (self.customSendColor ?? interfaceState.theme.chat.inputPanel.panelControlAccentColor).cgColor + + if slowmodeProgressLayer.bounds.size != sendButtonBackgroundFrame.size { + let pathFrame = CGRect(origin: CGPoint(), size: sendButtonBackgroundFrame.size).insetBy(dx: 2.0, dy: 2.0) + slowmodeProgressLayer.path = UIBezierPath(roundedRect: pathFrame, cornerRadius: pathFrame.height * 0.5).cgPath + } + slowmodeProgressTransition.updateFrame(layer: slowmodeProgressLayer, frame: sendButtonBackgroundFrame) + + if self.slowmodeProgressTimer == nil { + self.slowmodeProgressTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true, block: { [weak self] _ in + guard let self else { + return + } + self.updateSlowmodeProgress() + }) + } + self.updateSlowmodeProgress() + } else { + if let slowmodeProgressLayer = self.slowmodeProgressLayer { + self.slowmodeProgressLayer = nil + slowmodeProgressLayer.removeFromSuperlayer() + } + if let slowmodeProgressTimer = self.slowmodeProgressTimer { + self.slowmodeProgressTimer = nil + slowmodeProgressTimer.invalidate() + } + } + + ComponentTransition(transition).setPosition(view: self.sendButtonBackgroundView, position: sendButtonBackgroundFrame.center) + ComponentTransition(transition).setBounds(view: self.sendButtonBackgroundView, bounds: CGRect(origin: CGPoint(), size: sendButtonBackgroundFrame.size)) + var sendButtonBackgroundScale: CGFloat = 1.0 + if sendSlowmodeTimerTimestamp != nil, let image = self.sendButtonBackgroundView.image { + sendButtonBackgroundScale = (image.size.height - slowmodeInset * 2.0) / image.size.height + } + transition.updateTransformScale(layer: self.sendButtonBackgroundView.layer, scale: sendButtonBackgroundScale) if self.isSendDisabled { transition.updateTintColor(view: self.sendButtonBackgroundView, color: interfaceState.theme.chat.inputPanel.panelControlAccentColor.withMultiplied(hue: 1.0, saturation: 0.0, brightness: 0.5).withMultipliedAlpha(0.25)) @@ -441,6 +513,18 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag return innerSize } + private func updateSlowmodeProgress() { + guard let slowmodeProgressLayer = self.slowmodeProgressLayer, let slowmodeProgressTimestamp = self.slowmodeProgressTimestamp else { + return + } + + let timestamp = Date().timeIntervalSince1970 + let timeout = max(0.0, Double(slowmodeProgressTimestamp.timestamp) - timestamp) + let fraction = timeout / max(0.1, Double(slowmodeProgressTimestamp.duration)) + + slowmodeProgressLayer.strokeEnd = CGFloat(fraction) + } + public func updateAccessibility() { self.accessibilityTraits = .button if !self.micButton.alpha.isZero { diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index a40c0fe8dd..4a74571527 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -2308,6 +2308,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } } } + sendActionButtonsSize = self.sendActionButtons.updateLayout(size: CGSize(width: 40.0, height: minimalHeight), isMediaInputExpanded: isMediaInputExpanded, showTitle: showTitle, currentMessageEffectId: presentationInterfaceState.interfaceState.sendMessageEffect, transition: transition, interfaceState: presentationInterfaceState) mediaActionButtonsSize = self.mediaActionButtons.updateLayout(size: CGSize(width: 40.0, height: minimalHeight), isMediaInputExpanded: isMediaInputExpanded, showTitle: false, currentMessageEffectId: presentationInterfaceState.interfaceState.sendMessageEffect, transition: transition, interfaceState: presentationInterfaceState) } @@ -5600,6 +5601,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } public func frameForInputActionButton() -> CGRect? { + if !self.sendActionButtons.alpha.isZero && self.sendActionButtons.frame.minX < self.bounds.width { + return self.sendActionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: -3.0, dy: 0.0) + } if !self.mediaActionButtons.alpha.isZero && self.mediaActionButtons.frame.minX < self.bounds.width { return self.mediaActionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: -3.0, dy: 0.0) } diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 92c25d9349..5f4d8181d2 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -1371,7 +1371,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { if installed { return .complete() } else { - return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) + return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) |> map { _ in return Void() } } case .fetching: break diff --git a/submodules/TelegramUI/Components/ComposePollScreen/Sources/StickerAttachmentScreen.swift b/submodules/TelegramUI/Components/ComposePollScreen/Sources/StickerAttachmentScreen.swift index 25408482d8..7ea3af3a22 100644 --- a/submodules/TelegramUI/Components/ComposePollScreen/Sources/StickerAttachmentScreen.swift +++ b/submodules/TelegramUI/Components/ComposePollScreen/Sources/StickerAttachmentScreen.swift @@ -309,7 +309,7 @@ final class StickerAttachmentScreenComponent: Component { if installed { return .complete() } else { - return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) + return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) |> map { _ in return Void() } } case .fetching: break @@ -719,7 +719,7 @@ final class StickerAttachmentScreenComponent: Component { if installed { return .complete() } else { - return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) + return context.engine.stickers.addStickerPackInteractively(info: info._parse(), items: items) |> map { _ in return Void() } } case .fetching: break diff --git a/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextControllerExtractedPresentationNode.swift b/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextControllerExtractedPresentationNode.swift index 546500c6f4..d65a39fad8 100644 --- a/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextControllerExtractedPresentationNode.swift +++ b/submodules/TelegramUI/Components/ContextControllerImpl/Sources/ContextControllerExtractedPresentationNode.swift @@ -134,17 +134,18 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo private final class ItemContentNode: ASDisplayNode { let offsetContainerNode: ASDisplayNode var containingItem: ContextControllerTakeViewInfo.ContainingItem - + var animateClippingFromContentAreaInScreenSpace: CGRect? var storedGlobalFrame: CGRect? var storedGlobalBoundsFrame: CGRect? - + var presentationScale: CGFloat = 1.0 + init(containingItem: ContextControllerTakeViewInfo.ContainingItem) { self.offsetContainerNode = ASDisplayNode() self.containingItem = containingItem - + super.init() - + self.addSubnode(self.offsetContainerNode) } @@ -633,6 +634,21 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo } let contentNodeValue = ItemContentNode(containingItem: takeInfo.containingItem) contentNodeValue.animateClippingFromContentAreaInScreenSpace = takeInfo.contentAreaInScreenSpace + + // Mirror any ancestor scale on the source (e.g. a sheet's container transform) onto the offset + // container so the extracted contents render at the same visual size as in-place — without this + // they pop to 1:1 when reparented into the unscaled overlay window. + let sourceView = takeInfo.containingItem.view + let modeledWidth = sourceView.bounds.width + if modeledWidth > 0.001 { + let visualWidth = sourceView.convert(sourceView.bounds, to: nil).width + let detectedScale = visualWidth / modeledWidth + if abs(detectedScale - 1.0) > 0.001 { + contentNodeValue.presentationScale = detectedScale + contentNodeValue.offsetContainerNode.layer.transform = CATransform3DMakeScale(detectedScale, detectedScale, 1.0) + } + } + self.scrollNode.insertSubnode(contentNodeValue, aboveSubnode: self.actionsContainerNode) self.itemContentNode = contentNodeValue itemContentNode = contentNodeValue @@ -1165,6 +1181,13 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo if let contentNode = itemContentNode { var contentFrame = CGRect(origin: CGPoint(x: contentParentGlobalFrame.minX + contentRect.minX - contentNode.containingItem.contentRect.minX, y: contentRect.minY - contentNode.containingItem.contentRect.minY + contentVerticalOffset + additionalVisibleOffsetY), size: contentNode.containingItem.view.bounds.size) + // contentRect.minY was derived from storedGlobalFrame.maxY (visual) minus contentRect.height (modeled); + // when an ancestor scale is in effect those don't cancel cleanly, leaving a (1 - scale) * (cy + ch) + // residue that pulls the content upward. Add it back so the content lands at the source's visual Y. + if contentNode.presentationScale != 1.0 { + let cr = contentNode.containingItem.contentRect + contentFrame.origin.y += (1.0 - contentNode.presentationScale) * (cr.minY + cr.height) + } if case let .extracted(extracted) = self.source { if extracted.adjustContentHorizontally { contentFrame.origin.x = combinedActionsFrame.minX @@ -1542,6 +1565,12 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo switch result { case .default, .custom: animationInContentYDistance = currentContentLocalFrame.minY - currentContentScreenFrame.minY + // Same modeled-vs-visual mismatch as the static contentFrame compensation: contentRect.minY (used by + // currentContentLocalFrame) was derived with modeled height while the source-side reference uses visual + // height, leaving a `ch * (1 - scale)` residue that animates the content downward on dismiss. + if let contentNode = itemContentNode, contentNode.presentationScale != 1.0 { + animationInContentYDistance += contentNode.containingItem.contentRect.height * (1.0 - contentNode.presentationScale) + } case .dismissWithoutContent: animationInContentYDistance = 0.0 if let contentNode = itemContentNode { diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift index 82475ee6f2..01a8977756 100644 --- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift +++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift @@ -339,24 +339,24 @@ public final class EmojiStatusSelectionController: ViewController { self.componentHost = ComponentView() self.componentShadowLayer = SimpleLayer() - self.componentShadowLayer.shadowOpacity = 0.12 + self.componentShadowLayer.shadowOpacity = 0.35 self.componentShadowLayer.shadowColor = UIColor(white: 0.0, alpha: 1.0).cgColor - self.componentShadowLayer.shadowOffset = CGSize(width: 0.0, height: 2.0) - self.componentShadowLayer.shadowRadius = 16.0 + self.componentShadowLayer.shadowOffset = CGSize(width: 0.0, height: 10.0) + self.componentShadowLayer.shadowRadius = 30.0 self.cloudLayer0 = SimpleLayer() self.cloudShadowLayer0 = SimpleLayer() - self.cloudShadowLayer0.shadowOpacity = 0.12 - self.cloudShadowLayer0.shadowColor = UIColor(white: 0.0, alpha: 1.0).cgColor - self.cloudShadowLayer0.shadowOffset = CGSize(width: 0.0, height: 2.0) - self.cloudShadowLayer0.shadowRadius = 16.0 + self.cloudShadowLayer0.shadowOpacity = self.componentShadowLayer.shadowOpacity + self.cloudShadowLayer0.shadowColor = self.componentShadowLayer.shadowColor + self.cloudShadowLayer0.shadowOffset = self.componentShadowLayer.shadowOffset + self.cloudShadowLayer0.shadowRadius = self.componentShadowLayer.shadowRadius self.cloudLayer1 = SimpleLayer() self.cloudShadowLayer1 = SimpleLayer() - self.cloudShadowLayer1.shadowOpacity = 0.12 - self.cloudShadowLayer1.shadowColor = UIColor(white: 0.0, alpha: 1.0).cgColor - self.cloudShadowLayer1.shadowOffset = CGSize(width: 0.0, height: 2.0) - self.cloudShadowLayer1.shadowRadius = 16.0 + self.cloudShadowLayer1.shadowOpacity = self.componentShadowLayer.shadowOpacity + self.cloudShadowLayer1.shadowColor = self.componentShadowLayer.shadowColor + self.cloudShadowLayer1.shadowOffset = self.componentShadowLayer.shadowOffset + self.cloudShadowLayer1.shadowRadius = self.componentShadowLayer.shadowRadius super.init() @@ -973,16 +973,12 @@ public final class EmojiStatusSelectionController: ViewController { if self.presentationData.theme.overallDarkAppearance { listBackgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor separatorColor = self.presentationData.theme.list.itemBlocksSeparatorColor - self.componentShadowLayer.shadowOpacity = 0.32 - self.cloudShadowLayer0.shadowOpacity = 0.32 - self.cloudShadowLayer1.shadowOpacity = 0.32 } else { listBackgroundColor = self.presentationData.theme.list.plainBackgroundColor separatorColor = self.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5) - self.componentShadowLayer.shadowOpacity = 0.12 - self.cloudShadowLayer0.shadowOpacity = 0.12 - self.cloudShadowLayer1.shadowOpacity = 0.12 } + self.cloudShadowLayer0.shadowOpacity = self.componentShadowLayer.shadowOpacity + self.cloudShadowLayer1.shadowOpacity = self.componentShadowLayer.shadowOpacity self.cloudLayer0.backgroundColor = listBackgroundColor.cgColor self.cloudLayer1.backgroundColor = listBackgroundColor.cgColor diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift index df4dd2efbb..c7b08f6fa2 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift @@ -1241,6 +1241,9 @@ public extension EmojiPagerContentComponent { tintMode: tintMode ) case let .text(text): + if !areUnicodeEmojiEnabled { + continue + } resultItem = EmojiPagerContentComponent.Item( animationData: nil, content: .staticEmoji(text), diff --git a/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift b/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift index d5378abeb1..77c53244df 100644 --- a/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift +++ b/submodules/TelegramUI/Components/InteractiveTextComponent/Sources/InteractiveTextComponent.swift @@ -298,6 +298,7 @@ public final class InteractiveTextNodeLayoutArguments { public let customTruncationToken: ((UIFont, Bool) -> NSAttributedString?)? public let expandedBlocks: Set public let computeCharacterRects: Bool + public let minWidth: CGFloat? public init( attributedString: NSAttributedString?, @@ -318,7 +319,8 @@ public final class InteractiveTextNodeLayoutArguments { displayContentsUnderSpoilers: Bool = false, customTruncationToken: ((UIFont, Bool) -> NSAttributedString?)? = nil, expandedBlocks: Set = Set(), - computeCharacterRects: Bool = false + computeCharacterRects: Bool = false, + minWidth: CGFloat? = nil ) { self.attributedString = attributedString self.backgroundColor = backgroundColor @@ -339,6 +341,7 @@ public final class InteractiveTextNodeLayoutArguments { self.customTruncationToken = customTruncationToken self.expandedBlocks = expandedBlocks self.computeCharacterRects = computeCharacterRects + self.minWidth = minWidth } public func withAttributedString(_ attributedString: NSAttributedString?) -> InteractiveTextNodeLayoutArguments { @@ -361,7 +364,8 @@ public final class InteractiveTextNodeLayoutArguments { displayContentsUnderSpoilers: self.displayContentsUnderSpoilers, customTruncationToken: self.customTruncationToken, expandedBlocks: self.expandedBlocks, - computeCharacterRects: self.computeCharacterRects + computeCharacterRects: self.computeCharacterRects, + minWidth: self.minWidth ) } } @@ -424,6 +428,7 @@ public final class InteractiveTextNodeLayout: NSObject { fileprivate let textStroke: (UIColor, CGFloat)? public let displayContentsUnderSpoilers: Bool fileprivate let expandedBlocks: Set + public let minWidth: CGFloat? fileprivate init( attributedString: NSAttributedString?, @@ -447,7 +452,8 @@ public final class InteractiveTextNodeLayout: NSObject { textShadowBlur: CGFloat?, textStroke: (UIColor, CGFloat)?, displayContentsUnderSpoilers: Bool, - expandedBlocks: Set + expandedBlocks: Set, + minWidth: CGFloat? ) { self.attributedString = attributedString self.maximumNumberOfLines = maximumNumberOfLines @@ -471,6 +477,7 @@ public final class InteractiveTextNodeLayout: NSObject { self.textStroke = textStroke self.displayContentsUnderSpoilers = displayContentsUnderSpoilers self.expandedBlocks = expandedBlocks + self.minWidth = minWidth } func withUpdatedDisplayContentsUnderSpoilers(_ displayContentsUnderSpoilers: Bool) -> InteractiveTextNodeLayout { @@ -496,7 +503,8 @@ public final class InteractiveTextNodeLayout: NSObject { textShadowBlur: self.textShadowBlur, textStroke: self.textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, - expandedBlocks: self.expandedBlocks + expandedBlocks: self.expandedBlocks, + minWidth: self.minWidth ) } @@ -1102,6 +1110,12 @@ public final class InteractiveTextNodeLayout: NSObject { } height += self.insets.top + self.insets.bottom + 2.0 + + if let minWidth = self.minWidth { + width = max(width, minWidth) + trailingLineWidth = max(trailingLineWidth, minWidth) + } + return TextNodeLayout.LayoutInfo( size: CGSize(width: width, height: ceil(height)), trailingLineWidth: trailingLineWidth @@ -1474,7 +1488,8 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn displayContentsUnderSpoilers: Bool, customTruncationToken: ((UIFont, Bool) -> NSAttributedString?)?, expandedBlocks: Set, - computeCharacterRects: Bool = false + computeCharacterRects: Bool = false, + minWidth: CGFloat? ) -> InteractiveTextNodeLayout { let blockQuoteLeftInset: CGFloat = 9.0 let blockQuoteRightInset: CGFloat = 0.0 @@ -2046,6 +2061,10 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn size.width += insets.left + insets.right size.height += insets.top + insets.bottom + if let minWidth { + size.width = max(size.width, minWidth) + } + return InteractiveTextNodeLayout( attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, @@ -2068,16 +2087,17 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn textShadowBlur: textShadowBlur, textStroke: textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, - expandedBlocks: expandedBlocks + expandedBlocks: expandedBlocks, + minWidth: minWidth ) } - static func calculateLayout(attributedString: NSAttributedString?, minimumNumberOfLines: Int, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?, textShadowBlur: CGFloat?, textStroke: (UIColor, CGFloat)?, displayContentsUnderSpoilers: Bool, customTruncationToken: ((UIFont, Bool) -> NSAttributedString?)?, expandedBlocks: Set, computeCharacterRects: Bool = false) -> InteractiveTextNodeLayout { + static func calculateLayout(attributedString: NSAttributedString?, minimumNumberOfLines: Int, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?, textShadowBlur: CGFloat?, textStroke: (UIColor, CGFloat)?, displayContentsUnderSpoilers: Bool, customTruncationToken: ((UIFont, Bool) -> NSAttributedString?)?, expandedBlocks: Set, computeCharacterRects: Bool = false, minWidth: CGFloat? = nil) -> InteractiveTextNodeLayout { guard let attributedString else { - return InteractiveTextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, segments: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textShadowBlur: textShadowBlur, textStroke: textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, expandedBlocks: expandedBlocks) + return InteractiveTextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, segments: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textShadowBlur: textShadowBlur, textStroke: textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, expandedBlocks: expandedBlocks, minWidth: minWidth) } - return calculateLayoutV2(attributedString: attributedString, minimumNumberOfLines: minimumNumberOfLines, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, backgroundColor: backgroundColor, constrainedSize: constrainedSize, alignment: alignment, verticalAlignment: verticalAlignment, lineSpacingFactor: lineSpacingFactor, cutout: cutout, insets: insets, lineColor: lineColor, textShadowColor: textShadowColor, textShadowBlur: textShadowBlur, textStroke: textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, customTruncationToken: customTruncationToken, expandedBlocks: expandedBlocks, computeCharacterRects: computeCharacterRects) + return calculateLayoutV2(attributedString: attributedString, minimumNumberOfLines: minimumNumberOfLines, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, backgroundColor: backgroundColor, constrainedSize: constrainedSize, alignment: alignment, verticalAlignment: verticalAlignment, lineSpacingFactor: lineSpacingFactor, cutout: cutout, insets: insets, lineColor: lineColor, textShadowColor: textShadowColor, textShadowBlur: textShadowBlur, textStroke: textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, customTruncationToken: customTruncationToken, expandedBlocks: expandedBlocks, computeCharacterRects: computeCharacterRects, minWidth: minWidth) } private func updateContentItems(arguments: ApplyArguments) { @@ -2222,7 +2242,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn return { arguments in var layout: InteractiveTextNodeLayout - if let existingLayout = existingLayout, existingLayout.constrainedSize == arguments.constrainedSize && existingLayout.maximumNumberOfLines == arguments.maximumNumberOfLines && existingLayout.truncationType == arguments.truncationType && existingLayout.cutout == arguments.cutout && existingLayout.explicitAlignment == arguments.alignment && existingLayout.lineSpacing.isEqual(to: arguments.lineSpacing) && existingLayout.expandedBlocks == arguments.expandedBlocks { + if let existingLayout = existingLayout, existingLayout.constrainedSize == arguments.constrainedSize && existingLayout.maximumNumberOfLines == arguments.maximumNumberOfLines && existingLayout.truncationType == arguments.truncationType && existingLayout.cutout == arguments.cutout && existingLayout.explicitAlignment == arguments.alignment && existingLayout.lineSpacing.isEqual(to: arguments.lineSpacing) && existingLayout.expandedBlocks == arguments.expandedBlocks && existingLayout.minWidth == arguments.minWidth { let stringMatch: Bool var colorMatch: Bool = true @@ -2250,10 +2270,10 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn layout = layout.withUpdatedDisplayContentsUnderSpoilers(arguments.displayContentsUnderSpoilers) } } else { - layout = InteractiveTextNode.calculateLayout(attributedString: arguments.attributedString, minimumNumberOfLines: arguments.minimumNumberOfLines, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, verticalAlignment: arguments.verticalAlignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor, textShadowBlur: arguments.textShadowBlur, textStroke: arguments.textStroke, displayContentsUnderSpoilers: arguments.displayContentsUnderSpoilers, customTruncationToken: arguments.customTruncationToken, expandedBlocks: arguments.expandedBlocks, computeCharacterRects: arguments.computeCharacterRects) + layout = InteractiveTextNode.calculateLayout(attributedString: arguments.attributedString, minimumNumberOfLines: arguments.minimumNumberOfLines, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, verticalAlignment: arguments.verticalAlignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor, textShadowBlur: arguments.textShadowBlur, textStroke: arguments.textStroke, displayContentsUnderSpoilers: arguments.displayContentsUnderSpoilers, customTruncationToken: arguments.customTruncationToken, expandedBlocks: arguments.expandedBlocks, computeCharacterRects: arguments.computeCharacterRects, minWidth: arguments.minWidth) } } else { - layout = InteractiveTextNode.calculateLayout(attributedString: arguments.attributedString, minimumNumberOfLines: arguments.minimumNumberOfLines, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, verticalAlignment: arguments.verticalAlignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor, textShadowBlur: arguments.textShadowBlur, textStroke: arguments.textStroke, displayContentsUnderSpoilers: arguments.displayContentsUnderSpoilers, customTruncationToken: arguments.customTruncationToken, expandedBlocks: arguments.expandedBlocks, computeCharacterRects: arguments.computeCharacterRects) + layout = InteractiveTextNode.calculateLayout(attributedString: arguments.attributedString, minimumNumberOfLines: arguments.minimumNumberOfLines, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, verticalAlignment: arguments.verticalAlignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor, textShadowBlur: arguments.textShadowBlur, textStroke: arguments.textStroke, displayContentsUnderSpoilers: arguments.displayContentsUnderSpoilers, customTruncationToken: arguments.customTruncationToken, expandedBlocks: arguments.expandedBlocks, computeCharacterRects: arguments.computeCharacterRects, minWidth: arguments.minWidth) } let node = maybeNode ?? InteractiveTextNode() diff --git a/submodules/TelegramUI/Components/NavigationBarImpl/Sources/NavigationBarImpl.swift b/submodules/TelegramUI/Components/NavigationBarImpl/Sources/NavigationBarImpl.swift index 6d0a5d7c57..9d217ebf3f 100644 --- a/submodules/TelegramUI/Components/NavigationBarImpl/Sources/NavigationBarImpl.swift +++ b/submodules/TelegramUI/Components/NavigationBarImpl/Sources/NavigationBarImpl.swift @@ -1073,17 +1073,18 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar { } if self.titleNode.view.superview != nil { - let titleSize = self.titleNode.updateLayout(CGSize(width: max(1.0, size.width - max(leftTitleInset, rightTitleInset) * 2.0), height: nominalHeight)) + var transition = transition + if self.titleNode.frame.width.isZero { + transition = .immediate + } + self.titleNode.alpha = 1.0 - do { - var transition = transition - if self.titleNode.frame.width.isZero { - transition = .immediate - } - self.titleNode.alpha = 1.0 - - let titleOffset: CGFloat = 0.0 - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + titleOffset + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize)) + let titleSize = self.titleNode.updateLayout(CGSize(width: max(1.0, size.width - leftTitleInset - rightTitleInset), height: nominalHeight)) + + if titleSize.width <= size.width - max(leftTitleInset, rightTitleInset) * 2.0 { + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize)) + } else { + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftTitleInset + floor((size.width - leftTitleInset - rightTitleInset - titleSize.width) / 2.0), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize)) } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift index fdc26f3789..e767664904 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift @@ -1350,7 +1350,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { let textSideInset: CGFloat = 36.0 let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height - let titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isPremium || isVerified || isFake ? 20.0 : 0.0), height: .greatestFiniteMagnitude) + var titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isPremium || isVerified || isFake ? 20.0 : 0.0), height: .greatestFiniteMagnitude) + if self.navigationButtonContainer.rightButtonNodes.count > 1 { + titleConstrainedSize.width -= 60.0 + } let titleNodeLayout = self.titleNode.updateLayout(text: titleStringText, states: [ TitleNodeStateRegular: MultiScaleTextState(attributes: titleAttributes, constrainedSize: titleConstrainedSize), diff --git a/submodules/TelegramUI/Components/TextProcessingScreen/Sources/TextProcessingStyleSelectionComponent.swift b/submodules/TelegramUI/Components/TextProcessingScreen/Sources/TextProcessingStyleSelectionComponent.swift index be385042ec..d7529e9a3b 100644 --- a/submodules/TelegramUI/Components/TextProcessingScreen/Sources/TextProcessingStyleSelectionComponent.swift +++ b/submodules/TelegramUI/Components/TextProcessingScreen/Sources/TextProcessingStyleSelectionComponent.swift @@ -470,7 +470,8 @@ private final class ItemComponent: Component { guard let component = self.component else { return } - let containerFrame = CGRect(origin: CGPoint(x: floor((size.width - measuredSize.width) * 0.5), y: floor((measuredSize.height - size.height) * 0.5)), size: measuredSize) + + let containerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - measuredSize.width) * 0.5), y: floor((measuredSize.height - size.height) * 0.5)), size: measuredSize) let contentRect = CGRect(origin: CGPoint(x: 0.0, y: -5.0 - 4.0), size: CGSize(width: size.width + 0.0, height: size.height + 5.0 + 3.0 + 6.0)) transition.setFrame(view: self.backgroundContainer, frame: contentRect) self.backgroundContainer.update(size: contentRect.size, isDark: component.theme.overallDarkAppearance, transition: transition) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 5b62ef7ea5..6032f669d1 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -8740,6 +8740,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {} ) { + var animateTransition = true + if let validLayout = self.chatDisplayNode.validLayout?.0 { + if validLayout.metrics.widthClass != .compact { + animateTransition = false + } + } + self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: self.context, account: self.context.account, signals: signals!, originalMediaReference: originalMediaReference) |> deliverOnMainQueue).startStrict(next: { [weak self] items in guard let strongSelf = self else { @@ -8766,6 +8773,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if shouldDivert { skipAddingTransitions = true } + if !animateTransition { + skipAddingTransitions = true + } for item in items { var message = item.message diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 4f1e87ba3f..68f52b510e 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -4058,8 +4058,8 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { func frameForInputActionButton() -> CGRect? { if let textInputPanelNode = self.textInputPanelNode, self.inputPanelNode === textInputPanelNode { - return textInputPanelNode.frameForInputActionButton().flatMap { - return $0.offsetBy(dx: textInputPanelNode.frame.minX, dy: textInputPanelNode.frame.minY) + return textInputPanelNode.frameForInputActionButton().flatMap { rect in + return self.view.convert(rect, from: textInputPanelNode.view) } } return nil diff --git a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift index 4c254eeabc..76fcf7bc4b 100644 --- a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift @@ -18,6 +18,9 @@ import ChatControllerInteraction import ChatContextResultPeekContent import ChatInputContextPanelNode import BatchVideoRendering +import GlassBackgroundComponent +import ComponentFlow +import ComponentDisplayAdapters private struct ChatContextResultStableId: Hashable { let result: ChatContextResult @@ -82,6 +85,9 @@ private func preparedTransition(from fromEntries: [HorizontalListContextResultsC } final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode { + private let backgroundContainerView: GlassBackgroundContainerView + private let backgroundView: GlassBackgroundView + private let listClippingView: UIView private let listView: ListView private var currentExternalResults: ChatContextResultCollection? private var currentProcessedResults: ChatContextResultCollection? @@ -95,9 +101,14 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont private let batchVideoContext: QueueLocalObject override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, chatPresentationContext: ChatPresentationContext) { + self.backgroundContainerView = GlassBackgroundContainerView() + self.backgroundView = GlassBackgroundView() + self.backgroundContainerView.contentView.addSubview(self.backgroundView) + self.listClippingView = UIView() + self.listClippingView.clipsToBounds = true + self.listView = ListViewImpl() - self.listView.isOpaque = true - self.listView.backgroundColor = theme.list.plainBackgroundColor + self.listView.isOpaque = false self.listView.transform = CATransform3DMakeRotation(-CGFloat(CGFloat.pi / 2.0), 0.0, 0.0, 1.0) self.listView.isHidden = true self.listView.accessibilityPageScrolledString = { row, count in @@ -111,9 +122,12 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont super.init(context: context, theme: theme, strings: strings, fontSize: fontSize, chatPresentationContext: chatPresentationContext) self.isOpaque = false - self.clipsToBounds = true + self.clipsToBounds = false + self.layer.allowsGroupOpacity = true - self.addSubnode(self.listView) + self.view.addSubview(self.backgroundContainerView) + self.listClippingView.addSubview(self.listView.view) + self.backgroundView.contentView.addSubview(self.listClippingView) self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in if let strongSelf = self, let state = opaqueTransactionState as? HorizontalListContextResultsOpaqueState { @@ -361,12 +375,26 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) { let listHeight: CGFloat = 105.0 + let sideInset: CGFloat = 8.0 + let innerInset: CGFloat = 4.0 + let cornerRadius: CGFloat = 8.0 + let innerRadius: CGFloat = cornerRadius - innerInset - self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: listHeight, height: size.width) + let listFrame = CGRect(x: sideInset, y: size.height - bottomInset - 8.0 - listHeight, width: size.width - sideInset * 2.0, height: listHeight) + let transformedListFrame = CGSize(width: listFrame.height, height: listFrame.width).centered(in: listFrame) + self.listView.bounds = CGRect(origin: CGPoint(), size: transformedListFrame.size) + transition.updatePosition(node: self.listView, position: CGRect(origin: CGPoint(x: -innerInset, y: -innerInset), size: listFrame.size).center) - //transition.updateFrame(node: self.listView, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)) + transition.updateFrame(view: self.listClippingView, frame: CGRect(origin: CGPoint(), size: listFrame.size).insetBy(dx: innerInset, dy: innerInset)) + self.listClippingView.layer.cornerRadius = innerRadius - transition.updatePosition(node: self.listView, position: CGPoint(x: size.width / 2.0, y: size.height - bottomInset - 8.0 - listHeight / 2.0)) + let backgroundContainerInset: CGFloat = 32.0 + let backgroundContainerFrame = listFrame.insetBy(dx: -backgroundContainerInset, dy: -backgroundContainerInset) + transition.updateFrame(view: self.backgroundContainerView, frame: backgroundContainerFrame) + self.backgroundContainerView.update(size: backgroundContainerFrame.size, isDark: interfaceState.theme.overallDarkAppearance, transition: ComponentTransition(transition)) + + transition.updateFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: listFrame.size).offsetBy(dx: backgroundContainerInset, dy: backgroundContainerInset)) + self.backgroundView.update(size: listFrame.size, cornerRadius: cornerRadius, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel), transition: ComponentTransition(transition)) var insets = UIEdgeInsets() insets.top = leftInset @@ -391,22 +419,18 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont } override func animateOut(completion: @escaping () -> Void) { - /*let position = self.listView.layer.position - self.listView.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + self.listView.bounds.size.width), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in - completion() - })*/ - self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in + ComponentTransition.easeInOut(duration: 0.3).setAlpha(view: self.backgroundContainerView, alpha: 0.01, completion: { _ in completion() }) } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - let listViewBounds = self.listView.bounds - let listViewPosition = self.listView.position - let listViewFrame = CGRect(origin: CGPoint(x: listViewPosition.x - listViewBounds.height / 2.0, y: listViewPosition.y - listViewBounds.width / 2.0), size: CGSize(width: listViewBounds.height, height: listViewBounds.width)) - if !listViewFrame.contains(point) { + guard let result = super.hitTest(point, with: event) else { return nil } - return super.hitTest(point, with: event) + if result === self.view { + return nil + } + return result } } diff --git a/third-party/td/build-td-bazel.sh b/third-party/td/build-td-bazel.sh index a977bbb10d..6ccc056e74 100755 --- a/third-party/td/build-td-bazel.sh +++ b/third-party/td/build-td-bazel.sh @@ -29,15 +29,16 @@ cd .. if [ "$ARCH" = "arm64" ]; then IOS_PLATFORMDIR="$(xcode-select -p)/Platforms/iPhoneOS.platform" IOS_SYSROOT=($IOS_PLATFORMDIR/Developer/SDKs/iPhoneOS*.sdk) - export CFLAGS="-arch arm64 --target=arm64-apple-ios13.0 -miphoneos-version-min=13.0" + export CFLAGS="-arch arm64 --target=arm64-apple-ios13.0 -miphoneos-version-min=13.0 -w" elif [ "$ARCH" = "sim_arm64" ]; then IOS_PLATFORMDIR="$(xcode-select -p)/Platforms/iPhoneSimulator.platform" IOS_SYSROOT=($IOS_PLATFORMDIR/Developer/SDKs/iPhoneSimulator*.sdk) - export CFLAGS="-arch arm64 --target=arm64-apple-ios13.0-simulator -miphonesimulator-version-min=13.0" + export CFLAGS="-arch arm64 --target=arm64-apple-ios13.0-simulator -miphonesimulator-version-min=13.0 -w" else echo "Unsupported architecture $ARCH" exit 1 fi +export CXXFLAGS="$CFLAGS" # Common build steps mkdir build