Various fixes

This commit is contained in:
Ilya Laktyushin 2022-09-21 02:13:36 +03:00
parent 37002ab90d
commit 74af8d17e1
22 changed files with 381 additions and 49 deletions

View File

@ -3563,10 +3563,10 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
headerNode = current headerNode = current
switch transition.0 { switch transition.0 {
case .immediate: case .immediate:
headerNode.frame = headerFrame headerNode.updateFrame(headerFrame, within: self.visibleSize)
case let .animated(duration, curve): case let .animated(duration, curve):
let previousFrame = headerNode.frame let previousFrame = headerNode.frame
headerNode.frame = headerFrame headerNode.updateFrame(headerFrame, within: self.visibleSize)
var offset = headerFrame.minY - previousFrame.minY + transition.2 var offset = headerFrame.minY - previousFrame.minY + transition.2
if headerNode.isRotated { if headerNode.isRotated {
offset = -offset offset = -offset

View File

@ -141,4 +141,17 @@ open class ListViewItemHeaderNode: ASDisplayNode {
open func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) { open func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
} }
open func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
}
public func updateFrame(_ frame: CGRect, within containerSize: CGSize, updateFrame: Bool = true) {
if updateFrame {
self.frame = frame
}
if frame.maxY < 0.0 || frame.minY > containerSize.height {
} else {
self.updateAbsoluteRect(frame, within: containerSize)
}
}
} }

View File

