From 69a824f26a2e49ec3a3da08885bf9c4baa47b1a0 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 6 May 2019 01:36:10 +0200 Subject: [PATCH] Fixed emoji determination --- TelegramUI/ChatHistoryEntry.swift | 2 +- TelegramUI/ChatListItem.swift | 4 +- TelegramUI/ChatMessageItem.swift | 2 +- TelegramUI/EmojiResources.swift | 21 ++++-- TelegramUI/EmojiUtils.swift | 78 ++++++++++++-------- TelegramUI/PasscodeEntryControllerNode.swift | 22 ++++-- 6 files changed, 83 insertions(+), 46 deletions(-) diff --git a/TelegramUI/ChatHistoryEntry.swift b/TelegramUI/ChatHistoryEntry.swift index 5587fc4c35..849691ae05 100644 --- a/TelegramUI/ChatHistoryEntry.swift +++ b/TelegramUI/ChatHistoryEntry.swift @@ -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)) diff --git a/TelegramUI/ChatListItem.swift b/TelegramUI/ChatListItem.swift index b911ff82b6..b90a18a366 100644 --- a/TelegramUI/ChatListItem.swift +++ b/TelegramUI/ChatListItem.swift @@ -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() diff --git a/TelegramUI/ChatMessageItem.swift b/TelegramUI/ChatMessageItem.swift index 2ef804f2b7..a877141ae3 100644 --- a/TelegramUI/ChatMessageItem.swift +++ b/TelegramUI/ChatMessageItem.swift @@ -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 } diff --git a/TelegramUI/EmojiResources.swift b/TelegramUI/EmojiResources.swift index 2dcc0ce559..ee06397337 100644 --- a/TelegramUI/EmojiResources.swift +++ b/TelegramUI/EmojiResources.swift @@ -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] = [] 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 = .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) } } diff --git a/TelegramUI/EmojiUtils.swift b/TelegramUI/EmojiUtils.swift index bcc729b2f5..9bef53eaf1 100644 --- a/TelegramUI/EmojiUtils.swift +++ b/TelegramUI/EmojiUtils.swift @@ -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) diff --git a/TelegramUI/PasscodeEntryControllerNode.swift b/TelegramUI/PasscodeEntryControllerNode.swift index 557d4d57d8..16a32c6f6e 100644 --- a/TelegramUI/PasscodeEntryControllerNode.swift +++ b/TelegramUI/PasscodeEntryControllerNode.swift @@ -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