Various improvements

This commit is contained in:
Ilya Laktyushin
2024-09-26 02:32:28 +04:00
parent cd7fc1cf9a
commit a30ab38ce4
8 changed files with 730 additions and 104 deletions

View File

@@ -30,6 +30,8 @@ swift_library(
"//submodules/Markdown",
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/TextNodeWithEntities",
"//submodules/InvisibleInkDustNode",
],
visibility = [
"//visibility:public",

View File

@@ -20,6 +20,8 @@ import ShimmerEffect
import Markdown
import ChatMessageBubbleContentNode
import ChatMessageItemCommon
import TextNodeWithEntities
import InvisibleInkDustNode
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id) -> NSAttributedString? {
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: false, forForumOverview: false)
@@ -34,7 +36,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
private let mediaBackgroundMaskNode: ASImageNode
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
private let titleNode: TextNode
private let subtitleNode: TextNode
private let subtitleNode: TextNodeWithEntities
private var dustNode: InvisibleInkDustNode?
private let placeholderNode: StickerShimmerEffectNode
private let animationNode: AnimatedStickerNode
@@ -60,6 +63,16 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
if wasVisible != isVisible {
self.visibilityStatus = isVisible
switch self.visibility {
case .none:
self.subtitleNode.visibilityRect = nil
case let .visible(_, subRect):
var subRect = subRect
subRect.origin.x = 0.0
subRect.size.width = 10000.0
self.subtitleNode.visibilityRect = subRect
}
}
}
}
@@ -88,9 +101,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.titleNode.isUserInteractionEnabled = false
self.titleNode.displaysAsynchronously = false
self.subtitleNode = TextNode()
self.subtitleNode.isUserInteractionEnabled = false
self.subtitleNode.displaysAsynchronously = false
self.subtitleNode = TextNodeWithEntities()
self.subtitleNode.textNode.isUserInteractionEnabled = false
self.subtitleNode.textNode.displaysAsynchronously = false
self.buttonNode = HighlightTrackingButtonNode()
self.buttonNode.clipsToBounds = true
@@ -120,8 +133,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.addSubnode(self.labelNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.subtitleNode)
self.addSubnode(self.subtitleNode)
self.addSubnode(self.subtitleNode.textNode)
self.addSubnode(self.placeholderNode)
self.addSubnode(self.animationNode)
@@ -236,7 +248,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeSubtitleLayout = TextNode.asyncLayout(self.subtitleNode)
let makeSubtitleLayout = TextNodeWithEntities.asyncLayout(self.subtitleNode)
let makeButtonTitleLayout = TextNode.asyncLayout(self.buttonTitleNode)
let makeRibbonTextLayout = TextNode.asyncLayout(self.ribbonTextNode)
@@ -259,6 +271,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
var animationFile: TelegramMediaFile?
var title = item.presentationData.strings.Notification_PremiumGift_Title
var text = ""
var entities: [MessageTextEntity] = []
var buttonTitle = item.presentationData.strings.Notification_PremiumGift_View
var ribbonTitle = ""
var hasServiceMessage = true
@@ -329,8 +342,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
buttonTitle = item.presentationData.strings.Notification_PremiumPrize_View
hasServiceMessage = false
}
case let .starGift(gift, convertStars, giftText, entities, nameHidden, savedToProfile, converted):
let _ = nameHidden
case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted):
//TODO:localize
if !incoming {
buttonTitle = ""
@@ -339,7 +351,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
title = "Gift from \(authorName)"
if let giftText, !giftText.isEmpty {
text = giftText
let _ = entities
entities = giftEntities ?? []
} else {
if incoming {
if converted {
@@ -386,15 +398,20 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: primaryTextColor),
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
linkAttribute: { url in
return ("URL", url)
}
), textAlignment: .center)
let attributedText: NSAttributedString
if let _ = animationFile {
attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: Font.regular(13.0), linkFont: Font.regular(13.0), boldFont: Font.semibold(13.0), italicFont: Font.italic(13.0), boldItalicFont: Font.semiboldItalic(13.0), fixedFont: Font.monospace(13.0), blockQuoteFont: Font.regular(13.0), message: nil)
} else {
attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: primaryTextColor),
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
linkAttribute: { url in
return ("URL", url)
}
), textAlignment: .center)
}
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
@@ -511,7 +528,13 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let _ = labelApply()
let _ = titleApply()
let _ = subtitleApply()
let _ = subtitleApply(TextNodeWithEntities.Arguments(
context: item.context,
cache: item.controllerInteraction.presentationContext.animationCache,
renderer: item.controllerInteraction.presentationContext.animationRenderer,
placeholderColor: item.presentationData.theme.theme.chat.message.freeform.withWallpaper.reactionInactiveBackground,
attemptSynchronous: synchronousLoads
))
let _ = buttonTitleApply()
let _ = ribbonTextApply()
@@ -522,7 +545,26 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
strongSelf.titleNode.frame = titleFrame
let subtitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY + textSpacing), size: subtitleLayout.size)
strongSelf.subtitleNode.frame = subtitleFrame
strongSelf.subtitleNode.textNode.frame = subtitleFrame
if !subtitleLayout.spoilers.isEmpty {
let dustColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
let dustNode: InvisibleInkDustNode
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: item.context.sharedContext.energyUsageSettings.fullTranslucency)
dustNode.isUserInteractionEnabled = false
strongSelf.dustNode = dustNode
strongSelf.insertSubnode(dustNode, aboveSubnode: strongSelf.subtitleNode.textNode)
}
dustNode.frame = subtitleFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 1.0)
dustNode.update(size: dustNode.frame.size, color: dustColor, textColor: dustColor, rects: subtitleLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: subtitleLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
} else if let dustNode = strongSelf.dustNode {
dustNode.removeFromSupernode()
strongSelf.dustNode = nil
}
let buttonTitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonTitleLayout.size.width) / 2.0), y: subtitleFrame.maxY + 18.0), size: buttonTitleLayout.size)
strongSelf.buttonTitleNode.frame = buttonTitleFrame
@@ -616,6 +658,16 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
if let (rect, size) = strongSelf.absoluteRect {
strongSelf.updateAbsoluteRect(rect, within: size)
}
switch strongSelf.visibility {
case .none:
strongSelf.subtitleNode.visibilityRect = nil
case let .visible(_, subRect):
var subRect = subRect
subRect.origin.x = 0.0
subRect.size.width = 10000.0
strongSelf.subtitleNode.visibilityRect = subRect
}
}
})
})
@@ -742,6 +794,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.updateVisibility()
}
private var internalPlayedOnce = false
private func updateVisibility() {
guard let item = self.item else {
return
@@ -772,9 +825,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
}
}
if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) {
if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) && !self.internalPlayedOnce {
item.controllerInteraction.seenOneTimeAnimatedMedia.insert(item.message.id)
self.animationNode.playOnce()
self.internalPlayedOnce = true
Queue.mainQueue().after(0.05) {
if let itemNode = self.itemNode, let supernode = itemNode.supernode {