@ -378,7 +378,7 @@ open class NavigationController: UINavigationController, ContainableController,
let belowKeyboardOverlayLayout = layout let belowKeyboardOverlayLayout = layout
var globalOverlayLayout = layout var globalOverlayLayout = layout
globalOverlayLayout.inputHeight = nil // globalOverlayLayout.inputHeight = nil
if let globalOverlayBelowKeyboardContainerParent = self.globalOverlayBelowKeyboardContainerParent { if let globalOverlayBelowKeyboardContainerParent = self.globalOverlayBelowKeyboardContainerParent {
if globalOverlayBelowKeyboardContainerParent.view.superview != self.displayNode.view { if globalOverlayBelowKeyboardContainerParent.view.superview != self.displayNode.view {

View File

@ -1014,11 +1014,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
func setupItem(_ item: UniversalVideoGalleryItem) { func setupItem(_ item: UniversalVideoGalleryItem) {
if self.item?.content.id != item.content.id { if self.item?.content.id != item.content.id {
func parseChapters(_ string: NSAttributedString) -> [MediaPlayerScrubbingChapter] { func parseChapters(_ string: NSAttributedString) -> [MediaPlayerScrubbingChapter] {
var existingTimecodes = Set<Double>()
var timecodeRanges: [(NSRange, TelegramTimecode)] = [] var timecodeRanges: [(NSRange, TelegramTimecode)] = []
var lineRanges: [NSRange] = [] var lineRanges: [NSRange] = []
string.enumerateAttributes(in: NSMakeRange(0, string.length), options: [], using: { attributes, range, _ in string.enumerateAttributes(in: NSMakeRange(0, string.length), options: [], using: { attributes, range, _ in
if let timecode = attributes[NSAttributedString.Key(TelegramTextAttributes.Timecode)] as? TelegramTimecode { if let timecode = attributes[NSAttributedString.Key(TelegramTextAttributes.Timecode)] as? TelegramTimecode {
timecodeRanges.append((range, timecode)) if !existingTimecodes.contains(timecode.time) {
timecodeRanges.append((range, timecode))
existingTimecodes.insert(timecode.time)
}
} }
}) })
(string.string as NSString).enumerateSubstrings(in: NSMakeRange(0, string.length), options: .byLines, using: { _, range, _, _ in (string.string as NSString).enumerateSubstrings(in: NSMakeRange(0, string.length), options: .byLines, using: { _, range, _, _ in
@ -1029,7 +1033,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
for (timecodeRange, timecode) in timecodeRanges { for (timecodeRange, timecode) in timecodeRanges {
inner: for lineRange in lineRanges { inner: for lineRange in lineRanges {
if lineRange.contains(timecodeRange.location) { if lineRange.contains(timecodeRange.location) {
if lineRange.length > timecodeRange.length { if lineRange.length > timecodeRange.length && timecodeRange.location < lineRange.location + 4 {
var title = ((string.string as NSString).substring(with: lineRange) as NSString).replacingCharacters(in: NSMakeRange(timecodeRange.location - lineRange.location, timecodeRange.length), with: "") var title = ((string.string as NSString).substring(with: lineRange) as NSString).replacingCharacters(in: NSMakeRange(timecodeRange.location - lineRange.location, timecodeRange.length), with: "")
title = title.trimmingCharacters(in: .whitespacesAndNewlines).trimmingCharacters(in: .punctuationCharacters) title = title.trimmingCharacters(in: .whitespacesAndNewlines).trimmingCharacters(in: .punctuationCharacters)
chapters.append(MediaPlayerScrubbingChapter(title: title, start: timecode.time)) chapters.append(MediaPlayerScrubbingChapter(title: title, start: timecode.time))
@ -1038,6 +1042,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
} }
} }
} }
return chapters return chapters
} }

View File

@ -877,7 +877,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
} }
let endPosition: CGFloat = max(startPosition, floor(backgroundFrame.width * CGFloat(chapter.start / duration)) - lineWidth / 2.0) let endPosition: CGFloat = max(startPosition, floor(backgroundFrame.width * CGFloat(chapter.start / duration)) - lineWidth / 2.0)
let width = endPosition - startPosition let width = endPosition - startPosition
if width < lineWidth * 2.0 { if width < lineWidth * 0.5 {
previousChapterNode.frame = CGRect() previousChapterNode.frame = CGRect()
continue continue
} }

View File

@ -602,7 +602,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
) )
let serviceMessage = PresentationThemeServiceMessage( let serviceMessage = PresentationThemeServiceMessage(
components: PresentationThemeServiceMessageColor(withDefaultWallpaper: PresentationThemeServiceMessageColorComponents(fill: UIColor(rgb: 0x1f1f1f, alpha: 1.0), primaryText: UIColor(rgb: 0xffffff), linkHighlight: UIColor(rgb: 0xffffff, alpha: 0.12), scam: UIColor(rgb: 0xeb5545), dateFillStatic: UIColor(rgb: 0x000000, alpha: 0.6), dateFillFloating: UIColor(rgb: 0x000000, alpha: 0.2)), withCustomWallpaper: PresentationThemeServiceMessageColorComponents(fill: UIColor(rgb: 0x1f1f1f, alpha: 1.0), primaryText: UIColor(rgb: 0xffffff), linkHighlight: UIColor(rgb: 0xffffff, alpha: 0.12), scam: UIColor(rgb: 0xeb5545), dateFillStatic: UIColor(rgb: 0x000000, alpha: 0.6), dateFillFloating: UIColor(rgb: 0x000000, alpha: 0.2))), components: PresentationThemeServiceMessageColor(withDefaultWallpaper: PresentationThemeServiceMessageColorComponents(fill: UIColor(rgb: 0x1f1f1f, alpha: 1.0), primaryText: UIColor(rgb: 0xffffff), linkHighlight: UIColor(rgb: 0xffffff, alpha: 0.12), scam: UIColor(rgb: 0xeb5545), dateFillStatic: UIColor(rgb: 0x000000, alpha: 0.2), dateFillFloating: UIColor(rgb: 0x000000, alpha: 0.2)), withCustomWallpaper: PresentationThemeServiceMessageColorComponents(fill: UIColor(rgb: 0x1f1f1f, alpha: 1.0), primaryText: UIColor(rgb: 0xffffff), linkHighlight: UIColor(rgb: 0xffffff, alpha: 0.12), scam: UIColor(rgb: 0xeb5545), dateFillStatic: UIColor(rgb: 0x000000, alpha: 0.2), dateFillFloating: UIColor(rgb: 0x000000, alpha: 0.2))),
unreadBarFillColor: UIColor(rgb: 0x1b1b1b), unreadBarFillColor: UIColor(rgb: 0x1b1b1b),
unreadBarStrokeColor: UIColor(rgb: 0x1b1b1b), unreadBarStrokeColor: UIColor(rgb: 0x1b1b1b),
unreadBarTextColor: UIColor(rgb: 0xffffff), unreadBarTextColor: UIColor(rgb: 0xffffff),

View File

@ -740,7 +740,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.emptyNode = emptyNode self.emptyNode = emptyNode
self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer) self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer)
if let (size, insets) = self.validEmptyNodeLayout { if let (size, insets) = self.validEmptyNodeLayout {
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: wasLoading && self.loadingNode.supernode != nil ? self.loadingNode : nil, size: size, insets: insets, transition: .immediate) emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: wasLoading && self.loadingNode.supernode != nil ? self.loadingNode : nil, backgroundNode: self.backgroundNode, size: size, insets: insets, transition: .immediate)
} }
if animated { if animated {
emptyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) emptyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
@ -1513,8 +1513,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
emptyNodeInsets.bottom += inputPanelsHeight emptyNodeInsets.bottom += inputPanelsHeight
self.validEmptyNodeLayout = (contentBounds.size, emptyNodeInsets) self.validEmptyNodeLayout = (contentBounds.size, emptyNodeInsets)
if let emptyNode = self.emptyNode, let emptyType = self.emptyType { if let emptyNode = self.emptyNode, let emptyType = self.emptyType {
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: nil, size: contentBounds.size, insets: emptyNodeInsets, transition: transition) emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: nil, backgroundNode: self.backgroundNode, size: contentBounds.size, insets: emptyNodeInsets, transition: transition)
transition.updateFrame(node: emptyNode, frame: contentBounds) transition.updateFrame(node: emptyNode, frame: contentBounds)
emptyNode.update(rect: contentBounds, within: contentBounds.size)
} }
var contentBottomInset: CGFloat = inputPanelsHeight + 4.0 var contentBottomInset: CGFloat = inputPanelsHeight + 4.0

View File

@ -11,6 +11,7 @@ import LocalizedPeerData
import TelegramStringFormatting import TelegramStringFormatting
import AccountContext import AccountContext
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import WallpaperBackgroundNode
private protocol ChatEmptyNodeContent { private protocol ChatEmptyNodeContent {
func updateLayout(interfaceState: ChatPresentationInterfaceState, size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize func updateLayout(interfaceState: ChatPresentationInterfaceState, size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize
@ -789,6 +790,11 @@ final class ChatEmptyNode: ASDisplayNode {
private let backgroundNode: NavigationBackgroundNode private let backgroundNode: NavigationBackgroundNode
private var wallpaperBackgroundNode: WallpaperBackgroundNode?
private var backgroundContent: WallpaperBubbleBackgroundNode?
private var absolutePosition: (CGRect, CGSize)?
private var currentTheme: PresentationTheme? private var currentTheme: PresentationTheme?
private var currentStrings: PresentationStrings? private var currentStrings: PresentationStrings?
@ -820,12 +826,21 @@ final class ChatEmptyNode: ASDisplayNode {
let targetFrame = self.backgroundNode.frame let targetFrame = self.backgroundNode.frame
let initialFrame = loadingNode.convert(loadingNode.progressFrame, to: self) let initialFrame = loadingNode.convert(loadingNode.progressFrame, to: self)
let transition = ContainedViewLayoutTransition.animated(duration: duration, curve: .easeInOut)
self.backgroundNode.layer.animateFrame(from: initialFrame, to: targetFrame, duration: duration) self.backgroundNode.layer.animateFrame(from: initialFrame, to: targetFrame, duration: duration)
self.backgroundNode.update(size: initialFrame.size, cornerRadius: initialFrame.size.width / 2.0, transition: .immediate) self.backgroundNode.update(size: initialFrame.size, cornerRadius: initialFrame.size.width / 2.0, transition: .immediate)
self.backgroundNode.update(size: targetFrame.size, cornerRadius: targetCornerRadius, transition: .animated(duration: duration, curve: .easeInOut)) self.backgroundNode.update(size: targetFrame.size, cornerRadius: targetCornerRadius, transition: transition)
if let backgroundContent = self.backgroundContent {
backgroundContent.layer.animateFrame(from: initialFrame, to: targetFrame, duration: duration)
backgroundContent.cornerRadius = initialFrame.size.width / 2.0
transition.updateCornerRadius(layer: backgroundContent.layer, cornerRadius: targetCornerRadius)
}
} }
func updateLayout(interfaceState: ChatPresentationInterfaceState, emptyType: ChatHistoryNodeLoadState.EmptyType, loadingNode: ChatLoadingNode?, size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) { func updateLayout(interfaceState: ChatPresentationInterfaceState, emptyType: ChatHistoryNodeLoadState.EmptyType, loadingNode: ChatLoadingNode?, backgroundNode: WallpaperBackgroundNode?, size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
self.wallpaperBackgroundNode = backgroundNode
if self.currentTheme !== interfaceState.theme || self.currentStrings !== interfaceState.strings { if self.currentTheme !== interfaceState.theme || self.currentStrings !== interfaceState.strings {
self.currentTheme = interfaceState.theme self.currentTheme = interfaceState.theme
self.currentStrings = interfaceState.strings self.currentStrings = interfaceState.strings
@ -833,6 +848,8 @@ final class ChatEmptyNode: ASDisplayNode {
self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), enableBlur: dateFillNeedsBlur(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), transition: .immediate) self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), enableBlur: dateFillNeedsBlur(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper), transition: .immediate)
} }
var isScheduledMessages = false var isScheduledMessages = false
if case .scheduledMessages = interfaceState.subject { if case .scheduledMessages = interfaceState.subject {
isScheduledMessages = true isScheduledMessages = true
@ -923,8 +940,45 @@ final class ChatEmptyNode: ASDisplayNode {
transition.updateFrame(node: self.backgroundNode, frame: contentFrame) transition.updateFrame(node: self.backgroundNode, frame: contentFrame)
self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(20.0, self.backgroundNode.bounds.height / 2.0), transition: transition) self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(20.0, self.backgroundNode.bounds.height / 2.0), transition: transition)
if backgroundNode?.hasExtraBubbleBackground() == true {
if self.backgroundContent == nil, let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContent.clipsToBounds = true
self.backgroundContent = backgroundContent
self.insertSubnode(backgroundContent, at: 0)
}
} else {
self.backgroundContent?.removeFromSupernode()
self.backgroundContent = nil
}
if let backgroundContent = self.backgroundContent {
self.backgroundNode.isHidden = true
backgroundContent.cornerRadius = min(20.0, self.backgroundNode.bounds.height / 2.0)
backgroundContent.frame = contentFrame
if let (rect, containerSize) = self.absolutePosition {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
} else {
self.backgroundNode.isHidden = false
}
if let loadingNode = loadingNode { if let loadingNode = loadingNode {
self.animateFromLoadingNode(loadingNode) self.animateFromLoadingNode(loadingNode)
} }
} }
public func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) {
self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
}
}
} }

View File

@ -244,7 +244,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
} }
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .UnreadEntry(_, presentationData): case let .UnreadEntry(_, presentationData):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData, context: context), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData, controllerInteraction: controllerInteraction, context: context), directionHint: entry.directionHint)
case let .ReplyCountEntry(_, isComments, count, presentationData): case let .ReplyCountEntry(_, isComments, count, presentationData):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatReplyCountItem(index: entry.entry.index, isComments: isComments, count: count, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatReplyCountItem(index: entry.entry.index, isComments: isComments, count: count, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction), directionHint: entry.directionHint)
case let .ChatInfoEntry(title, text, photo, video, presentationData): case let .ChatInfoEntry(title, text, photo, video, presentationData):
@ -289,7 +289,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
} }
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .UnreadEntry(_, presentationData): case let .UnreadEntry(_, presentationData):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData, context: context), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatUnreadItem(index: entry.entry.index, presentationData: presentationData, controllerInteraction: controllerInteraction, context: context), directionHint: entry.directionHint)
case let .ReplyCountEntry(_, isComments, count, presentationData): case let .ReplyCountEntry(_, isComments, count, presentationData):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatReplyCountItem(index: entry.entry.index, isComments: isComments, count: count, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatReplyCountItem(index: entry.entry.index, isComments: isComments, count: count, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction), directionHint: entry.directionHint)
case let .ChatInfoEntry(title, text, photo, video, presentationData): case let .ChatInfoEntry(title, text, photo, video, presentationData):

