Various improvements

This commit is contained in:
Ilya Laktyushin 2020-11-12 00:46:41 +04:00
parent d253ac736d
commit 8b569209c8
28 changed files with 2159 additions and 2084 deletions

View File

@ -5898,3 +5898,5 @@ Sorry for the inconvenience.";
"Conversation.ReplacePhoto" = "Replace Photo";
"Conversation.ReplaceFile" = "Replace File";
"Conversation.SendAsNewPhoto" = "Send as New Photo";
"Conversation.TextCopied" = "Text copied to clipboard";

View File

@ -331,13 +331,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var existingPeerIds = Set<PeerId>()
var peers = peers
if let accountPeer = accountPeer, let lowercasedQuery = searchQuery?.lowercased(), lowercasedQuery.count > 1 && (presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery)) {
peers.insert(accountPeer, at: 0)
}
if !peers.isEmpty && selectedFilter != .filter(ChatListSearchFilter.chats.id) {
var existingPeerIds = Set<PeerId>()
var peers = peers
if let accountPeer = accountPeer, let lowercasedQuery = searchQuery?.lowercased(), lowercasedQuery.count > 1 && (presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery)) {
peers.insert(accountPeer, at: 0)
}
for peer in peers {
if existingPeerIds.contains(peer.id) {
continue

View File

@ -517,7 +517,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
}
if self.itemNodes.isEmpty {
let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0, synchronous: synchronous)
node.frame = CGRect(origin: CGPoint(), size: scrollView.bounds.size)
node.frame = CGRect(origin: CGPoint(), size: self.scrollView.bounds.size)
if let containerLayout = self.containerLayout {
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
}

View File

@ -449,8 +449,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let (previousLayout, _) = self.validLayout, self.dismissOnOrientationChange, previousLayout.size.width > previousLayout.size.height && previousLayout.size.height == layout.size.width {
dismiss = true
}
let hadLayout = self.validLayout != nil
self.validLayout = (layout, navigationBarHeight)
if !hadLayout {
self.zoomableContent = zoomableContent
}
let statusDiameter: CGFloat = 50.0
let statusFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusDiameter) / 2.0), y: floor((layout.size.height - statusDiameter) / 2.0)), size: CGSize(width: statusDiameter, height: statusDiameter))
transition.updateFrame(node: self.statusButtonNode, frame: statusFrame)

View File

@ -59,7 +59,7 @@ NSString *const TGMentionPanelCellKind = @"TGMentionPanelCell";
self.selectedBackgroundView.backgroundColor = selectionColor;
_avatarView = [[TGLetteredAvatarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)];
[_avatarView setSingleFontSize:18.0f doubleFontSize:18.0f useBoldFont:false];
[_avatarView setSingleFontSize:16.0f doubleFontSize:16.0f useBoldFont:false];
_avatarView.fadeTransition = true;
[self.contentView addSubview:_avatarView];

View File

