mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-05-21 18:20:41 +00:00
Various improvements
This commit is contained in:
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+11
-10
@@ -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
|
||||
|
||||
+85
-1
@@ -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 {
|
||||
|
||||
+4
@@ -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)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+33
-4
@@ -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 {
|
||||
|
||||
+13
-17
@@ -339,24 +339,24 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
|
||||
self.componentHost = ComponentView<Empty>()
|
||||
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
|
||||
|
||||
@@ -1241,6 +1241,9 @@ public extension EmojiPagerContentComponent {
|
||||
tintMode: tintMode
|
||||
)
|
||||
case let .text(text):
|
||||
if !areUnicodeEmojiEnabled {
|
||||
continue
|
||||
}
|
||||
resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: nil,
|
||||
content: .staticEmoji(text),
|
||||
|
||||
+32
-12
@@ -298,6 +298,7 @@ public final class InteractiveTextNodeLayoutArguments {
|
||||
public let customTruncationToken: ((UIFont, Bool) -> NSAttributedString?)?
|
||||
public let expandedBlocks: Set<Int>
|
||||
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<Int> = 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<Int>
|
||||
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<Int>
|
||||
expandedBlocks: Set<Int>,
|
||||
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<Int>,
|
||||
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<Int>, 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<Int>, 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()
|
||||
|
||||
+11
-10
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -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),
|
||||
|
||||
+2
-1
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+41
-17
@@ -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<BatchVideoRenderingContext>
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+3
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user