View File

@ -6,6 +6,7 @@ import Postbox
import Display import Display
import TelegramPresentationData import TelegramPresentationData
import AccountContext import AccountContext
import WallpaperBackgroundNode
private let titleFont = Font.medium(16.0) private let titleFont = Font.medium(16.0)
@ -16,6 +17,12 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
private var iconNode: ASImageNode? private var iconNode: ASImageNode?
private var buttonView: HighlightTrackingButton? private var buttonView: HighlightTrackingButton?
private var wallpaperBackgroundNode: WallpaperBackgroundNode?
private var backgroundContent: WallpaperBubbleBackgroundNode?
private var backgroundColorNode: ASDisplayNode?
private var absolutePosition: (CGRect, CGSize)?
private var button: ReplyMarkupButton? private var button: ReplyMarkupButton?
var pressed: ((ReplyMarkupButton) -> Void)? var pressed: ((ReplyMarkupButton) -> Void)?
var longTapped: ((ReplyMarkupButton) -> Void)? var longTapped: ((ReplyMarkupButton) -> Void)?
@ -58,9 +65,15 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
if highlighted { if highlighted {
strongSelf.backgroundBlurNode.layer.removeAnimation(forKey: "opacity") strongSelf.backgroundBlurNode.layer.removeAnimation(forKey: "opacity")
strongSelf.backgroundBlurNode.alpha = 0.55 strongSelf.backgroundBlurNode.alpha = 0.55
strongSelf.backgroundContent?.layer.removeAnimation(forKey: "opacity")
strongSelf.backgroundContent?.alpha = 0.55
} else { } else {
strongSelf.backgroundBlurNode.alpha = 1.0 strongSelf.backgroundBlurNode.alpha = 1.0
strongSelf.backgroundBlurNode.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2) strongSelf.backgroundBlurNode.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
strongSelf.backgroundContent?.alpha = 1.0
strongSelf.backgroundContent?.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
} }
} }
} }
@ -83,10 +96,21 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
} }
} }
class func asyncLayout(_ maybeNode: ChatMessageActionButtonNode?) -> (_ context: AccountContext, _ theme: ChatPresentationThemeData, _ bubbleCorners: PresentationChatBubbleCorners, _ strings: PresentationStrings, _ message: Message, _ button: ReplyMarkupButton, _ constrainedWidth: CGFloat, _ position: MessageBubbleActionButtonPosition) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonNode))) { func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
}
class func asyncLayout(_ maybeNode: ChatMessageActionButtonNode?) -> (_ context: AccountContext, _ theme: ChatPresentationThemeData, _ bubbleCorners: PresentationChatBubbleCorners, _ strings: PresentationStrings, _ backgroundNode: WallpaperBackgroundNode?, _ message: Message, _ button: ReplyMarkupButton, _ constrainedWidth: CGFloat, _ position: MessageBubbleActionButtonPosition) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonNode))) {
let titleLayout = TextNode.asyncLayout(maybeNode?.titleNode) let titleLayout = TextNode.asyncLayout(maybeNode?.titleNode)
return { context, theme, bubbleCorners, strings, message, button, constrainedWidth, position in return { context, theme, bubbleCorners, strings, backgroundNode, message, button, constrainedWidth, position in
let incoming = message.effectivelyIncoming(context.account.peerId) let incoming = message.effectivelyIncoming(context.account.peerId)
let graphics = PresentationResourcesChat.additionalGraphics(theme.theme, wallpaper: theme.wallpaper, bubbleCorners: bubbleCorners) let graphics = PresentationResourcesChat.additionalGraphics(theme.theme, wallpaper: theme.wallpaper, bubbleCorners: bubbleCorners)
@ -159,6 +183,8 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
animation = .None animation = .None
} }
node.wallpaperBackgroundNode = backgroundNode
node.button = button node.button = button
switch button.action { switch button.action {
@ -175,6 +201,44 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
node.backgroundBlurNode.update(size: node.backgroundBlurNode.bounds.size, cornerRadius: bubbleCorners.auxiliaryRadius, animator: animation.animator) node.backgroundBlurNode.update(size: node.backgroundBlurNode.bounds.size, cornerRadius: bubbleCorners.auxiliaryRadius, animator: animation.animator)
node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate) node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate)
if backgroundNode?.hasExtraBubbleBackground() == true {
if node.backgroundContent == nil, let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContent.clipsToBounds = true
backgroundContent.allowsGroupOpacity = true
node.backgroundContent = backgroundContent
node.insertSubnode(backgroundContent, at: 0)
let backgroundColorNode = ASDisplayNode()
backgroundColorNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.4)
backgroundContent.addSubnode(backgroundColorNode)
node.backgroundColorNode = backgroundColorNode
}
} else {
node.backgroundContent?.removeFromSupernode()
node.backgroundContent = nil
node.backgroundColorNode?.removeFromSupernode()
node.backgroundColorNode = nil
}
if let backgroundContent = node.backgroundContent {
node.backgroundBlurNode.isHidden = true
backgroundContent.frame = node.backgroundBlurNode.frame
backgroundContent.cornerRadius = bubbleCorners.auxiliaryRadius
node.backgroundColorNode?.frame = backgroundContent.bounds
if let (rect, containerSize) = node.absolutePosition {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
} else {
node.backgroundBlurNode.isHidden = false
}
if iconImage != nil { if iconImage != nil {
if node.iconNode == nil { if node.iconNode == nil {
let iconNode = ASImageNode() let iconNode = ASImageNode()
@ -206,6 +270,10 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
animation.animator.updateFrame(layer: iconNode.layer, frame: CGRect(x: width - 16.0, y: 4.0, width: 12.0, height: 12.0), completion: nil) animation.animator.updateFrame(layer: iconNode.layer, frame: CGRect(x: width - 16.0, y: 4.0, width: 12.0, height: 12.0), completion: nil)
} }
if let (rect, size) = node.absolutePosition {
node.updateAbsoluteRect(rect, within: size)
}
node.accessibilityArea.accessibilityLabel = title node.accessibilityArea.accessibilityLabel = title
node.accessibilityArea.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: 42.0)) node.accessibilityArea.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: 42.0))
@ -224,6 +292,8 @@ final class ChatMessageActionButtonsNode: ASDisplayNode {
var buttonPressed: ((ReplyMarkupButton) -> Void)? var buttonPressed: ((ReplyMarkupButton) -> Void)?
var buttonLongTapped: ((ReplyMarkupButton) -> Void)? var buttonLongTapped: ((ReplyMarkupButton) -> Void)?
private var absolutePosition: (CGRect, CGSize)?
override init() { override init() {
super.init() super.init()
@ -240,10 +310,21 @@ final class ChatMessageActionButtonsNode: ASDisplayNode {
} }
} }
class func asyncLayout(_ maybeNode: ChatMessageActionButtonsNode?) -> (_ context: AccountContext, _ theme: ChatPresentationThemeData, _ chatBubbleCorners: PresentationChatBubbleCorners, _ strings: PresentationStrings, _ replyMarkup: ReplyMarkupMessageAttribute, _ message: Message, _ constrainedWidth: CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode)) { func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absolutePosition = (rect, containerSize)
for button in buttonNodes {
var buttonFrame = button.frame
buttonFrame.origin.x += rect.minX
buttonFrame.origin.y += rect.minY
button.updateAbsoluteRect(buttonFrame, within: containerSize)
}
}
class func asyncLayout(_ maybeNode: ChatMessageActionButtonsNode?) -> (_ context: AccountContext, _ theme: ChatPresentationThemeData, _ chatBubbleCorners: PresentationChatBubbleCorners, _ strings: PresentationStrings, _ backgroundNode: WallpaperBackgroundNode?, _ replyMarkup: ReplyMarkupMessageAttribute, _ message: Message, _ constrainedWidth: CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode)) {
let currentButtonLayouts = maybeNode?.buttonNodes.map { ChatMessageActionButtonNode.asyncLayout($0) } ?? [] let currentButtonLayouts = maybeNode?.buttonNodes.map { ChatMessageActionButtonNode.asyncLayout($0) } ?? []
return { context, theme, chatBubbleCorners, strings, replyMarkup, message, constrainedWidth in return { context, theme, chatBubbleCorners, strings, backgroundNode, replyMarkup, message, constrainedWidth in
let buttonHeight: CGFloat = 42.0 let buttonHeight: CGFloat = 42.0
let buttonSpacing: CGFloat = 4.0 let buttonSpacing: CGFloat = 4.0
@ -276,9 +357,9 @@ final class ChatMessageActionButtonsNode: ASDisplayNode {
let prepareButtonLayout: (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonNode))) let prepareButtonLayout: (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonNode)))
if buttonIndex < currentButtonLayouts.count { if buttonIndex < currentButtonLayouts.count {
prepareButtonLayout = currentButtonLayouts[buttonIndex](context, theme, chatBubbleCorners, strings, message, button, maximumButtonWidth, buttonPosition) prepareButtonLayout = currentButtonLayouts[buttonIndex](context, theme, chatBubbleCorners, strings, backgroundNode, message, button, maximumButtonWidth, buttonPosition)
} else { } else {
prepareButtonLayout = ChatMessageActionButtonNode.asyncLayout(nil)(context, theme, chatBubbleCorners, strings, message, button, maximumButtonWidth, buttonPosition) prepareButtonLayout = ChatMessageActionButtonNode.asyncLayout(nil)(context, theme, chatBubbleCorners, strings, backgroundNode, message, button, maximumButtonWidth, buttonPosition)
} }
maximumRowButtonWidth = max(maximumRowButtonWidth, prepareButtonLayout.minimumWidth) maximumRowButtonWidth = max(maximumRowButtonWidth, prepareButtonLayout.minimumWidth)
@ -363,6 +444,10 @@ final class ChatMessageActionButtonsNode: ASDisplayNode {
} }
node.buttonNodes = updatedButtons node.buttonNodes = updatedButtons
if let (rect, size) = node.absolutePosition {
node.updateAbsoluteRect(rect, within: size)
}
return node return node
}) })
}) })

