mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Support colored emoji
This commit is contained in:
parent
71bed257bb
commit
2cb2717ce7
@ -29,7 +29,17 @@ public func reactionStaticImage(context: AccountContext, animation: TelegramMedi
|
||||
} else {
|
||||
type = .still
|
||||
}
|
||||
let fetchFrame = animationCacheFetchFile(context: context, resource: MediaResourceReference.standalone(resource: animation.resource), type: type, keyframeOnly: true)
|
||||
|
||||
var customColor: UIColor?
|
||||
for attribute in animation.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
customColor = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fetchFrame = animationCacheFetchFile(context: context, resource: MediaResourceReference.standalone(resource: animation.resource), type: type, keyframeOnly: true, customColor: customColor)
|
||||
|
||||
class AnimationCacheItemWriterImpl: AnimationCacheItemWriter {
|
||||
let queue: Queue
|
||||
|
@ -212,11 +212,13 @@ public final class TextNodeLayout: NSObject {
|
||||
public let range: NSRange
|
||||
public let rect: CGRect
|
||||
public let value: AnyHashable
|
||||
public let textColor: UIColor
|
||||
|
||||
public init(range: NSRange, rect: CGRect, value: AnyHashable) {
|
||||
public init(range: NSRange, rect: CGRect, value: AnyHashable, textColor: UIColor) {
|
||||
self.range = range
|
||||
self.rect = rect
|
||||
self.value = value
|
||||
self.textColor = textColor
|
||||
}
|
||||
|
||||
public static func ==(lhs: EmbeddedItem, rhs: EmbeddedItem) -> Bool {
|
||||
@ -229,6 +231,9 @@ public final class TextNodeLayout: NSObject {
|
||||
if lhs.value != rhs.value {
|
||||
return false
|
||||
}
|
||||
if lhs.textColor != rhs.textColor {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -301,7 +306,18 @@ public final class TextNodeLayout: NSObject {
|
||||
spoilers.append(contentsOf: line.spoilers.map { ( $0.range, $0.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)) })
|
||||
spoilerWords.append(contentsOf: line.spoilerWords.map { ( $0.range, $0.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)) })
|
||||
for embeddedItem in line.embeddedItems {
|
||||
embeddedItems.append(TextNodeLayout.EmbeddedItem(range: embeddedItem.range, rect: embeddedItem.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY), value: embeddedItem.item))
|
||||
var textColor: UIColor?
|
||||
if let attributedString = attributedString, embeddedItem.range.location < attributedString.length {
|
||||
if let color = attributedString.attribute(.foregroundColor, at: embeddedItem.range.location, effectiveRange: nil) as? UIColor {
|
||||
textColor = color
|
||||
}
|
||||
if textColor == nil {
|
||||
if let color = attributedString.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor {
|
||||
textColor = color
|
||||
}
|
||||
}
|
||||
}
|
||||
embeddedItems.append(TextNodeLayout.EmbeddedItem(range: embeddedItem.range, rect: embeddedItem.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY), value: embeddedItem.item, textColor: textColor ?? .black))
|
||||
}
|
||||
}
|
||||
self.hasRTL = hasRTL
|
||||
|
@ -100,7 +100,7 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
|
||||
var instantPageMedia: (TelegramMediaWebpage, [InstantPageGalleryEntry])?
|
||||
if message.media.isEmpty, let entities = message.textEntitiesAttribute?.entities, entities.count == 1, let firstEntity = entities.first, case let .CustomEmoji(_, fileId) = firstEntity.type, let file = message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, reference) = attribute {
|
||||
if case let .CustomEmoji(_, _, _, reference) = attribute {
|
||||
if let reference = reference {
|
||||
return .stickerPack(reference)
|
||||
}
|
||||
|
@ -2285,7 +2285,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
var packReference: StickerPackReference?
|
||||
if let file = file {
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, reference) = attribute {
|
||||
if case let .CustomEmoji(_, _, _, reference) = attribute {
|
||||
packReference = reference
|
||||
}
|
||||
}
|
||||
@ -2357,7 +2357,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
tapAction: { [weak state, weak environment] _, _ in
|
||||
if let emojiFile = state?.emojiFile, let controller = environment?.controller() as? PremiumIntroScreen, let navigationController = controller.navigationController as? NavigationController {
|
||||
for attribute in emojiFile.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
|
||||
let controller = accountContext.sharedContext.makeStickerPackScreen(context: accountContext, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: loadedEmojiPack.flatMap { [$0] } ?? [], parentNavigationController: navigationController, sendSticker: { _, _, _ in
|
||||
return false
|
||||
})
|
||||
|
@ -425,7 +425,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
for item in featuredEmojiPack.topItems {
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if filterList.contains(alt) {
|
||||
filteredFiles.append(item.file)
|
||||
}
|
||||
@ -1395,7 +1395,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
if !alt.isEmpty, let keyword = allEmoticons[alt] {
|
||||
result.append((alt, item.file, keyword))
|
||||
@ -1424,7 +1424,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
content: .animation(animationData),
|
||||
itemFile: itemFile, subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
@ -1742,7 +1742,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
if additionalAnimation == nil && itemNode.item.isCustom {
|
||||
outer: for attribute in itemNode.item.stillAnimation.attributes {
|
||||
if case let .CustomEmoji(_, alt, _) = attribute {
|
||||
if case let .CustomEmoji(_, _, alt, _) = attribute {
|
||||
if let availableReactions = self.availableReactions {
|
||||
for availableReaction in availableReactions.reactions {
|
||||
if availableReaction.value == .builtin(alt) {
|
||||
|
@ -203,7 +203,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, _):
|
||||
case let .CustomEmoji(_, _, displayText, _):
|
||||
text = displayText
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
@ -229,7 +229,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, _):
|
||||
case let .CustomEmoji(_, _, displayText, _):
|
||||
text = displayText
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
@ -354,7 +354,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
||||
} else {
|
||||
updateItemLayerPlaceholder = true
|
||||
itemTransition = .immediate
|
||||
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
itemLayer = EmojiPagerContentComponent.View.ItemLayer(
|
||||
item: EmojiPagerContentComponent.Item(
|
||||
@ -363,7 +363,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
),
|
||||
context: context,
|
||||
attemptSynchronousLoad: attemptSynchronousLoads,
|
||||
@ -425,6 +425,15 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
||||
self.visibleItemLayers[itemId] = itemLayer
|
||||
}
|
||||
|
||||
switch itemLayer.item.tintMode {
|
||||
case .none:
|
||||
break
|
||||
case .accent:
|
||||
itemLayer.layerTintColor = theme.list.itemAccentColor.cgColor
|
||||
case .primary:
|
||||
itemLayer.layerTintColor = theme.list.itemPrimaryTextColor.cgColor
|
||||
}
|
||||
|
||||
var itemFrame = itemLayout.frame(itemIndex: index)
|
||||
|
||||
itemFrame.origin.x += floor((itemFrame.width - itemVisibleFitSize.width) / 2.0)
|
||||
|
@ -66,7 +66,7 @@ private struct StickerPackPreviewGridTransaction {
|
||||
let scrollToItem: GridNodeScrollToItem?
|
||||
|
||||
init(previousList: [StickerPackPreviewGridEntry], list: [StickerPackPreviewGridEntry], context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, strings: PresentationStrings, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, scrollToItem: GridNodeScrollToItem?) {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
|
||||
|
||||
self.deletions = deleteIndices
|
||||
self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction, theme: theme, strings: strings, animationCache: animationCache, animationRenderer: animationRenderer), previousIndex: $0.2) }
|
||||
|
@ -112,7 +112,8 @@ func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAtt
|
||||
result.append(.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer))
|
||||
case let .documentAttributeCustomEmoji(flags, alt, stickerSet):
|
||||
let isFree = (flags & (1 << 0)) != 0
|
||||
result.append(.CustomEmoji(isPremium: !isFree, alt: alt, packReference: StickerPackReference(apiInputSet: stickerSet)))
|
||||
let isSingleColor = (flags & (1 << 1)) != 0
|
||||
result.append(.CustomEmoji(isPremium: !isFree, isSingleColor: isSingleColor, alt: alt, packReference: StickerPackReference(apiInputSet: stickerSet)))
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -190,7 +190,7 @@ public struct TelegramMediaVideoFlags: OptionSet {
|
||||
public static let supportsStreaming = TelegramMediaVideoFlags(rawValue: 1 << 1)
|
||||
}
|
||||
|
||||
public struct StickerMaskCoords: PostboxCoding {
|
||||
public struct StickerMaskCoords: PostboxCoding, Equatable {
|
||||
public let n: Int32
|
||||
public let x: Double
|
||||
public let y: Double
|
||||
@ -218,7 +218,7 @@ public struct StickerMaskCoords: PostboxCoding {
|
||||
}
|
||||
}
|
||||
|
||||
public enum TelegramMediaFileAttribute: PostboxCoding {
|
||||
public enum TelegramMediaFileAttribute: PostboxCoding, Equatable {
|
||||
case FileName(fileName: String)
|
||||
case Sticker(displayText: String, packReference: StickerPackReference?, maskData: StickerMaskCoords?)
|
||||
case ImageSize(size: PixelDimensions)
|
||||
@ -229,7 +229,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
|
||||
case hintFileIsLarge
|
||||
case hintIsValidated
|
||||
case NoPremium
|
||||
case CustomEmoji(isPremium: Bool, alt: String, packReference: StickerPackReference?)
|
||||
case CustomEmoji(isPremium: Bool, isSingleColor: Bool, alt: String, packReference: StickerPackReference?)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0)
|
||||
@ -260,7 +260,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
|
||||
case typeNoPremium:
|
||||
self = .NoPremium
|
||||
case typeCustomEmoji:
|
||||
self = .CustomEmoji(isPremium: decoder.decodeBoolForKey("ip", orElse: true), alt: decoder.decodeStringForKey("dt", orElse: ""), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference)
|
||||
self = .CustomEmoji(isPremium: decoder.decodeBoolForKey("ip", orElse: true), isSingleColor: decoder.decodeBoolForKey("sc", orElse: false), alt: decoder.decodeStringForKey("dt", orElse: ""), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference)
|
||||
default:
|
||||
preconditionFailure()
|
||||
}
|
||||
@ -317,9 +317,10 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
|
||||
encoder.encodeInt32(typeHintIsValidated, forKey: "t")
|
||||
case .NoPremium:
|
||||
encoder.encodeInt32(typeNoPremium, forKey: "t")
|
||||
case let .CustomEmoji(isPremium, alt, packReference):
|
||||
case let .CustomEmoji(isPremium, isSingleColor, alt, packReference):
|
||||
encoder.encodeInt32(typeCustomEmoji, forKey: "t")
|
||||
encoder.encodeBool(isPremium, forKey: "ip")
|
||||
encoder.encodeBool(isSingleColor, forKey: "sc")
|
||||
encoder.encodeString(alt, forKey: "dt")
|
||||
if let packReference = packReference {
|
||||
encoder.encodeObject(packReference, forKey: "pr")
|
||||
@ -652,7 +653,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
||||
|
||||
public var isPremiumEmoji: Bool {
|
||||
for attribute in self.attributes {
|
||||
if case let .CustomEmoji(isPremium, _, _) = attribute {
|
||||
if case let .CustomEmoji(isPremium, _, _, _) = attribute {
|
||||
return isPremium
|
||||
}
|
||||
}
|
||||
@ -737,6 +738,10 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
||||
return false
|
||||
}
|
||||
|
||||
if self.attributes != other.attributes {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -442,7 +442,10 @@ public final class EmojiStatusComponent: Component {
|
||||
var accentTint = false
|
||||
if let _ = emojiThemeColor {
|
||||
for attribute in emojiFile.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
|
||||
if isSingleColor {
|
||||
accentTint = true
|
||||
}
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
if id == 773947703670341676 || id == 2964141614563343 {
|
||||
@ -456,8 +459,10 @@ public final class EmojiStatusComponent: Component {
|
||||
}
|
||||
if accentTint {
|
||||
animationLayer.contentTintColor = emojiThemeColor
|
||||
animationLayer.dynamicColor = emojiThemeColor
|
||||
} else {
|
||||
animationLayer.contentTintColor = nil
|
||||
animationLayer.dynamicColor = nil
|
||||
}
|
||||
|
||||
animationLayer.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
@ -329,7 +329,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
for item in featuredEmojiPack.topItems {
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if filterList.contains(alt) {
|
||||
filteredFiles.append(item.file)
|
||||
}
|
||||
@ -487,7 +487,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
}
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
if !alt.isEmpty, let keyword = allEmoticons[alt] {
|
||||
result.append((alt, item.file, keyword))
|
||||
@ -516,7 +516,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
content: .animation(animationData),
|
||||
itemFile: itemFile, subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
@ -645,7 +645,10 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
} else if let itemFile = item.itemFile {
|
||||
var useCleanEffect = false
|
||||
for attribute in itemFile.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
|
||||
if isSingleColor {
|
||||
useCleanEffect = true
|
||||
}
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
if id == 773947703670341676 || id == 2964141614563343 {
|
||||
@ -692,8 +695,13 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
placeholderColor: UIColor(white: 0.0, alpha: 0.0),
|
||||
pointSize: CGSize(width: 32.0, height: 32.0)
|
||||
)
|
||||
if item.accentTint {
|
||||
switch item.tintMode {
|
||||
case .accent:
|
||||
baseItemLayer.contentTintColor = self.presentationData.theme.list.itemAccentColor
|
||||
case .primary:
|
||||
baseItemLayer.contentTintColor = self.presentationData.theme.list.itemPrimaryTextColor
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
|
||||
if let sublayers = animationLayer.sublayers {
|
||||
@ -1001,7 +1009,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
if let itemFile = previewItem.item.itemFile {
|
||||
attributeLoop: for attribute in itemFile.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
emojiString = alt
|
||||
break attributeLoop
|
||||
default:
|
||||
@ -1165,7 +1173,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
if let itemFile = item.itemFile {
|
||||
attributeLoop: for attribute in itemFile.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
emojiString = alt
|
||||
break attributeLoop
|
||||
default:
|
||||
|
@ -59,7 +59,7 @@ public final class EmojiSuggestionsComponent: Component {
|
||||
}
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if alt == query || (!normalizedQuery.isEmpty && alt == normalizedQuery) {
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
if !existingIds.contains(item.file.fileId) {
|
||||
@ -78,7 +78,7 @@ public final class EmojiSuggestionsComponent: Component {
|
||||
for item in featuredPack.topItems {
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if alt == query || (!normalizedQuery.isEmpty && alt == normalizedQuery) {
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
if !existingIds.contains(item.file.fileId) {
|
||||
|
@ -96,7 +96,7 @@ public extension AnimationCacheAnimationType {
|
||||
}
|
||||
}
|
||||
|
||||
public func animationCacheFetchFile(context: AccountContext, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool) -> (AnimationCacheFetchOptions) -> Disposable {
|
||||
public func animationCacheFetchFile(context: AccountContext, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool, customColor: UIColor?) -> (AnimationCacheFetchOptions) -> Disposable {
|
||||
return { options in
|
||||
let source = AnimatedStickerResourceSource(account: context.account, resource: resource.resource, fitzModifier: nil, isVideo: false)
|
||||
|
||||
@ -107,15 +107,15 @@ public func animationCacheFetchFile(context: AccountContext, resource: MediaReso
|
||||
|
||||
switch type {
|
||||
case .video:
|
||||
cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly)
|
||||
cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
|
||||
case .lottie:
|
||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
|
||||
options.writer.finish()
|
||||
return
|
||||
}
|
||||
cacheLottieAnimation(data: data, width: Int(options.size.width), height: Int(options.size.height), keyframeOnly: keyframeOnly, writer: options.writer, firstFrameOnly: options.firstFrameOnly)
|
||||
cacheLottieAnimation(data: data, width: Int(options.size.width), height: Int(options.size.height), keyframeOnly: keyframeOnly, writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
|
||||
case .still:
|
||||
cacheStillSticker(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer)
|
||||
cacheStillSticker(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, customColor: customColor)
|
||||
}
|
||||
})
|
||||
|
||||
@ -153,6 +153,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
private let pixelSize: CGSize
|
||||
|
||||
private var isDisplayingPlaceholder: Bool = false
|
||||
private var didProcessTintColor: Bool = false
|
||||
|
||||
public private(set) var file: TelegramMediaFile?
|
||||
private var infoDisposable: Disposable?
|
||||
@ -168,6 +169,14 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
}
|
||||
}
|
||||
|
||||
public var dynamicColor: UIColor? {
|
||||
didSet {
|
||||
if self.dynamicColor != oldValue {
|
||||
self.updateTintColor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var currentLoopCount: Int = 0
|
||||
|
||||
private var isInHierarchyValue: Bool = false
|
||||
@ -179,13 +188,14 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, loopCount: Int? = nil) {
|
||||
public init(context: AccountContext, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) {
|
||||
self.context = context
|
||||
self.emoji = emoji
|
||||
self.cache = cache
|
||||
self.renderer = renderer
|
||||
self.unique = unique
|
||||
self.placeholderColor = placeholderColor
|
||||
self.dynamicColor = dynamicColor
|
||||
self.loopCount = loopCount
|
||||
|
||||
let scale = min(2.0, UIScreenScale)
|
||||
@ -239,7 +249,18 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
|
||||
private func updateTintColor() {
|
||||
if !self.isDisplayingPlaceholder {
|
||||
self.layerTintColor = self.contentTintColor?.cgColor
|
||||
var customColor = self.contentTintColor
|
||||
if let file = self.file {
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
customColor = self.dynamicColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.layerTintColor = customColor?.cgColor
|
||||
} else {
|
||||
self.layerTintColor = nil
|
||||
}
|
||||
@ -311,10 +332,17 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
|
||||
self.loadAnimation()
|
||||
} else {
|
||||
var isTemplate = false
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
isTemplate = isSingleColor
|
||||
}
|
||||
}
|
||||
|
||||
let pointSize = self.pointSize
|
||||
let placeholderColor = self.placeholderColor
|
||||
let isThumbnailCancelled = Atomic<Bool>(value: false)
|
||||
self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(context: self.context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true), completion: { [weak self] result, isFinal in
|
||||
self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(context: self.context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true, customColor: isTemplate ? .white : nil), completion: { [weak self] result, isFinal in
|
||||
if !result {
|
||||
MultiAnimationRendererImpl.firstFrameQueue.async {
|
||||
let image = generateStickerPlaceholderImage(data: file.immediateThumbnailData, size: pointSize, scale: min(2.0, UIScreenScale), imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), backgroundColor: nil, foregroundColor: placeholderColor)
|
||||
@ -350,11 +378,18 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
return
|
||||
}
|
||||
|
||||
var isTemplate = false
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
isTemplate = isSingleColor
|
||||
}
|
||||
}
|
||||
|
||||
let context = self.context
|
||||
if file.isAnimatedSticker || file.isVideoEmoji {
|
||||
let keyframeOnly = self.pixelSize.width >= 120.0
|
||||
|
||||
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly))
|
||||
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly, customColor: isTemplate ? .white : nil))
|
||||
} else {
|
||||
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: { options in
|
||||
let dataDisposable = context.account.postbox.mediaBox.resourceData(file.resource).start(next: { result in
|
||||
@ -362,7 +397,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
return
|
||||
}
|
||||
|
||||
cacheStillSticker(path: result.path, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer)
|
||||
cacheStillSticker(path: result.path, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, customColor: isTemplate ? .white : nil)
|
||||
})
|
||||
|
||||
let fetchDisposable = freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .customEmoji(media: file), resource: file.resource).start()
|
||||
@ -405,6 +440,10 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
|
||||
self.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
} else {
|
||||
if !self.didProcessTintColor {
|
||||
//self.didProcessTintColor = true
|
||||
self.updateTintColor()
|
||||
}
|
||||
self.contents = contents
|
||||
}
|
||||
|
||||
@ -433,6 +472,10 @@ public final class EmojiTextAttachmentView: UIView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func updateTextColor(_ textColor: UIColor) {
|
||||
self.contentLayer.dynamicColor = textColor
|
||||
}
|
||||
|
||||
override public func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
|
@ -222,14 +222,16 @@ public final class EntityKeyboardAnimationData: Equatable {
|
||||
public let dimensions: CGSize
|
||||
public let immediateThumbnailData: Data?
|
||||
public let isReaction: Bool
|
||||
public let isTemplate: Bool
|
||||
|
||||
public init(id: Id, type: ItemType, resource: MediaResourceReference, dimensions: CGSize, immediateThumbnailData: Data?, isReaction: Bool) {
|
||||
public init(id: Id, type: ItemType, resource: MediaResourceReference, dimensions: CGSize, immediateThumbnailData: Data?, isReaction: Bool, isTemplate: Bool) {
|
||||
self.id = id
|
||||
self.type = type
|
||||
self.resource = resource
|
||||
self.dimensions = dimensions
|
||||
self.immediateThumbnailData = immediateThumbnailData
|
||||
self.isReaction = isReaction
|
||||
self.isTemplate = isTemplate
|
||||
}
|
||||
|
||||
public convenience init(file: TelegramMediaFile, isReaction: Bool = false) {
|
||||
@ -241,7 +243,13 @@ public final class EntityKeyboardAnimationData: Equatable {
|
||||
} else {
|
||||
type = .still
|
||||
}
|
||||
self.init(id: .file(file.fileId), type: type, resource: .standalone(resource: file.resource), dimensions: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), immediateThumbnailData: file.immediateThumbnailData, isReaction: isReaction)
|
||||
var isTemplate = false
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
isTemplate = isSingleColor
|
||||
}
|
||||
}
|
||||
self.init(id: .file(file.fileId), type: type, resource: .standalone(resource: file.resource), dimensions: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), immediateThumbnailData: file.immediateThumbnailData, isReaction: isReaction, isTemplate: isTemplate)
|
||||
}
|
||||
|
||||
public static func ==(lhs: EntityKeyboardAnimationData, rhs: EntityKeyboardAnimationData) -> Bool {
|
||||
@ -2201,12 +2209,18 @@ public final class EmojiPagerContentComponent: Component {
|
||||
case premium
|
||||
}
|
||||
|
||||
public enum TintMode {
|
||||
case none
|
||||
case accent
|
||||
case primary
|
||||
}
|
||||
|
||||
public let animationData: EntityKeyboardAnimationData?
|
||||
public let content: ItemContent
|
||||
public let itemFile: TelegramMediaFile?
|
||||
public let subgroupId: Int32?
|
||||
public let icon: Icon
|
||||
public let accentTint: Bool
|
||||
public let tintMode: TintMode
|
||||
|
||||
public init(
|
||||
animationData: EntityKeyboardAnimationData?,
|
||||
@ -2214,14 +2228,14 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: TelegramMediaFile?,
|
||||
subgroupId: Int32?,
|
||||
icon: Icon,
|
||||
accentTint: Bool
|
||||
tintMode: TintMode
|
||||
) {
|
||||
self.animationData = animationData
|
||||
self.content = content
|
||||
self.itemFile = itemFile
|
||||
self.subgroupId = subgroupId
|
||||
self.icon = icon
|
||||
self.accentTint = accentTint
|
||||
self.tintMode = tintMode
|
||||
}
|
||||
|
||||
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||
@ -2243,7 +2257,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
if lhs.icon != rhs.icon {
|
||||
return false
|
||||
}
|
||||
if lhs.accentTint != rhs.accentTint {
|
||||
if lhs.tintMode != rhs.tintMode {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -2894,14 +2908,14 @@ public final class EmojiPagerContentComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.disposable = renderer.add(target: strongSelf, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, unique: false, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: pixelSize.width >= 120.0))
|
||||
strongSelf.disposable = renderer.add(target: strongSelf, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, unique: false, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: pixelSize.width >= 120.0, customColor: animationData.isTemplate ? .white : nil))
|
||||
}
|
||||
|
||||
if attemptSynchronousLoad {
|
||||
if !renderer.loadFirstFrameSynchronously(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize) {
|
||||
self.updateDisplayPlaceholder(displayPlaceholder: true)
|
||||
|
||||
self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true), completion: { [weak self] success, isFinal in
|
||||
self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in
|
||||
if !isFinal {
|
||||
if !success {
|
||||
Queue.mainQueue().async {
|
||||
@ -2931,7 +2945,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
loadAnimation()
|
||||
}
|
||||
} else {
|
||||
self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true), completion: { [weak self] success, isFinal in
|
||||
self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in
|
||||
if !isFinal {
|
||||
if !success {
|
||||
Queue.mainQueue().async {
|
||||
@ -5337,9 +5351,12 @@ public final class EmojiPagerContentComponent: Component {
|
||||
|
||||
itemLayer.update(transition: transition, size: itemFrame.size, badge: badge, blurredBadgeColor: UIColor(white: 0.0, alpha: 0.1), blurredBadgeBackgroundColor: keyboardChildEnvironment.theme.list.plainBackgroundColor)
|
||||
|
||||
if item.accentTint {
|
||||
switch item.tintMode {
|
||||
case .accent:
|
||||
itemLayer.layerTintColor = keyboardChildEnvironment.theme.list.itemAccentColor.cgColor
|
||||
} else {
|
||||
case .primary:
|
||||
itemLayer.layerTintColor = keyboardChildEnvironment.theme.list.itemPrimaryTextColor.cgColor
|
||||
case .none:
|
||||
itemLayer.layerTintColor = nil
|
||||
}
|
||||
|
||||
@ -5373,7 +5390,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.visibleItemSelectionLayers[itemId] = itemSelectionLayer
|
||||
}
|
||||
|
||||
if item.accentTint {
|
||||
if case .accent = item.tintMode {
|
||||
itemSelectionLayer.backgroundColor = keyboardChildEnvironment.theme.list.itemAccentColor.withMultipliedAlpha(0.1).cgColor
|
||||
itemSelectionLayer.tintContainerLayer.backgroundColor = UIColor.clear.cgColor
|
||||
} else {
|
||||
@ -6392,7 +6409,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: nil,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: .none
|
||||
)
|
||||
|
||||
let groupId = "recent"
|
||||
@ -6411,13 +6428,16 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
existingIds.insert(file.fileId)
|
||||
|
||||
var accentTint = false
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .accent
|
||||
}
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
if id == 773947703670341676 || id == 2964141614563343 {
|
||||
accentTint = true
|
||||
tintMode = .accent
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -6434,7 +6454,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: accentTint
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
@ -6448,7 +6468,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: nil,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: .none
|
||||
)
|
||||
|
||||
let groupId = "recent"
|
||||
@ -6467,13 +6487,16 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
existingIds.insert(file.fileId)
|
||||
|
||||
var accentTint = false
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .accent
|
||||
}
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
if id == 773947703670341676 || id == 2964141614563343 {
|
||||
accentTint = true
|
||||
tintMode = .accent
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -6490,7 +6513,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: accentTint
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
@ -6510,13 +6533,16 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
existingIds.insert(file.fileId)
|
||||
|
||||
var accentTint = false
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .accent
|
||||
}
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
if id == 773947703670341676 || id == 2964141614563343 {
|
||||
accentTint = true
|
||||
tintMode = .accent
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -6533,7 +6559,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: accentTint
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
@ -6559,13 +6585,16 @@ public final class EmojiPagerContentComponent: Component {
|
||||
|
||||
let resultItem: EmojiPagerContentComponent.Item
|
||||
|
||||
var accentTint = false
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .accent
|
||||
}
|
||||
switch packReference {
|
||||
case let .id(id, _):
|
||||
if id == 773947703670341676 || id == 2964141614563343 {
|
||||
accentTint = true
|
||||
tintMode = .accent
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -6580,7 +6609,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: accentTint
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
@ -6637,6 +6666,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
icon = .none
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in reactionItem.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationFile = reactionItem.file
|
||||
let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
@ -6645,7 +6683,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: animationFile,
|
||||
subgroupId: nil,
|
||||
icon: icon,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let groupId = "recent"
|
||||
@ -6692,6 +6730,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
icon = .none
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in reactionItem.selectAnimation.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationFile = reactionItem.selectAnimation
|
||||
let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
@ -6700,7 +6747,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: animationFile,
|
||||
subgroupId: nil,
|
||||
icon: icon,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
if hasPremium {
|
||||
@ -6768,6 +6815,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in animationFile.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -6775,7 +6831,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: animationFile,
|
||||
subgroupId: nil,
|
||||
icon: icon,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let groupId = "popular"
|
||||
@ -6811,6 +6867,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
let resultItem: EmojiPagerContentComponent.Item
|
||||
switch item.content {
|
||||
case let .file(file):
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: file)
|
||||
resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -6818,7 +6883,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
case let .text(text):
|
||||
resultItem = EmojiPagerContentComponent.Item(
|
||||
@ -6827,7 +6892,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: nil,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: .none
|
||||
)
|
||||
}
|
||||
|
||||
@ -6857,6 +6922,19 @@ public final class EmojiPagerContentComponent: Component {
|
||||
icon = .locked
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
if isStatusSelection {
|
||||
tintMode = .accent
|
||||
} else {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -6864,7 +6942,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: icon,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let supergroupId = entry.index.collectionId
|
||||
@ -6900,7 +6978,8 @@ public final class EmojiPagerContentComponent: Component {
|
||||
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
|
||||
dimensions: thumbnail.dimensions.cgSize,
|
||||
immediateThumbnailData: info.immediateThumbnailData,
|
||||
isReaction: false
|
||||
isReaction: false,
|
||||
isTemplate: false
|
||||
)
|
||||
}
|
||||
|
||||
@ -6918,6 +6997,19 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
|
||||
for item in featuredEmojiPack.topItems {
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
if isStatusSelection {
|
||||
tintMode = .accent
|
||||
} else {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -6925,7 +7017,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let supergroupId = featuredEmojiPack.info.id
|
||||
@ -6959,7 +7051,8 @@ public final class EmojiPagerContentComponent: Component {
|
||||
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
|
||||
dimensions: thumbnail.dimensions.cgSize,
|
||||
immediateThumbnailData: info.immediateThumbnailData,
|
||||
isReaction: false
|
||||
isReaction: false,
|
||||
isTemplate: false
|
||||
)
|
||||
}
|
||||
|
||||
@ -6980,7 +7073,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: nil,
|
||||
subgroupId: subgroupId.rawValue,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: .none
|
||||
)
|
||||
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
@ -7190,19 +7283,29 @@ public final class EmojiPagerContentComponent: Component {
|
||||
resource: .stickerPackThumbnail(stickerPack: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), resource: thumbnail.resource),
|
||||
dimensions: thumbnail.dimensions.cgSize,
|
||||
immediateThumbnailData: featuredStickerPack.info.immediateThumbnailData,
|
||||
isReaction: false
|
||||
isReaction: false,
|
||||
isTemplate: false
|
||||
)
|
||||
} else {
|
||||
animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
content: .animation(animationData),
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let supergroupId = "featuredTop"
|
||||
@ -7233,6 +7336,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
continue
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -7240,7 +7352,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let groupId = "saved"
|
||||
@ -7262,6 +7374,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
continue
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.media.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.media)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -7269,7 +7390,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.media,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let groupId = "recent"
|
||||
@ -7314,6 +7435,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
processedIds.insert(item.file.fileId)
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -7321,7 +7451,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let groupId = "premium"
|
||||
@ -7348,6 +7478,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
processedIds.insert(item.file.fileId)
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -7355,7 +7494,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let groupId = "peerSpecific"
|
||||
@ -7372,6 +7511,16 @@ public final class EmojiPagerContentComponent: Component {
|
||||
guard let item = entry.item as? StickerPackItem else {
|
||||
continue
|
||||
}
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -7379,7 +7528,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
let groupId = entry.index.collectionId
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
@ -7409,7 +7558,8 @@ public final class EmojiPagerContentComponent: Component {
|
||||
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
|
||||
dimensions: thumbnail.dimensions.cgSize,
|
||||
immediateThumbnailData: info.immediateThumbnailData,
|
||||
isReaction: false
|
||||
isReaction: false,
|
||||
isTemplate: false
|
||||
)
|
||||
}
|
||||
|
||||
@ -7426,6 +7576,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
|
||||
for item in featuredStickerPack.topItems {
|
||||
var tintMode: Item.TintMode = .none
|
||||
for attribute in item.file.attributes {
|
||||
if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
|
||||
if isSingleColor {
|
||||
tintMode = .primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: item.file)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
@ -7433,7 +7592,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
let supergroupId = featuredStickerPack.info.id
|
||||
@ -7469,7 +7628,8 @@ public final class EmojiPagerContentComponent: Component {
|
||||
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
|
||||
dimensions: thumbnail.dimensions.cgSize,
|
||||
immediateThumbnailData: info.immediateThumbnailData,
|
||||
isReaction: false
|
||||
isReaction: false,
|
||||
isTemplate: false
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
|
||||
itemFile: nil,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: component.item.isTemplate ? .primary : .none
|
||||
),
|
||||
context: component.context,
|
||||
attemptSynchronousLoad: false,
|
||||
@ -158,6 +158,15 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
|
||||
}
|
||||
itemLayer.update(transition: transition, size: iconFrame.size, badge: badge, blurredBadgeColor: UIColor(white: 0.0, alpha: 0.1), blurredBadgeBackgroundColor: component.theme.list.plainBackgroundColor)
|
||||
|
||||
switch itemLayer.item.tintMode {
|
||||
case .none:
|
||||
break
|
||||
case .primary:
|
||||
itemLayer.layerTintColor = component.theme.list.itemPrimaryTextColor.cgColor
|
||||
case .accent:
|
||||
itemLayer.layerTintColor = component.theme.list.itemAccentColor.cgColor
|
||||
}
|
||||
|
||||
itemLayer.isVisibleForAnimations = true
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import RLottieBinding
|
||||
import GZip
|
||||
import WebPBinding
|
||||
|
||||
public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOnly: Bool, writer: AnimationCacheItemWriter, firstFrameOnly: Bool) {
|
||||
public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOnly: Bool, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
|
||||
let work: () -> Void = {
|
||||
let decompressedData = TGGUnzipData(data, 2 * 1024 * 1024) ?? data
|
||||
guard let animation = LottieInstance(data: decompressedData, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
|
||||
@ -32,6 +32,19 @@ public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOn
|
||||
}
|
||||
writer.add(with: { surface in
|
||||
animation.renderFrame(with: i, into: surface.argb, width: Int32(surface.width), height: Int32(surface.height), bytesPerRow: Int32(surface.bytesPerRow))
|
||||
if customColor != nil {
|
||||
for y in 0 ..< surface.height {
|
||||
for x in 0 ..< surface.width {
|
||||
let pixel = surface.argb.advanced(by: y * surface.bytesPerRow + x * 4)
|
||||
let a = pixel.advanced(by: 3).pointee
|
||||
|
||||
pixel.advanced(by: 0).pointee = a
|
||||
pixel.advanced(by: 1).pointee = a
|
||||
pixel.advanced(by: 2).pointee = a
|
||||
pixel.advanced(by: 3).pointee = a
|
||||
}
|
||||
}
|
||||
}
|
||||
return frameDuration
|
||||
}, proposedWidth: width, proposedHeight: height, insertKeyframe: i == 0 || keyframeOnly)
|
||||
|
||||
@ -46,7 +59,7 @@ public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOn
|
||||
writer.queue.async(work)
|
||||
}
|
||||
|
||||
public func cacheStillSticker(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter) {
|
||||
public func cacheStillSticker(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, customColor: UIColor?) {
|
||||
let work: () -> Void = {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let image = WebP.convert(fromWebP: data) {
|
||||
writer.add(with: { surface in
|
||||
@ -55,6 +68,12 @@ public func cacheStillSticker(path: String, width: Int, height: Int, writer: Ani
|
||||
}
|
||||
context.withFlippedContext { c in
|
||||
UIGraphicsPushContext(c)
|
||||
|
||||
if let customColor = customColor {
|
||||
c.setFillColor(customColor.cgColor)
|
||||
c.setBlendMode(.sourceIn)
|
||||
}
|
||||
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: context.size))
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
@ -243,9 +243,10 @@ public final class TextNodeWithEntities {
|
||||
let itemLayer: InlineStickerItemLayer
|
||||
if let current = self.inlineStickerItemLayers[id] {
|
||||
itemLayer = current
|
||||
itemLayer.dynamicColor = item.textColor
|
||||
} else {
|
||||
let pointSize = floor(itemSize * 1.3)
|
||||
itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize))
|
||||
itemLayer = InlineStickerItemLayer(context: context, 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)
|
||||
|
||||
@ -407,9 +408,10 @@ public class ImmediateTextNodeWithEntities: TextNode {
|
||||
let itemLayer: InlineStickerItemLayer
|
||||
if let current = self.inlineStickerItemLayers[id] {
|
||||
itemLayer = current
|
||||
itemLayer.dynamicColor = item.textColor
|
||||
} else {
|
||||
let pointSize = floor(itemSize * 1.3)
|
||||
itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: false, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize))
|
||||
itemLayer = InlineStickerItemLayer(context: context, 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)
|
||||
|
||||
|
@ -18,7 +18,7 @@ private func roundUp(_ numToRound: Int, multiple: Int) -> Int {
|
||||
return numToRound + multiple - remainder
|
||||
}
|
||||
|
||||
public func cacheVideoAnimation(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool) {
|
||||
public func cacheVideoAnimation(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
|
||||
let work: () -> Void = {
|
||||
guard let frameSource = makeVideoStickerDirectFrameSource(queue: writer.queue, path: path, width: roundUp(width, multiple: 16), height: roundUp(height, multiple: 16), cachePathPrefix: nil, unpremultiplyAlpha: false) else {
|
||||
return
|
||||
|
@ -1177,7 +1177,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var existingIds = Set<Int64>()
|
||||
for (_, file) in files {
|
||||
loop: for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .id(id, _) = packReference, !existingIds.contains(id) {
|
||||
packReferences.append(packReference)
|
||||
existingIds.insert(id)
|
||||
@ -1451,7 +1451,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var existingIds = Set<Int64>()
|
||||
for (_, file) in customEmoji {
|
||||
loop: for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .id(id, _) = packReference, !existingIds.contains(id) {
|
||||
packReferences.append(packReference)
|
||||
existingIds.insert(id)
|
||||
@ -13676,7 +13676,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
var stickerPackReference: StickerPackReference?
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute {
|
||||
stickerPackReference = packReference
|
||||
break
|
||||
}
|
||||
|
@ -526,7 +526,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, _):
|
||||
case let .CustomEmoji(_, _, displayText, _):
|
||||
text = displayText
|
||||
|
||||
var packId: ItemCollectionId?
|
||||
@ -781,7 +781,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
if !alt.isEmpty, let keyword = allEmoticons[alt] {
|
||||
result.append((alt, item.file, keyword))
|
||||
@ -811,7 +811,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
itemFile: itemFile,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
@ -824,8 +824,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
itemFile: nil,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
accentTint: false)
|
||||
)
|
||||
tintMode: .none
|
||||
))
|
||||
}
|
||||
|
||||
return [EmojiPagerContentComponent.ItemGroup(
|
||||
@ -1731,7 +1731,7 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, _):
|
||||
case let .CustomEmoji(_, _, displayText, _):
|
||||
text = displayText
|
||||
var packId: ItemCollectionId?
|
||||
if let id = groupId.base as? ItemCollectionId {
|
||||
@ -2072,7 +2072,7 @@ private final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
||||
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, _, packReference), let .Sticker(_, packReference, _):
|
||||
case let .CustomEmoji(_, _, _, packReference), let .Sticker(_, packReference, _):
|
||||
if let packReference = packReference {
|
||||
let controller = strongSelf.context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], parentNavigationController: strongSelf.controllerInteraction.navigationController(), sendSticker: { file, sourceView, sourceRect in
|
||||
sendSticker(file, false, false, nil, false, sourceView, sourceRect, nil)
|
||||
|
@ -1165,7 +1165,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
}
|
||||
|
||||
if resourceAvailable, !message.containsSecretMedia {
|
||||
if resourceAvailable, !message.containsSecretMedia, !chatPresentationInterfaceState.copyProtectionEnabled, !message.isCopyProtected() {
|
||||
var mediaReference: AnyMediaReference?
|
||||
var isVideo = false
|
||||
for media in message.media {
|
||||
@ -2413,7 +2413,7 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
|
||||
var firstCustomEmojiReaction: TelegramMediaFile?
|
||||
for (_, file) in customEmoji {
|
||||
loop: for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .id(id, _) = packReference, !existingIds.contains(id) {
|
||||
if firstCustomEmojiReaction == nil {
|
||||
firstCustomEmojiReaction = file
|
||||
|
@ -351,7 +351,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
|
||||
}
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if alt == query {
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
result.append((alt, item.file, alt))
|
||||
@ -415,7 +415,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
|
||||
}
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, alt, _):
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if !alt.isEmpty, let keyword = allEmoticons[alt] {
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
result.append((alt, item.file, keyword))
|
||||
|
@ -1069,7 +1069,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
let maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset)
|
||||
|
||||
let font = Font.regular(fontSizeForEmojiString(item.message.text))
|
||||
let attributedText = stringWithAppliedEntities(item.message.text, entities: item.message.textEntitiesAttribute?.entities ?? [], baseColor: .black, linkColor: .black, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: item.message)
|
||||
let textColor = item.presentationData.theme.theme.list.itemPrimaryTextColor
|
||||
let attributedText = stringWithAppliedEntities(item.message.text, entities: item.message.textEntitiesAttribute?.entities ?? [], baseColor: textColor, linkColor: textColor, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: item.message)
|
||||
textLayoutAndApply = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural))
|
||||
|
||||
imageSize = CGSize(width: textLayoutAndApply!.0.size.width, height: textLayoutAndApply!.0.size.height)
|
||||
|
@ -334,7 +334,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let currentDict = updatedString.attributes(at: range.lowerBound, effectiveRange: nil)
|
||||
var updatedAttributes: [NSAttributedString.Key: Any] = currentDict
|
||||
updatedAttributes[NSAttributedString.Key.foregroundColor] = UIColor.clear.cgColor
|
||||
//updatedAttributes[NSAttributedString.Key.foregroundColor] = UIColor.clear.cgColor
|
||||
updatedAttributes[ChatTextInputAttributes.customEmoji] = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: fileId, file: item.message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile)
|
||||
|
||||
let insertString = NSAttributedString(string: updatedString.attributedSubstring(from: range).string, attributes: updatedAttributes)
|
||||
|
@ -473,7 +473,7 @@ final class CustomEmojiContainerView: UIView {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
func update(fontSize: CGFloat, emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)]) {
|
||||
func update(fontSize: CGFloat, textColor: UIColor, emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)]) {
|
||||
var nextIndexById: [Int64: Int] = [:]
|
||||
|
||||
var validKeys = Set<InlineStickerItemLayer.Key>()
|
||||
@ -499,6 +499,10 @@ final class CustomEmojiContainerView: UIView {
|
||||
continue
|
||||
}
|
||||
|
||||
if let view = view as? EmojiTextAttachmentView {
|
||||
view.updateTextColor(textColor)
|
||||
}
|
||||
|
||||
let itemSize: CGFloat = floor(24.0 * fontSize / 17.0)
|
||||
let size = CGSize(width: itemSize, height: itemSize)
|
||||
|
||||
@ -2352,7 +2356,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.customEmojiContainerView = customEmojiContainerView
|
||||
}
|
||||
|
||||
customEmojiContainerView.update(fontSize: fontSize, emojiRects: customEmojiRects)
|
||||
customEmojiContainerView.update(fontSize: fontSize, textColor: textColor, emojiRects: customEmojiRects)
|
||||
} else if let customEmojiContainerView = self.customEmojiContainerView {
|
||||
customEmojiContainerView.removeFromSuperview()
|
||||
self.customEmojiContainerView = nil
|
||||
@ -2599,7 +2603,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, _):
|
||||
case let .CustomEmoji(_, _, displayText, _):
|
||||
text = displayText
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
|
@ -206,7 +206,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
if let file = file {
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case let .CustomEmoji(_, displayText, _):
|
||||
case let .CustomEmoji(_, _, displayText, _):
|
||||
text = displayText
|
||||
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
|
||||
break loop
|
||||
|
@ -2505,7 +2505,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
strongSelf.emojiStatusFileAndPackTitle.set(.never())
|
||||
|
||||
for attribute in emojiFile.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
|
||||
strongSelf.emojiStatusPackDisposable.set((strongSelf.context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: false)
|
||||
|> filter { result in
|
||||
if case .result = result {
|
||||
|
@ -3514,7 +3514,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if let file = files.first?.value {
|
||||
var stickerPackReference: StickerPackReference?
|
||||
for attribute in file.attributes {
|
||||
if case let .CustomEmoji(_, _, packReference) = attribute {
|
||||
if case let .CustomEmoji(_, _, _, packReference) = attribute {
|
||||
stickerPackReference = packReference
|
||||
break
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user