mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-04 13:38:21 +00:00
Fixed emoji determination
This commit is contained in:
parent
1b7f876c3f
commit
69a824f26a
@ -39,7 +39,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
switch self {
|
||||
case let .MessageEntry(message, presentationData, _, _, _, _):
|
||||
var type = 2
|
||||
if presentationData.largeEmoji && message.elligibleForLargeEmoji {
|
||||
if presentationData.largeEmoji && message.elligibleForLargeEmoji && messageTextIsElligibleForLargeEmoji(message.text) {
|
||||
type = 3
|
||||
}
|
||||
return UInt64(message.stableId) | ((UInt64(type) << 40))
|
||||
|
||||
@ -724,11 +724,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
switch contentData {
|
||||
case let .chat(itemPeer, peer, _, messageText):
|
||||
let messageText = messageText.replacingOccurrences(of: "\n\n", with: " ")
|
||||
|
||||
if inlineAuthorPrefix == nil, let embeddedState = embeddedState as? ChatEmbeddedInterfaceState {
|
||||
hasDraft = true
|
||||
authorAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Draft, font: textFont, textColor: theme.messageDraftTextColor)
|
||||
|
||||
attributedText = NSAttributedString(string: embeddedState.text.string, font: textFont, textColor: theme.messageTextColor)
|
||||
attributedText = NSAttributedString(string: embeddedState.text.string.replacingOccurrences(of: "\n\n", with: " "), font: textFont, textColor: theme.messageTextColor)
|
||||
} else if let message = message {
|
||||
if let inlineAuthorPrefix = inlineAuthorPrefix {
|
||||
let composedString = NSMutableAttributedString()
|
||||
|
||||
@ -352,7 +352,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
if self.presentationData.largeEmoji && self.message.elligibleForLargeEmoji && viewClassName == ChatMessageBubbleItemNode.self {
|
||||
if viewClassName == ChatMessageBubbleItemNode.self && self.presentationData.largeEmoji && self.message.elligibleForLargeEmoji && messageTextIsElligibleForLargeEmoji(message.text) {
|
||||
viewClassName = ChatMessageStickerItemNode.self
|
||||
}
|
||||
|
||||
|
||||
@ -192,17 +192,26 @@ private func matchingEmojiEntry(_ emoji: String) -> (UInt8, UInt8, UInt8)? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func messageTextIsElligibleForLargeEmoji(_ emoji: String) -> Bool {
|
||||
for emoji in emoji.emojis {
|
||||
if let _ = matchingEmojiEntry(emoji) {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func largeEmoji(postbox: Postbox, emoji: String, outline: Bool = true) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
var dataSignals: [Signal<MediaResourceData, NoError>] = []
|
||||
for emoji in emoji.emojis {
|
||||
let thumbnailResource = EmojiThumbnailResource(emoji: emoji)
|
||||
let thumbnailRepresentation = CachedEmojiThumbnailRepresentation(outline: outline)
|
||||
let thumbnailSignal = postbox.mediaBox.cachedResourceRepresentation(thumbnailResource, representation: thumbnailRepresentation, complete: true, fetch: true)
|
||||
|
||||
if let entry = matchingEmojiEntry(emoji) {
|
||||
let thumbnailResource = EmojiThumbnailResource(emoji: emoji)
|
||||
let thumbnailRepresentation = CachedEmojiThumbnailRepresentation(outline: outline)
|
||||
|
||||
let spriteResource = EmojiSpriteResource(packId: entry.0, stickerId: entry.1)
|
||||
let representation = CachedEmojiRepresentation(tile: entry.2, outline: outline)
|
||||
|
||||
let thumbnailSignal = postbox.mediaBox.cachedResourceRepresentation(thumbnailResource, representation: thumbnailRepresentation, complete: true, fetch: true)
|
||||
let signal: Signal<MediaResourceData?, NoError> = .single(nil) |> then(postbox.mediaBox.cachedResourceRepresentation(spriteResource, representation: representation, complete: true, fetch: true) |> map(Optional.init))
|
||||
|
||||
let dataSignal = thumbnailSignal
|
||||
@ -217,6 +226,8 @@ func largeEmoji(postbox: Postbox, emoji: String, outline: Bool = true) -> Signal
|
||||
}
|
||||
}
|
||||
dataSignals.append(dataSignal)
|
||||
} else {
|
||||
dataSignals.append(thumbnailSignal)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,20 +3,28 @@ import CoreText
|
||||
|
||||
extension UnicodeScalar {
|
||||
var isEmoji: Bool {
|
||||
switch value {
|
||||
switch self.value {
|
||||
case 0x1F600...0x1F64F, // Emoticons
|
||||
0x1F300...0x1F5FF, // Misc Symbols and Pictographs
|
||||
0x1F680...0x1F6FF, // Transport and Map
|
||||
0x1F1E6...0x1F1FF, // Regional country flags
|
||||
0x2600...0x26FF, // Misc symbols
|
||||
0x2700...0x27BF, // Dingbats
|
||||
0xE0020...0xE007F, // Tags
|
||||
0xFE00...0xFE0F, // Variation Selectors
|
||||
0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
|
||||
127000...127600, // Various asian characters
|
||||
65024...65039, // Variation selector
|
||||
9100...9300, // Misc items
|
||||
8400...8447: // Combining Diacritical Marks for Symbols
|
||||
0x1F300...0x1F5FF, // Misc Symbols and Pictographs
|
||||
0x1F680...0x1F6FF, // Transport and Map
|
||||
0x1F1E6...0x1F1FF, // Regional country flags
|
||||
0xE0020...0xE007F, // Tags
|
||||
0xFE00...0xFE0F, // Variation Selectors
|
||||
0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
|
||||
127000...127600, // Various asian characters
|
||||
65024...65039, // Variation selector
|
||||
9100...9300, // Misc items
|
||||
8400...8447: // Combining Diacritical Marks for Symbols
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var maybeEmoji: Bool {
|
||||
switch self.value {
|
||||
case 0x2600...0x26FF, // Misc symbols
|
||||
0x2700...0x27BF: // Dingbats
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -24,7 +32,7 @@ extension UnicodeScalar {
|
||||
}
|
||||
|
||||
var isZeroWidthJoiner: Bool {
|
||||
return value == 8205
|
||||
return self.value == 8205
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,34 +45,44 @@ extension String {
|
||||
return t
|
||||
}
|
||||
|
||||
var glyphCount: Int {
|
||||
let richText = NSAttributedString(string: self)
|
||||
let line = CTLineCreateWithAttributedString(richText)
|
||||
return CTLineGetGlyphCount(line)
|
||||
}
|
||||
|
||||
var isSingleEmoji: Bool {
|
||||
return glyphCount == 1 && containsEmoji
|
||||
return self.emojis.count == 1 && self.containsEmoji
|
||||
}
|
||||
|
||||
var containsEmoji: Bool {
|
||||
return unicodeScalars.contains { $0.isEmoji }
|
||||
return self.unicodeScalars.contains { $0.isEmoji }
|
||||
}
|
||||
|
||||
var containsOnlyEmoji: Bool {
|
||||
return !isEmpty && !unicodeScalars.contains(where: {
|
||||
!$0.isEmoji && !$0.isZeroWidthJoiner
|
||||
})
|
||||
guard !self.isEmpty else {
|
||||
return false
|
||||
}
|
||||
var nextShouldBeFE0F = false
|
||||
for scalar in self.unicodeScalars {
|
||||
if nextShouldBeFE0F {
|
||||
if scalar.value == 0xfe0f {
|
||||
nextShouldBeFE0F = false
|
||||
continue
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if scalar.maybeEmoji {
|
||||
nextShouldBeFE0F = true
|
||||
}
|
||||
else if !scalar.isEmoji && !scalar.isZeroWidthJoiner {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return !nextShouldBeFE0F
|
||||
}
|
||||
|
||||
// The next tricks are mostly to demonstrate how tricky it can be to determine emoji's
|
||||
// If anyone has suggestions how to improve this, please let me know
|
||||
var emojiString: String {
|
||||
return emojiScalars.map { String($0) }.reduce("", +)
|
||||
return self.emojiScalars.map { String($0) }.reduce("", +)
|
||||
}
|
||||
|
||||
var firstEmoji: String {
|
||||
if let first = emojiScalars.first {
|
||||
if let first = self.emojiScalars.first {
|
||||
return String(first)
|
||||
} else {
|
||||
return ""
|
||||
@ -84,7 +102,7 @@ extension String {
|
||||
fileprivate var emojiScalars: [UnicodeScalar] {
|
||||
var chars: [UnicodeScalar] = []
|
||||
var previous: UnicodeScalar?
|
||||
for cur in unicodeScalars {
|
||||
for cur in self.unicodeScalars {
|
||||
if let previous = previous, previous.isZeroWidthJoiner && cur.isEmoji {
|
||||
chars.append(previous)
|
||||
chars.append(cur)
|
||||
|
||||
@ -158,15 +158,24 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
|
||||
return
|
||||
}
|
||||
|
||||
var size = validLayout.size
|
||||
if case .compact = validLayout.metrics.widthClass, size.width > size.height {
|
||||
size = CGSize(width: size.height, height: size.width)
|
||||
}
|
||||
|
||||
if let background = self.background, background.size == size {
|
||||
return
|
||||
}
|
||||
|
||||
switch self.wallpaper {
|
||||
case .image, .file:
|
||||
if let image = chatControllerBackgroundImage(wallpaper: self.wallpaper, mediaBox: self.context.sharedContext.accountManager.mediaBox, composed: false) {
|
||||
self.background = ImageBasedPasscodeBackground(image: image, size: validLayout.size)
|
||||
self.background = ImageBasedPasscodeBackground(image: image, size: size)
|
||||
} else {
|
||||
self.background = DefaultPasscodeBackground(size: validLayout.size)
|
||||
self.background = DefaultPasscodeBackground(size: size)
|
||||
}
|
||||
default:
|
||||
self.background = DefaultPasscodeBackground(size: validLayout.size)
|
||||
self.background = DefaultPasscodeBackground(size: size)
|
||||
}
|
||||
|
||||
if let background = self.background {
|
||||
@ -313,12 +322,9 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let hadValidLayout = self.validLayout != nil
|
||||
self.validLayout = layout
|
||||
|
||||
if !hadValidLayout {
|
||||
self.updateBackground()
|
||||
}
|
||||
|
||||
self.updateBackground()
|
||||
|
||||
if layout.size.width == 320.0 {
|
||||
self.iconNode.alpha = 0.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user