View File

@ -57,6 +57,8 @@ extension SlotMachineAnimationNode: GenericAnimatedStickerNode {
} }
class ChatMessageShareButton: HighlightableButtonNode { class ChatMessageShareButton: HighlightableButtonNode {
private var backgroundContent: WallpaperBubbleBackgroundNode?
private let backgroundNode: NavigationBackgroundNode private let backgroundNode: NavigationBackgroundNode
private let iconNode: ASImageNode private let iconNode: ASImageNode
private var iconOffset = CGPoint() private var iconOffset = CGPoint()
@ -66,6 +68,8 @@ class ChatMessageShareButton: HighlightableButtonNode {
private var textNode: ImmediateTextNode? private var textNode: ImmediateTextNode?
private var absolutePosition: (CGRect, CGSize)?
init() { init() {
self.backgroundNode = NavigationBackgroundNode(color: .clear) self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.iconNode = ASImageNode() self.iconNode = ASImageNode()
@ -80,7 +84,7 @@ class ChatMessageShareButton: HighlightableButtonNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
func update(presentationData: ChatPresentationData, chatLocation: ChatLocation, subject: ChatControllerSubject?, message: Message, account: Account, disableComments: Bool = false) -> CGSize { func update(presentationData: ChatPresentationData, controllerInteraction: ChatControllerInteraction, chatLocation: ChatLocation, subject: ChatControllerSubject?, message: Message, account: Account, disableComments: Bool = false) -> CGSize {
var isReplies = false var isReplies = false
var replyCount = 0 var replyCount = 0
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info { if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
@ -160,8 +164,46 @@ class ChatMessageShareButton: HighlightableButtonNode {
if let image = self.iconNode.image { if let image = self.iconNode.image {
self.iconNode.frame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0) + self.iconOffset.x, y: floor((size.width - image.size.width) / 2.0) - (offsetIcon ? 1.0 : 0.0) + self.iconOffset.y), size: image.size) self.iconNode.frame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0) + self.iconOffset.x, y: floor((size.width - image.size.width) / 2.0) - (offsetIcon ? 1.0 : 0.0) + self.iconOffset.y), size: image.size)
} }
if controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true {
if self.backgroundContent == nil, let backgroundContent = controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContent.clipsToBounds = true
backgroundContent.allowsGroupOpacity = true
self.backgroundContent = backgroundContent
self.insertSubnode(backgroundContent, at: 0)
}
} else {
self.backgroundContent?.removeFromSupernode()
self.backgroundContent = nil
}
if let backgroundContent = self.backgroundContent {
self.backgroundNode.isHidden = true
backgroundContent.cornerRadius = min(self.backgroundNode.bounds.width, self.backgroundNode.bounds.height) / 2.0
backgroundContent.frame = self.backgroundNode.frame
if let (rect, containerSize) = self.absolutePosition {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
} else {
self.backgroundNode.isHidden = false
}
return size return size
} }
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
}
} }
class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
@ -1206,7 +1248,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
var maxContentWidth = imageSize.width var maxContentWidth = imageSize.width
var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))? var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))?
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, replyMarkup, item.message, maxContentWidth) let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, item.controllerInteraction.presentationContext.backgroundNode, replyMarkup, item.message, maxContentWidth)
maxContentWidth = max(maxContentWidth, minWidth) maxContentWidth = max(maxContentWidth, minWidth)
actionButtonsFinalize = buttonsLayout actionButtonsFinalize = buttonsLayout
} }
@ -1359,7 +1401,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
strongSelf.addSubnode(updatedShareButtonNode) strongSelf.addSubnode(updatedShareButtonNode)
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside) updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
} }
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account) let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account)
updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: updatedImageFrame.maxX + 8.0, y: updatedImageFrame.maxY - buttonSize.height - 4.0 + imageBottomPadding), size: buttonSize) updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: updatedImageFrame.maxX + 8.0, y: updatedImageFrame.maxY - buttonSize.height - 4.0 + imageBottomPadding), size: buttonSize)
} else if let shareButtonNode = strongSelf.shareButtonNode { } else if let shareButtonNode = strongSelf.shareButtonNode {
shareButtonNode.removeFromSupernode() shareButtonNode.removeFromSupernode()

View File

@ -1073,7 +1073,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode), adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, String?, CGSize) -> (CGSize, (CGFloat) -> ChatMessageForwardInfoNode), forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, String?, CGSize) -> (CGSize, (CGFloat) -> ChatMessageForwardInfoNode),
replyInfoLayout: (ChatMessageReplyInfoNode.Arguments) -> (CGSize, (Bool) -> ChatMessageReplyInfoNode), replyInfoLayout: (ChatMessageReplyInfoNode.Arguments) -> (CGSize, (Bool) -> ChatMessageReplyInfoNode),
actionButtonsLayout: (AccountContext, ChatPresentationThemeData, PresentationChatBubbleCorners, PresentationStrings, ReplyMarkupMessageAttribute, Message, CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode)), actionButtonsLayout: (AccountContext, ChatPresentationThemeData, PresentationChatBubbleCorners, PresentationStrings, WallpaperBackgroundNode?, ReplyMarkupMessageAttribute, Message, CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode)),
reactionButtonsLayout: (ChatMessageReactionButtonsNode.Arguments) -> (minWidth: CGFloat, layout: (CGFloat) -> (size: CGSize, apply: (ListViewItemUpdateAnimation) -> ChatMessageReactionButtonsNode)), reactionButtonsLayout: (ChatMessageReactionButtonsNode.Arguments) -> (minWidth: CGFloat, layout: (CGFloat) -> (size: CGSize, apply: (ListViewItemUpdateAnimation) -> ChatMessageReactionButtonsNode)),
mosaicStatusLayout: (ChatMessageDateAndStatusNode.Arguments) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageDateAndStatusNode)), mosaicStatusLayout: (ChatMessageDateAndStatusNode.Arguments) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageDateAndStatusNode)),
layoutConstants: ChatMessageItemLayoutConstants, layoutConstants: ChatMessageItemLayoutConstants,
@ -1937,7 +1937,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))? var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))?
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, replyMarkup, item.message, maximumNodeWidth) let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, item.controllerInteraction.presentationContext.backgroundNode, replyMarkup, item.message, maximumNodeWidth)
maxContentWidth = max(maxContentWidth, minWidth) maxContentWidth = max(maxContentWidth, minWidth)
actionButtonsFinalize = buttonsLayout actionButtonsFinalize = buttonsLayout
} }
@ -2959,7 +2959,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
if let shareButtonNode = strongSelf.shareButtonNode { if let shareButtonNode = strongSelf.shareButtonNode {
let currentBackgroundFrame = strongSelf.backgroundNode.frame let currentBackgroundFrame = strongSelf.backgroundNode.frame
let buttonSize = shareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true) let buttonSize = shareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true)
animation.animator.updateFrame(layer: shareButtonNode.layer, frame: CGRect(origin: CGPoint(x: currentBackgroundFrame.maxX + 8.0, y: currentBackgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize), completion: nil) animation.animator.updateFrame(layer: shareButtonNode.layer, frame: CGRect(origin: CGPoint(x: currentBackgroundFrame.maxX + 8.0, y: currentBackgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize), completion: nil)
} }
} else { } else {
@ -2969,7 +2969,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}*/ }*/
strongSelf.messageAccessibilityArea.frame = backgroundFrame strongSelf.messageAccessibilityArea.frame = backgroundFrame
if let shareButtonNode = strongSelf.shareButtonNode { if let shareButtonNode = strongSelf.shareButtonNode {
let buttonSize = shareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true) let buttonSize = shareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true)
shareButtonNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.maxX + 8.0, y: backgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize) shareButtonNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.maxX + 8.0, y: backgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize)
} }
@ -3984,6 +3984,22 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
contentNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + contentNode.frame.minX, y: rect.minY + contentNode.frame.minY), size: rect.size), within: containerSize) contentNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + contentNode.frame.minX, y: rect.minY + contentNode.frame.minY), size: rect.size), within: containerSize)
} }
if let shareButtonNode = self.shareButtonNode {
var shareButtonNodeFrame = shareButtonNode.frame
shareButtonNodeFrame.origin.x += rect.minX
shareButtonNodeFrame.origin.y += rect.minY
shareButtonNode.updateAbsoluteRect(shareButtonNodeFrame, within: containerSize)
}
if let actionButtonsNode = self.actionButtonsNode {
var actionButtonsNodeFrame = actionButtonsNode.frame
actionButtonsNodeFrame.origin.x += rect.minX
actionButtonsNodeFrame.origin.y += rect.minY
actionButtonsNode.updateAbsoluteRect(actionButtonsNodeFrame, within: containerSize)
}
if let reactionButtonsNode = self.reactionButtonsNode { if let reactionButtonsNode = self.reactionButtonsNode {
var reactionButtonsNodeFrame = reactionButtonsNode.frame var reactionButtonsNodeFrame = reactionButtonsNode.frame
reactionButtonsNodeFrame.origin.x += rect.minX reactionButtonsNodeFrame.origin.x += rect.minX

View File

@ -12,6 +12,7 @@ import TelegramUniversalVideoContent
import UniversalMediaPlayer import UniversalMediaPlayer
import GalleryUI import GalleryUI
import HierarchyTrackingLayer import HierarchyTrackingLayer
import WallpaperBackgroundNode
private let timezoneOffset: Int32 = { private let timezoneOffset: Int32 = {
let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
@ -30,13 +31,15 @@ final class ChatMessageDateHeader: ListViewItemHeader {
let id: ListViewItemNode.HeaderId let id: ListViewItemNode.HeaderId
let presentationData: ChatPresentationData let presentationData: ChatPresentationData
let controllerInteraction: ChatControllerInteraction?
let context: AccountContext let context: AccountContext
let action: ((Int32, Bool) -> Void)? let action: ((Int32, Bool) -> Void)?
init(timestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32, Bool) -> Void)? = nil) { init(timestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, controllerInteraction: ChatControllerInteraction?, context: AccountContext, action: ((Int32, Bool) -> Void)? = nil) {
self.timestamp = timestamp self.timestamp = timestamp
self.scheduled = scheduled self.scheduled = scheduled
self.presentationData = presentationData self.presentationData = presentationData
self.controllerInteraction = controllerInteraction
self.context = context self.context = context
self.action = action self.action = action
self.roundedTimestamp = dateHeaderTimestampId(timestamp: timestamp) self.roundedTimestamp = dateHeaderTimestampId(timestamp: timestamp)
@ -57,7 +60,7 @@ final class ChatMessageDateHeader: ListViewItemHeader {
} }
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, scheduled: self.scheduled, presentationData: self.presentationData, context: self.context, action: self.action) return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, scheduled: self.scheduled, presentationData: self.presentationData, controllerInteraction: self.controllerInteraction, context: self.context, action: self.action)
} }
func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) { func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) {
@ -115,8 +118,11 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let stickBackgroundNode: ASImageNode let stickBackgroundNode: ASImageNode
let activateArea: AccessibilityAreaNode let activateArea: AccessibilityAreaNode
private var backgroundContent: WallpaperBubbleBackgroundNode?
private let localTimestamp: Int32 private let localTimestamp: Int32
private var presentationData: ChatPresentationData private var presentationData: ChatPresentationData
private let controllerInteraction: ChatControllerInteraction?
private let context: AccountContext private let context: AccountContext
private let text: String private let text: String
@ -124,8 +130,11 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
private var stickDistanceFactor: CGFloat = 0.0 private var stickDistanceFactor: CGFloat = 0.0
private var action: ((Int32, Bool) -> Void)? = nil private var action: ((Int32, Bool) -> Void)? = nil
init(localTimestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32, Bool) -> Void)? = nil) { private var absolutePosition: (CGRect, CGSize)?
init(localTimestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, controllerInteraction: ChatControllerInteraction?, context: AccountContext, action: ((Int32, Bool) -> Void)? = nil) {
self.presentationData = presentationData self.presentationData = presentationData
self.controllerInteraction = controllerInteraction
self.context = context self.context = context
self.localTimestamp = localTimestamp self.localTimestamp = localTimestamp
@ -135,6 +144,11 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.labelNode.isUserInteractionEnabled = false self.labelNode.isUserInteractionEnabled = false
self.labelNode.displaysAsynchronously = !presentationData.isPreview self.labelNode.displaysAsynchronously = !presentationData.isPreview
if controllerInteraction?.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true, let backgroundContent = controllerInteraction?.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContent.clipsToBounds = true
self.backgroundContent = backgroundContent
}
self.backgroundNode = NavigationBackgroundNode(color: .clear) self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.backgroundNode.isUserInteractionEnabled = false self.backgroundNode.isUserInteractionEnabled = false
@ -188,7 +202,11 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.stickBackgroundNode.image = graphics.dateFloatingBackground self.stickBackgroundNode.image = graphics.dateFloatingBackground
self.stickBackgroundNode.alpha = 0.0 self.stickBackgroundNode.alpha = 0.0
self.addSubnode(self.backgroundNode) if let backgroundContent = self.backgroundContent {
self.addSubnode(backgroundContent)
} else {
self.addSubnode(self.backgroundNode)
}
self.addSubnode(self.labelNode) self.addSubnode(self.labelNode)
self.addSubnode(self.activateArea) self.addSubnode(self.activateArea)
@ -239,6 +257,16 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.backgroundNode.updateColor(color: color, enableBlur: enableBlur, transition: .immediate) self.backgroundNode.updateColor(color: color, enableBlur: enableBlur, transition: .immediate)
} }
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += containerSize.height - rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
}
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) { override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
let chatDateSize: CGFloat = 20.0 let chatDateSize: CGFloat = 20.0
let chatDateInset: CGFloat = 6.0 let chatDateInset: CGFloat = 6.0
@ -253,6 +281,20 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.labelNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.origin.x + chatDateInset, y: backgroundFrame.origin.y + floorToScreenPixels((backgroundSize.height - labelSize.height) / 2.0)), size: labelSize) self.labelNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.origin.x + chatDateInset, y: backgroundFrame.origin.y + floorToScreenPixels((backgroundSize.height - labelSize.height) / 2.0)), size: labelSize)
self.activateArea.frame = backgroundFrame self.activateArea.frame = backgroundFrame
if let backgroundContent = self.backgroundContent {
backgroundContent.allowsGroupOpacity = true
self.backgroundNode.isHidden = true
backgroundContent.frame = self.backgroundNode.frame
backgroundContent.cornerRadius = backgroundFrame.size.height / 2.0
if let (rect, containerSize) = self.absolutePosition {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += containerSize.height - rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
}
} }
override func updateStickDistanceFactor(_ factor: CGFloat, transition: ContainedViewLayoutTransition) { override func updateStickDistanceFactor(_ factor: CGFloat, transition: ContainedViewLayoutTransition) {
@ -285,10 +327,12 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let previousAlpha = self.backgroundNode.alpha let previousAlpha = self.backgroundNode.alpha
if !previousAlpha.isEqual(to: alpha) { if !previousAlpha.isEqual(to: alpha) {
self.backgroundContent?.alpha = alpha
self.backgroundNode.alpha = alpha self.backgroundNode.alpha = alpha
self.labelNode.alpha = alpha self.labelNode.alpha = alpha
if animated { if animated {
let duration: Double = flashing ? 0.3 : 0.4 let duration: Double = flashing ? 0.3 : 0.4
self.backgroundContent?.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration)
self.backgroundNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration) self.backgroundNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration)
self.labelNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration) self.labelNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration)
} }

