mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Emoji in chat folders
This commit is contained in:
@@ -20,11 +20,13 @@ private final class InlineStickerItem: Hashable {
|
||||
let emoji: ChatTextInputTextCustomEmojiAttribute
|
||||
let file: TelegramMediaFile?
|
||||
let fontSize: CGFloat
|
||||
let enableAnimation: Bool
|
||||
|
||||
init(emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, fontSize: CGFloat) {
|
||||
init(emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, fontSize: CGFloat, enableAnimation: Bool) {
|
||||
self.emoji = emoji
|
||||
self.file = file
|
||||
self.fontSize = fontSize
|
||||
self.enableAnimation = enableAnimation
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
@@ -42,6 +44,9 @@ private final class InlineStickerItem: Hashable {
|
||||
if lhs.fontSize != rhs.fontSize {
|
||||
return false
|
||||
}
|
||||
if lhs.enableAnimation != rhs.enableAnimation {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -65,19 +70,25 @@ public final class TextNodeWithEntities {
|
||||
public let renderer: MultiAnimationRenderer
|
||||
public let placeholderColor: UIColor
|
||||
public let attemptSynchronous: Bool
|
||||
public let emojiOffset: CGPoint
|
||||
public let fontSizeNorm: CGFloat
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
cache: AnimationCache,
|
||||
renderer: MultiAnimationRenderer,
|
||||
placeholderColor: UIColor,
|
||||
attemptSynchronous: Bool
|
||||
attemptSynchronous: Bool,
|
||||
emojiOffset: CGPoint = CGPoint(),
|
||||
fontSizeNorm: CGFloat = 17.0
|
||||
) {
|
||||
self.context = context
|
||||
self.cache = cache
|
||||
self.renderer = renderer
|
||||
self.placeholderColor = placeholderColor
|
||||
self.attemptSynchronous = attemptSynchronous
|
||||
self.emojiOffset = emojiOffset
|
||||
self.fontSizeNorm = fontSizeNorm
|
||||
}
|
||||
|
||||
public func withUpdatedPlaceholderColor(_ color: UIColor) -> Arguments {
|
||||
@@ -86,7 +97,8 @@ public final class TextNodeWithEntities {
|
||||
cache: self.cache,
|
||||
renderer: self.renderer,
|
||||
placeholderColor: color,
|
||||
attemptSynchronous: self.attemptSynchronous
|
||||
attemptSynchronous: self.attemptSynchronous,
|
||||
emojiOffset: self.emojiOffset
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -96,6 +108,8 @@ public final class TextNodeWithEntities {
|
||||
|
||||
private var enableLooping: Bool = true
|
||||
|
||||
public var resetEmojiToFirstFrameAutomatically: Bool = false
|
||||
|
||||
public var visibilityRect: CGRect? {
|
||||
didSet {
|
||||
if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibilityRect {
|
||||
@@ -110,7 +124,13 @@ public final class TextNodeWithEntities {
|
||||
} else {
|
||||
isItemVisible = false
|
||||
}
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && isItemVisible
|
||||
let isVisibleForAnimations = self.enableLooping && isItemVisible && itemLayer.enableAnimation
|
||||
if itemLayer.isVisibleForAnimations != isVisibleForAnimations {
|
||||
itemLayer.isVisibleForAnimations = isVisibleForAnimations
|
||||
if !isVisibleForAnimations && self.resetEmojiToFirstFrameAutomatically {
|
||||
itemLayer.reloadAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +161,7 @@ public final class TextNodeWithEntities {
|
||||
|
||||
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
|
||||
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
|
||||
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize), range: replacementRange)
|
||||
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize, enableAnimation: value.enableAnimation), range: replacementRange)
|
||||
updatedSubstring.addAttribute(originalTextAttributeKey, value: OriginalTextAttribute(id: originalTextId, string: string.attributedSubstring(from: range).string), range: replacementRange)
|
||||
originalTextId += 1
|
||||
|
||||
@@ -197,7 +217,7 @@ public final class TextNodeWithEntities {
|
||||
|
||||
if let maybeNode = maybeNode {
|
||||
if let applyArguments = applyArguments {
|
||||
maybeNode.updateInlineStickers(context: applyArguments.context, cache: applyArguments.cache, renderer: applyArguments.renderer, textLayout: layout, placeholderColor: applyArguments.placeholderColor, attemptSynchronousLoad: false)
|
||||
maybeNode.updateInlineStickers(context: applyArguments.context, cache: applyArguments.cache, renderer: applyArguments.renderer, textLayout: layout, placeholderColor: applyArguments.placeholderColor, attemptSynchronousLoad: false, emojiOffset: applyArguments.emojiOffset, fontSizeNorm: applyArguments.fontSizeNorm)
|
||||
}
|
||||
|
||||
return maybeNode
|
||||
@@ -205,7 +225,7 @@ public final class TextNodeWithEntities {
|
||||
let resultNode = TextNodeWithEntities(textNode: result)
|
||||
|
||||
if let applyArguments = applyArguments {
|
||||
resultNode.updateInlineStickers(context: applyArguments.context, cache: applyArguments.cache, renderer: applyArguments.renderer, textLayout: layout, placeholderColor: applyArguments.placeholderColor, attemptSynchronousLoad: false)
|
||||
resultNode.updateInlineStickers(context: applyArguments.context, cache: applyArguments.cache, renderer: applyArguments.renderer, textLayout: layout, placeholderColor: applyArguments.placeholderColor, attemptSynchronousLoad: false, emojiOffset: applyArguments.emojiOffset, fontSizeNorm: applyArguments.fontSizeNorm)
|
||||
}
|
||||
|
||||
return resultNode
|
||||
@@ -222,7 +242,7 @@ public final class TextNodeWithEntities {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor, attemptSynchronousLoad: Bool) {
|
||||
private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor, attemptSynchronousLoad: Bool, emojiOffset: CGPoint, fontSizeNorm: CGFloat) {
|
||||
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
|
||||
|
||||
var nextIndexById: [Int64: Int] = [:]
|
||||
@@ -241,9 +261,9 @@ public final class TextNodeWithEntities {
|
||||
let id = InlineStickerItemLayer.Key(id: stickerItem.emoji.fileId, index: index)
|
||||
validIds.append(id)
|
||||
|
||||
let itemSize = floorToScreenPixels(stickerItem.fontSize * 24.0 / 17.0)
|
||||
let itemSize = floorToScreenPixels(stickerItem.fontSize * 24.0 / fontSizeNorm)
|
||||
|
||||
var itemFrame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 1.0).center, size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0)
|
||||
var itemFrame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left + emojiOffset.x, dy: textLayout.insets.top + 1.0 + emojiOffset.y).center, size: CGSize()).insetBy(dx: -itemSize / 2.0, dy: -itemSize / 2.0)
|
||||
itemFrame.origin.x = floorToScreenPixels(itemFrame.origin.x)
|
||||
itemFrame.origin.y = floorToScreenPixels(itemFrame.origin.y)
|
||||
|
||||
@@ -256,8 +276,13 @@ public final class TextNodeWithEntities {
|
||||
itemLayer = InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor)
|
||||
self.inlineStickerItemLayers[id] = itemLayer
|
||||
self.textNode.layer.addSublayer(itemLayer)
|
||||
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && self.isItemVisible(itemRect: itemFrame)
|
||||
}
|
||||
itemLayer.enableAnimation = stickerItem.enableAnimation
|
||||
let isVisibleForAnimations = self.enableLooping && self.isItemVisible(itemRect: itemFrame) && itemLayer.enableAnimation
|
||||
if itemLayer.isVisibleForAnimations != isVisibleForAnimations {
|
||||
if !isVisibleForAnimations && self.resetEmojiToFirstFrameAutomatically {
|
||||
itemLayer.reloadAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
itemLayer.frame = itemFrame
|
||||
@@ -301,12 +326,19 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayer] = [:]
|
||||
public private(set) var dustNode: InvisibleInkDustNode?
|
||||
|
||||
public var resetEmojiToFirstFrameAutomatically: Bool = false
|
||||
|
||||
public var visibility: Bool = false {
|
||||
didSet {
|
||||
if !self.inlineStickerItemLayers.isEmpty && oldValue != self.visibility {
|
||||
for (_, itemLayer) in self.inlineStickerItemLayers {
|
||||
let isItemVisible: Bool = self.visibility
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && isItemVisible
|
||||
let isVisibleForAnimations = self.enableLooping && self.visibility && itemLayer.enableAnimation
|
||||
if itemLayer.isVisibleForAnimations != isVisibleForAnimations {
|
||||
itemLayer.isVisibleForAnimations = isVisibleForAnimations
|
||||
if !isVisibleForAnimations && self.resetEmojiToFirstFrameAutomatically {
|
||||
itemLayer.reloadAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,7 +407,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
|
||||
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
|
||||
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
|
||||
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize), range: replacementRange)
|
||||
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize, enableAnimation: value.enableAnimation), range: replacementRange)
|
||||
updatedSubstring.addAttribute(originalTextAttributeKey, value: OriginalTextAttribute(id: originalTextId, string: string.attributedSubstring(from: range).string), range: replacementRange)
|
||||
originalTextId += 1
|
||||
|
||||
@@ -437,7 +469,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
|
||||
var enableAnimations = true
|
||||
if let arguments = self.arguments {
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor)
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor, fontSizeNorm: arguments.fontSizeNorm)
|
||||
enableAnimations = arguments.context.sharedContext.energyUsageSettings.fullTranslucency
|
||||
}
|
||||
self.updateSpoilers(enableAnimations: enableAnimations, textLayout: layout)
|
||||
@@ -450,7 +482,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
return layout.size
|
||||
}
|
||||
|
||||
private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor) {
|
||||
private func updateInlineStickers(context: AccountContext, cache: AnimationCache, renderer: MultiAnimationRenderer, textLayout: TextNodeLayout?, placeholderColor: UIColor, fontSizeNorm: CGFloat) {
|
||||
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
|
||||
|
||||
var nextIndexById: [Int64: Int] = [:]
|
||||
@@ -469,7 +501,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
let id = InlineStickerItemLayer.Key(id: stickerItem.emoji.fileId, index: index)
|
||||
validIds.append(id)
|
||||
|
||||
let itemSide = floor(stickerItem.fontSize * 24.0 / 17.0)
|
||||
let itemSide = floor(stickerItem.fontSize * 24.0 / fontSizeNorm)
|
||||
var itemSize = CGSize(width: itemSide, height: itemSide)
|
||||
if let file = stickerItem.file, let customItemLayout = self.customItemLayout {
|
||||
itemSize = customItemLayout(itemSize, file)
|
||||
@@ -486,8 +518,15 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
itemLayer = InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: false, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor)
|
||||
self.inlineStickerItemLayers[id] = itemLayer
|
||||
self.layer.addSublayer(itemLayer)
|
||||
|
||||
itemLayer.isVisibleForAnimations = self.enableLooping && self.visibility
|
||||
}
|
||||
|
||||
itemLayer.enableAnimation = stickerItem.enableAnimation
|
||||
let isVisibleForAnimations = self.enableLooping && self.visibility && itemLayer.enableAnimation
|
||||
if itemLayer.isVisibleForAnimations != isVisibleForAnimations {
|
||||
itemLayer.isVisibleForAnimations = isVisibleForAnimations
|
||||
if !isVisibleForAnimations && self.resetEmojiToFirstFrameAutomatically {
|
||||
itemLayer.reloadAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
itemLayer.frame = itemFrame
|
||||
@@ -535,7 +574,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
let _ = apply()
|
||||
|
||||
if let arguments = self.arguments {
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor)
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor, fontSizeNorm: arguments.fontSizeNorm)
|
||||
}
|
||||
|
||||
return ImmediateTextNodeLayoutInfo(size: layout.size, truncated: layout.truncated, numberOfLines: layout.numberOfLines)
|
||||
@@ -550,7 +589,7 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
let _ = apply()
|
||||
|
||||
if let arguments = self.arguments {
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor)
|
||||
self.updateInlineStickers(context: arguments.context, cache: arguments.cache, renderer: arguments.renderer, textLayout: layout, placeholderColor: arguments.placeholderColor, fontSizeNorm: arguments.fontSizeNorm)
|
||||
}
|
||||
|
||||
return layout
|
||||
|
||||
Reference in New Issue
Block a user