@ -17,8 +17,8 @@ public func legacySuggestionContext(context: AccountContext, peerId: PeerId, cha
let disposable = searchPeerMembers(context: context, peerId: peerId, chatLocation: chatLocation, query: query, scope: .mention).start(next: { peers in
let users = NSMutableArray()
for peer in peers {
let user = TGUser()
if let peer = peer as? TelegramUser {
let user = TGUser()
user.uid = peer.id.id
user.firstName = peer.firstName
user.lastName = peer.lastName

View File

@ -119,7 +119,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
break
case .ignore:
return .fail
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults:
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy:
return .waitForSingleTap
}
}

View File

@ -2345,6 +2345,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self?.editMessageMediaWithLegacySignals(signals)
})
}
}, copyText: { [weak self] text in
if let strongSelf = self {
storeMessageTextInPasteboard(text, entities: nil)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in
return true
}), in: .current)
}
}, requestMessageUpdate: { [weak self] id in
if let strongSelf = self {
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
@ -4396,7 +4405,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break
}
}
var inputTextMaxLength: Int32?
var inputTextMaxLength: Int32 = 4096
for media in message.media {
if media is TelegramMediaImage || media is TelegramMediaFile {
inputTextMaxLength = strongSelf.context.currentLimitsConfiguration.with { $0 }.maxMediaCaptionLength

View File

@ -117,6 +117,7 @@ public final class ChatControllerInteraction {
let openReplyThreadOriginalMessage: (Message) -> Void
let openMessageStats: (MessageId) -> Void
let editMessageMedia: (MessageId, Bool) -> Void
let copyText: (String) -> Void
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
@ -205,6 +206,7 @@ public final class ChatControllerInteraction {
openReplyThreadOriginalMessage: @escaping (Message) -> Void,
openMessageStats: @escaping (MessageId) -> Void,
editMessageMedia: @escaping (MessageId, Bool) -> Void,
copyText: @escaping (String) -> Void,
requestMessageUpdate: @escaping (MessageId) -> Void,
cancelInteractiveKeyboardGestures: @escaping () -> Void,
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
@ -280,6 +282,7 @@ public final class ChatControllerInteraction {
self.openReplyThreadOriginalMessage = openReplyThreadOriginalMessage
self.openMessageStats = openMessageStats
self.editMessageMedia = editMessageMedia
self.copyText = copyText
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -332,6 +335,7 @@ public final class ChatControllerInteraction {
}, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -493,7 +493,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.inputPanelBackgroundSeparatorNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelSeparatorColor
self.inputPanelBackgroundSeparatorNode.isLayerBacked = true
self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme)
self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme, dateTimeFormat: self.chatPresentationInterfaceState.dateTimeFormat)
self.navigateButtons.accessibilityElementsHidden = true
self.navigationBarBackroundNode = ASDisplayNode()
@ -1919,7 +1919,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let updateInputTextState = self.chatPresentationInterfaceState.interfaceState.effectiveInputState != chatPresentationInterfaceState.interfaceState.effectiveInputState
self.chatPresentationInterfaceState = chatPresentationInterfaceState
self.navigateButtons.updateTheme(theme: chatPresentationInterfaceState.theme)
self.navigateButtons.update(theme: chatPresentationInterfaceState.theme, dateTimeFormat: chatPresentationInterfaceState.dateTimeFormat)
if themeUpdated {
if case let .color(color) = self.chatPresentationInterfaceState.chatWallpaper, UIColor(rgb: color).isEqual(self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {

View File

@ -6,6 +6,7 @@ import TelegramPresentationData
final class ChatHistoryNavigationButtons: ASDisplayNode {
private var theme: PresentationTheme
private var dateTimeFormat: PresentationDateTimeFormat
private let mentionsButton: ChatHistoryNavigationButtonNode
private let mentionsButtonTapNode: ASDisplayNode
@ -31,7 +32,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
var unreadCount: Int32 = 0 {
didSet {
if self.unreadCount != 0 {
self.downButton.badge = "\(self.unreadCount)"
self.downButton.badge = compactNumericCountString(Int(self.unreadCount), decimalSeparator: self.dateTimeFormat.decimalSeparator)
} else {
self.downButton.badge = ""
}
@ -41,7 +42,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
var mentionCount: Int32 = 0 {
didSet {
if self.mentionCount != 0 {
self.mentionsButton.badge = "\(self.mentionCount)"
self.mentionsButton.badge = compactNumericCountString(Int(self.mentionCount), decimalSeparator: self.dateTimeFormat.decimalSeparator)
} else {
self.mentionsButton.badge = ""
}
@ -52,8 +53,9 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
}
}
init(theme: PresentationTheme) {
init(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat) {
self.theme = theme
self.dateTimeFormat = dateTimeFormat
self.mentionsButton = ChatHistoryNavigationButtonNode(theme: theme, type: .mentions)
self.mentionsButton.alpha = 0.0
@ -81,9 +83,10 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
self.mentionsButtonTapNode.view.addGestureRecognizer(tapRecognizer)
}
func updateTheme(theme: PresentationTheme) {
if self.theme !== theme {
func update(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat) {
if self.theme !== theme || self.dateTimeFormat != dateTimeFormat {
self.theme = theme
self.dateTimeFormat = dateTimeFormat
self.mentionsButton.updateTheme(theme: theme)
self.downButton.updateTheme(theme: theme)

View File

@ -146,19 +146,7 @@ func preparedChatMediaInputGridEntryTransition(account: Account, view: ItemColle
firstIndexInSectionOffset = Int(index.itemIndex.index)
}
}
if case .initial = update {
switch toEntries[0].index {
case .search:
if toEntries.count > 1 {
//scrollToItem = GridNodeScrollToItem(index: 1, position: .top, transition: .immediate, directionHint: .up, adjustForSection: true)
}
break
default:
break
}
}
let opaqueState = ChatMediaInputStickerPaneOpaqueState(hasLower: view.lower != nil)
return ChatMediaInputGridTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: firstIndexInSectionOffset, stationaryItems: stationaryItems, scrollToItem: scrollToItem, updateOpaqueState: opaqueState, animated: animated)

View File

@ -218,7 +218,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
return
}
if image != nil {
strongSelf.removePlaceholder(animated: !firstTime)
// strongSelf.removePlaceholder(animated: !firstTime)
}
firstTime = false
}

View File

@ -97,6 +97,7 @@ enum ChatMessageBubbleContentTapAction {
case bankCard(String)
case ignore
case openPollResults(Data)
case copy(String)
}
final class ChatMessageBubbleContentItem {

View File

@ -643,7 +643,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
break
case .ignore:
return .fail
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults:
case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy:
return .waitForSingleTap
}
}
@ -3122,6 +3122,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
item.controllerInteraction.openMessagePollResults(item.message.id, option)
})
}
case let .copy(text):
if let item = self.item {
return .optionalAction({
item.controllerInteraction.copyText(text)
})
}
}
}
return nil
@ -3198,6 +3204,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
break
case .openPollResults:
break
case .copy:
break
}
}
if let tapMessage = tapMessage {

View File

@ -450,6 +450,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
return .timecode(timecode.time, timecode.text)
} else if let bankCard = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard)] as? String {
return .bankCard(bankCard)
} else if let pre = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre)] as? String {
return .copy(pre)
} else {
return .none
}