View File

@ -532,7 +532,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
var maxContentWidth = normalDisplaySize.width var maxContentWidth = normalDisplaySize.width
var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))? var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))?
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, replyMarkup, item.message, maxContentWidth) let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, item.controllerInteraction.presentationContext.backgroundNode, replyMarkup, item.message, maxContentWidth)
maxContentWidth = max(maxContentWidth, minWidth) maxContentWidth = max(maxContentWidth, minWidth)
actionButtonsFinalize = buttonsLayout actionButtonsFinalize = buttonsLayout
} }
@ -636,7 +636,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
strongSelf.addSubnode(updatedShareButtonNode) strongSelf.addSubnode(updatedShareButtonNode)
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside) updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
} }
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account) let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account)
updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: min(params.width - buttonSize.width - 8.0, videoFrame.maxX - 7.0), y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize) updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: min(params.width - buttonSize.width - 8.0, videoFrame.maxX - 7.0), y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize)
} else if let shareButtonNode = strongSelf.shareButtonNode { } else if let shareButtonNode = strongSelf.shareButtonNode {
shareButtonNode.removeFromSupernode() shareButtonNode.removeFromSupernode()

View File

@ -328,7 +328,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
isScheduledMessages = true isScheduledMessages = true
} }
self.dateHeader = ChatMessageDateHeader(timestamp: content.index.timestamp, scheduled: isScheduledMessages, presentationData: presentationData, context: context, action: { timestamp, alreadyThere in self.dateHeader = ChatMessageDateHeader(timestamp: content.index.timestamp, scheduled: isScheduledMessages, presentationData: presentationData, controllerInteraction: controllerInteraction, context: context, action: { timestamp, alreadyThere in
var calendar = NSCalendar.current var calendar = NSCalendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")! calendar.timeZone = TimeZone(abbreviation: "UTC")!
let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) let date = Date(timeIntervalSince1970: TimeInterval(timestamp))

View File

@ -84,7 +84,7 @@ struct ChatMessageItemLayoutConstants {
} }
fileprivate static var compact: ChatMessageItemLayoutConstants { fileprivate static var compact: ChatMessageItemLayoutConstants {
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)) let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 0.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0)) let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 380.0), minDimensions: CGSize(width: 170.0, height: 74.0)) let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 380.0), minDimensions: CGSize(width: 170.0, height: 74.0))
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0) let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
@ -96,7 +96,7 @@ struct ChatMessageItemLayoutConstants {
} }
fileprivate static var regular: ChatMessageItemLayoutConstants { fileprivate static var regular: ChatMessageItemLayoutConstants {
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.65), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)) let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 0.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.65), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0)) let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0)) let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0))
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0) let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)

View File

@ -673,7 +673,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
var maxContentWidth = imageSize.width var maxContentWidth = imageSize.width
var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))? var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageActionButtonsNode))?
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, replyMarkup, item.message, maxContentWidth) let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, item.controllerInteraction.presentationContext.backgroundNode, replyMarkup, item.message, maxContentWidth)
maxContentWidth = max(maxContentWidth, minWidth) maxContentWidth = max(maxContentWidth, minWidth)
actionButtonsFinalize = buttonsLayout actionButtonsFinalize = buttonsLayout
} }
@ -839,7 +839,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
strongSelf.addSubnode(updatedShareButtonNode) strongSelf.addSubnode(updatedShareButtonNode)
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside) updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
} }
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account) let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account)
let shareButtonFrame = CGRect(origin: CGPoint(x: baseShareButtonFrame.minX, y: baseShareButtonFrame.maxY - buttonSize.height), size: buttonSize) let shareButtonFrame = CGRect(origin: CGPoint(x: baseShareButtonFrame.minX, y: baseShareButtonFrame.maxY - buttonSize.height), size: buttonSize)
transition.updateFrame(node: updatedShareButtonNode, frame: shareButtonFrame) transition.updateFrame(node: updatedShareButtonNode, frame: shareButtonFrame)
} else if let shareButtonNode = strongSelf.shareButtonNode { } else if let shareButtonNode = strongSelf.shareButtonNode {

View File

@ -23,7 +23,7 @@ class ChatReplyCountItem: ListViewItem {
self.isComments = isComments self.isComments = isComments
self.count = count self.count = count
self.presentationData = presentationData self.presentationData = presentationData
self.header = ChatMessageDateHeader(timestamp: index.timestamp, scheduled: false, presentationData: presentationData, context: context) self.header = ChatMessageDateHeader(timestamp: index.timestamp, scheduled: false, presentationData: presentationData, controllerInteraction: controllerInteraction, context: context)
self.controllerInteraction = controllerInteraction self.controllerInteraction = controllerInteraction
} }