View File

@ -456,6 +456,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -31,8 +31,6 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
self.micButton = ChatTextInputMediaRecordingButton(theme: theme, strings: strings, presentController: presentController)
self.sendButton = HighlightTrackingButtonNode(pointerStyle: .lift)
//self.sendButton.adjustsImageWhenHighlighted = false
//self.sendButton.adjustsImageWhenDisabled = false
self.expandMediaInputButton = HighlightableButtonNode(pointerStyle: .default)

View File

@ -204,6 +204,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let textInputBackgroundNode: ASImageNode
let actionButtons: ChatTextInputActionButtonsNode
var mediaRecordingAccessibilityArea: AccessibilityAreaNode?
private let counterTextNode: ImmediateTextNode
let attachmentButton: HighlightableButtonNode
let attachmentButtonDisabledNode: HighlightableButtonNode
@ -244,6 +245,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
private var theme: PresentationTheme?
private var strings: PresentationStrings?
private let hapticFeedback = HapticFeedback()
var inputTextState: ChatTextInputState {
if let textInputNode = self.textInputNode {
let selectionRange: Range<Int> = textInputNode.selectedRange.location ..< (textInputNode.selectedRange.location + textInputNode.selectedRange.length)
@ -403,6 +406,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.searchLayoutClearButton.addSubnode(self.searchLayoutClearImageNode)
self.actionButtons = ChatTextInputActionButtonsNode(theme: presentationInterfaceState.theme, strings: presentationInterfaceState.strings, presentController: presentController)
self.counterTextNode = ImmediateTextNode()
self.counterTextNode.textAlignment = .center
super.init()
@ -491,6 +496,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.addSubnode(self.attachmentButtonDisabledNode)
self.addSubnode(self.actionButtons)
self.addSubnode(self.counterTextNode)
self.view.addSubview(self.searchLayoutClearButton)
@ -1183,6 +1189,22 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
textInputBackgroundWidthOffset = 36.0
}
if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState, let editMessage = presentationInterfaceState.interfaceState.editMessage, let inputTextMaxLength = editMessage.inputTextMaxLength {
let textCount = Int32(textInputNode.textView.text.count)
let counterColor: UIColor = textCount > inputTextMaxLength ? presentationInterfaceState.theme.chat.inputPanel.panelControlDestructiveColor : presentationInterfaceState.theme.chat.inputPanel.panelControlColor
let remainingCount = inputTextMaxLength - textCount
let counterText = remainingCount >= 5 ? "" : "\(inputTextMaxLength - textCount)"
self.counterTextNode.attributedText = NSAttributedString(string: counterText, font: Font.regular(14.0), textColor: counterColor)
} else {
self.counterTextNode.attributedText = NSAttributedString(string: "", font: Font.regular(14.0), textColor: .black)
}
let counterSize = self.counterTextNode.updateLayout(CGSize(width: 44.0, height: 44.0))
let actionButtonsOriginX = width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset
let counterFrame = CGRect(origin: CGPoint(x: actionButtonsOriginX, y: panelHeight - minimalHeight - counterSize.height + 3.0), size: CGSize(width: width - actionButtonsOriginX - rightInset, height: counterSize.height))
transition.updateFrame(node: self.counterTextNode, frame: counterFrame)
let actionButtonsFrame = CGRect(origin: CGPoint(x: width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset, y: panelHeight - minimalHeight), size: CGSize(width: 44.0, height: minimalHeight))
transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame)
@ -1454,6 +1476,21 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.interfaceInteraction?.updateTextInputStateAndMode({ _, inputMode in return (inputTextState, inputMode) })
self.interfaceInteraction?.updateInputLanguage({ _ in return textInputNode.textInputMode.primaryLanguage })
self.updateTextNodeText(animated: true)
if let editMessage = presentationInterfaceState.interfaceState.editMessage, let inputTextMaxLength = editMessage.inputTextMaxLength {
let textCount = Int32(textInputNode.textView.text.count)
let counterColor: UIColor = textCount > inputTextMaxLength ? presentationInterfaceState.theme.chat.inputPanel.panelControlDestructiveColor : presentationInterfaceState.theme.chat.inputPanel.panelControlColor
let remainingCount = inputTextMaxLength - textCount
let counterText = remainingCount >= 5 ? "" : "\(inputTextMaxLength - textCount)"
self.counterTextNode.attributedText = NSAttributedString(string: counterText, font: Font.regular(14.0), textColor: counterColor)
} else {
self.counterTextNode.attributedText = NSAttributedString(string: "", font: Font.regular(14.0), textColor: .black)
}
if let (width, leftInset, rightInset, maxHeight, metrics, isSecondary) = self.validLayout {
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics)
}
}
}
@ -1793,14 +1830,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
}
}
let newText = (editableTextNode.textView.text as NSString).replacingCharacters(in: range, with: cleanText)
if let interfaceState = self.presentationInterfaceState, let editMessage = interfaceState.interfaceState.editMessage, let inputTextMaxLength = editMessage.inputTextMaxLength {
if newText.count > inputTextMaxLength {
return false
}
}
if cleanText != text {
let string = NSMutableAttributedString(attributedString: editableTextNode.attributedText ?? NSAttributedString())
var textColor: UIColor = .black
@ -1898,6 +1928,17 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
@objc func sendButtonPressed() {
if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState, let editMessage = presentationInterfaceState.interfaceState.editMessage, let inputTextMaxLength = editMessage.inputTextMaxLength {
let textCount = Int32(textInputNode.textView.text.count)
let remainingCount = inputTextMaxLength - textCount
if remainingCount < 0 {
textInputNode.layer.addShakeAnimation()
self.hapticFeedback.error()
return
}
}
self.sendMessage()
}

View File

@ -149,6 +149,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
}, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -139,6 +139,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))