View File

@ -6,18 +6,21 @@ import Display
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import AccountContext import AccountContext
import WallpaperBackgroundNode
private let titleFont = UIFont.systemFont(ofSize: 13.0) private let titleFont = UIFont.systemFont(ofSize: 13.0)
class ChatUnreadItem: ListViewItem { class ChatUnreadItem: ListViewItem {
let index: MessageIndex let index: MessageIndex
let presentationData: ChatPresentationData let presentationData: ChatPresentationData
let controllerInteraction: ChatControllerInteraction
let header: ChatMessageDateHeader let header: ChatMessageDateHeader
init(index: MessageIndex, presentationData: ChatPresentationData, context: AccountContext) { init(index: MessageIndex, presentationData: ChatPresentationData, controllerInteraction: ChatControllerInteraction, context: AccountContext) {
self.index = index self.index = index
self.presentationData = presentationData self.presentationData = presentationData
self.header = ChatMessageDateHeader(timestamp: index.timestamp, scheduled: false, presentationData: presentationData, context: context) self.controllerInteraction = controllerInteraction
self.header = ChatMessageDateHeader(timestamp: index.timestamp, scheduled: false, presentationData: presentationData, controllerInteraction: controllerInteraction, context: context)
} }
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -61,6 +64,11 @@ class ChatUnreadItemNode: ListViewItemNode {
let activateArea: AccessibilityAreaNode let activateArea: AccessibilityAreaNode
private var wallpaperBackgroundNode: WallpaperBackgroundNode?
private var backgroundContent: WallpaperBubbleBackgroundNode?
private var absolutePosition: (CGRect, CGSize)?
private var theme: ChatPresentationThemeData? private var theme: ChatPresentationThemeData?
private let layoutConstants = ChatMessageItemLayoutConstants.default private let layoutConstants = ChatMessageItemLayoutConstants.default
@ -101,7 +109,7 @@ class ChatUnreadItemNode: ListViewItemNode {
} }
override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) { override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
if let item = item as? ChatUnreadItem { if let item = item as? ChatUnreadItem {
let dateAtBottom = !chatItemsHaveCommonDateHeader(item, nextItem) let dateAtBottom = !chatItemsHaveCommonDateHeader(item, nextItem)
let (layout, apply) = self.asyncLayout()(item, params, dateAtBottom) let (layout, apply) = self.asyncLayout()(item, params, dateAtBottom)
apply() apply()
@ -142,11 +150,48 @@ class ChatUnreadItemNode: ListViewItemNode {
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: backgroundSize) strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: backgroundSize)
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - size.size.width) / 2.0), y: floorToScreenPixels((backgroundSize.height - size.size.height) / 2.0)), size: size.size) strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - size.size.width) / 2.0), y: floorToScreenPixels((backgroundSize.height - size.size.height) / 2.0)), size: size.size)
if item.controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true {
if strongSelf.backgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContent.clipsToBounds = true
strongSelf.backgroundContent = backgroundContent
strongSelf.insertSubnode(backgroundContent, at: 0)
}
} else {
strongSelf.backgroundContent?.removeFromSupernode()
strongSelf.backgroundContent = nil
}
if let backgroundContent = strongSelf.backgroundContent {
strongSelf.backgroundNode.isHidden = true
backgroundContent.frame = strongSelf.backgroundNode.frame
if let (rect, containerSize) = strongSelf.absolutePosition {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
} else {
strongSelf.backgroundNode.isHidden = false
}
} }
}) })
} }
} }
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
super.updateAbsoluteRect(rect, within: containerSize)
self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent {
var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
}
}
override public func headers() -> [ListViewItemHeader]? { override public func headers() -> [ListViewItemHeader]? {
if let item = self.item { if let item = self.item {
return [item.header] return [item.header]

View File

@ -1355,7 +1355,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
} }
public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader { public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader {
return ChatMessageDateHeader(timestamp: timestamp, scheduled: false, presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context) return ChatMessageDateHeader(timestamp: timestamp, scheduled: false, presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), controllerInteraction: nil, context: context)
} }
#if ENABLE_WALLET #if ENABLE_WALLET

View File

@ -291,6 +291,10 @@ final class MetalWallpaperBackgroundNode: ASDisplayNode, WallpaperBackgroundNode
return false return false
} }
func hasExtraBubbleBackground() -> Bool {
return false
}
func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode? { func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode? {
return nil return nil
} }