View File

@ -1970,6 +1970,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -1239,6 +1239,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, openReplyThreadOriginalMessage: { _ in
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -160,15 +160,17 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
if case .Mention = entities[i + 1].type {
let nextRange = NSRange(location: entities[i + 1].range.lowerBound, length: entities[i + 1].range.upperBound - entities[i + 1].range.lowerBound)
if nextRange.location == range.location + range.length + 1 && nsString!.character(at: range.location + range.length) == 43 {
let peerName: String = nsString!.substring(with: NSRange(location: nextRange.location + 1, length: nextRange.length - 1))
skipEntity = true
let combinedRange = NSRange(location: range.location, length: nextRange.location + nextRange.length - range.location)
string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: combinedRange)
if linkColor.isEqual(baseColor) {
string.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: combinedRange)
if nextRange.length > 0 {
let peerName: String = nsString!.substring(with: NSRange(location: nextRange.location + 1, length: nextRange.length - 1))
let combinedRange = NSRange(location: range.location, length: nextRange.location + nextRange.length - range.location)
string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: combinedRange)
if linkColor.isEqual(baseColor) {
string.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: combinedRange)
}
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag), value: TelegramHashtag(peerName: peerName, hashtag: hashtag), range: combinedRange)
}
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag), value: TelegramHashtag(peerName: peerName, hashtag: hashtag), range: combinedRange)
}
}
}
@ -190,6 +192,10 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.BotCommand), value: nsString!.substring(with: range), range: range)
case .Code, .Pre:
string.addAttribute(NSAttributedString.Key.font, value: fixedFont, range: range)
if nsString == nil {
nsString = text as NSString
}
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre), value: nsString!.substring(with: range), range: range)
case .BlockQuote:
if let fontAttribute = fontAttributes[range] {
fontAttributes[range] = fontAttribute.union(.blockQuote)

View File

@ -40,4 +40,5 @@ public struct TelegramTextAttributes {
public static let BankCard = "TelegramBankCard"
public static let Timecode = "TelegramTimecode"
public static let BlockQuote = "TelegramBlockQuote"
public static let Pre = "TelegramPre"
}

View File

@ -142,7 +142,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.textNode.attributedText = attributedText
self.textNode.maximumNumberOfLines = 2
displayUndo = false
self.originalRemainingSeconds = 5
self.originalRemainingSeconds = 3
case let .info(text):
self.iconNode = nil
self.iconCheckNode = nil