View File

@ -61,6 +61,8 @@ public protocol WallpaperBackgroundNode: ASDisplayNode {
func hasBubbleBackground(for type: WallpaperBubbleType) -> Bool func hasBubbleBackground(for type: WallpaperBubbleType) -> Bool
func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode? func makeBubbleBackground(for type: WallpaperBubbleType) -> WallpaperBubbleBackgroundNode?
func hasExtraBubbleBackground() -> Bool
func makeDimmedNode() -> ASDisplayNode? func makeDimmedNode() -> ASDisplayNode?
} }
@ -393,7 +395,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
if isInvertedGradient { if isInvertedGradient {
switch self.bubbleType { switch self.bubbleType {
case .free: case .free:
needsCleanBackground = false self.contentNode.backgroundColor = bubbleTheme.chat.message.incoming.bubble.withWallpaper.fill[0]
// needsCleanBackground = false
case .incoming, .outgoing: case .incoming, .outgoing:
break break
} }
@ -591,6 +594,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
private struct ValidPatternImage { private struct ValidPatternImage {
let wallpaper: TelegramWallpaper let wallpaper: TelegramWallpaper
let invertPattern: Bool
let generate: (TransformImageArguments) -> DrawingContext? let generate: (TransformImageArguments) -> DrawingContext?
} }
private var validPatternImage: ValidPatternImage? private var validPatternImage: ValidPatternImage?
@ -893,10 +897,14 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
var updated = true var updated = true
let brightness = UIColor.average(of: file.settings.colors.map(UIColor.init(rgb:))).hsb.b let brightness = UIColor.average(of: file.settings.colors.map(UIColor.init(rgb:))).hsb.b
patternIsLight = brightness > 0.3 patternIsLight = brightness > 0.3
let intensity = CGFloat(file.settings.intensity ?? 50) / 100.0
invertPattern = intensity < 0
if let previousWallpaper = self.validPatternImage?.wallpaper { if let previousWallpaper = self.validPatternImage?.wallpaper {
switch previousWallpaper { switch previousWallpaper {
case let .file(previousFile): case let .file(previousFile):
if file.file.id == previousFile.file.id { if file.file.id == previousFile.file.id && self.validPatternImage?.invertPattern == invertPattern {
updated = false updated = false
} }
default: default:
@ -908,8 +916,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
self.validPatternGeneratedImage = nil self.validPatternGeneratedImage = nil
self.validPatternImage = nil self.validPatternImage = nil
if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper { if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper && cachedValidPatternImage.generated.invertPattern == invertPattern {
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, generate: cachedValidPatternImage.generate) self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, invertPattern: invertPattern, generate: cachedValidPatternImage.generate)
} else { } else {
func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference { func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference {
return .wallpaper(wallpaper: .slug(file.slug), resource: resource._asResource()) return .wallpaper(wallpaper: .slug(file.slug), resource: resource._asResource())
@ -945,7 +953,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
return context return context
}*/ }*/
strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, generate: generator) strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, generate: generator)
strongSelf.validPatternGeneratedImage = nil strongSelf.validPatternGeneratedImage = nil
if let size = strongSelf.validLayout { if let size = strongSelf.validLayout {
strongSelf.loadPatternForSizeIfNeeded(size: size, transition: .immediate) strongSelf.loadPatternForSizeIfNeeded(size: size, transition: .immediate)
@ -958,8 +966,6 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
})) }))
} }
} }
let intensity = CGFloat(file.settings.intensity ?? 50) / 100.0
invertPattern = intensity < 0
default: default:
self.updatePatternPresentation() self.updatePatternPresentation()
} }
@ -1165,6 +1171,19 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
return node return node
} }
func hasExtraBubbleBackground() -> Bool {
var isInvertedGradient = false
switch self.wallpaper {
case let .file(file):
if let intensity = file.settings.intensity, intensity < 0 {
isInvertedGradient = true
}
default:
break
}
return isInvertedGradient
}
func makeDimmedNode() -> ASDisplayNode? { func makeDimmedNode() -> ASDisplayNode? {
if let gradientBackgroundNode = self.gradientBackgroundNode { if let gradientBackgroundNode = self.gradientBackgroundNode {
return GradientBackgroundNode.CloneNode(parentNode: gradientBackgroundNode) return GradientBackgroundNode.CloneNode(parentNode: gradientBackgroundNode)
@ -1988,6 +2007,10 @@ final class WallpaperBackgroundNodeMergedImpl: ASDisplayNode, WallpaperBackgroun
return node return node
} }
func hasExtraBubbleBackground() -> Bool {
return false
}
func makeDimmedNode() -> ASDisplayNode? { func makeDimmedNode() -> ASDisplayNode? {
return nil return nil
} }