mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +00:00
Emoji improvements
This commit is contained in:
parent
ee4cc8599c
commit
97de870643
@ -198,8 +198,8 @@ public struct ChatInterfaceForwardOptionsState: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatTextInputState: Codable, Equatable {
|
public struct ChatTextInputState: Codable, Equatable {
|
||||||
public let inputText: NSAttributedString
|
public var inputText: NSAttributedString
|
||||||
public let selectionRange: Range<Int>
|
public var selectionRange: Range<Int>
|
||||||
|
|
||||||
public static func ==(lhs: ChatTextInputState, rhs: ChatTextInputState) -> Bool {
|
public static func ==(lhs: ChatTextInputState, rhs: ChatTextInputState) -> Bool {
|
||||||
return lhs.inputText.isEqual(to: rhs.inputText) && lhs.selectionRange == rhs.selectionRange
|
return lhs.inputText.isEqual(to: rhs.inputText) && lhs.selectionRange == rhs.selectionRange
|
||||||
|
|||||||
@ -769,7 +769,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
context.scaleBy(x: 1.0 / scaleFactor, y: 1.0 / scaleFactor)
|
context.scaleBy(x: 1.0 / scaleFactor, y: 1.0 / scaleFactor)
|
||||||
|
|
||||||
let string = NSAttributedString(string: staticEmoji, font: Font.regular(floor(30.0 * scaleFactor)), textColor: .black)
|
let string = NSAttributedString(string: staticEmoji, font: Font.regular(floor(32.0 * scaleFactor)), textColor: .black)
|
||||||
let boundingRect = string.boundingRect(with: scaledSize, options: .usesLineFragmentOrigin, context: nil)
|
let boundingRect = string.boundingRect(with: scaledSize, options: .usesLineFragmentOrigin, context: nil)
|
||||||
UIGraphicsPushContext(context)
|
UIGraphicsPushContext(context)
|
||||||
string.draw(at: CGPoint(x: (scaledSize.width - boundingRect.width) / 2.0 + boundingRect.minX, y: (scaledSize.height - boundingRect.height) / 2.0 + boundingRect.minY))
|
string.draw(at: CGPoint(x: (scaledSize.width - boundingRect.width) / 2.0 + boundingRect.minX, y: (scaledSize.height - boundingRect.height) / 2.0 + boundingRect.minY))
|
||||||
@ -969,6 +969,9 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
guard let item = strongSelf.item(atPoint: point), let itemLayer = strongSelf.visibleItemLayers[item.1], let file = item.0.file else {
|
guard let item = strongSelf.item(atPoint: point), let itemLayer = strongSelf.visibleItemLayers[item.1], let file = item.0.file else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if itemLayer.displayPlaceholder {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
let context = component.context
|
let context = component.context
|
||||||
let accountPeerId = context.account.peerId
|
let accountPeerId = context.account.peerId
|
||||||
@ -1059,11 +1062,11 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
|
|
||||||
loop: for attribute in file.attributes {
|
loop: for attribute in file.attributes {
|
||||||
switch attribute {
|
switch attribute {
|
||||||
case let .CustomEmoji(_, _, packReference):
|
case let .CustomEmoji(_, _, packReference), let .Sticker(_, packReference, _):
|
||||||
if let packReference = packReference {
|
if let packReference = packReference {
|
||||||
let controller = context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: component.inputInteraction.navigationController(), sendSticker: { file, sourceView, sourceRect in
|
let controller = context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: component.inputInteraction.navigationController(), sendSticker: { file, sourceView, sourceRect in
|
||||||
//return component.inputInteraction.sendSticker(file, false, false, nil, false, sourceNode, sourceRect, nil)
|
component.inputInteraction.sendSticker?(file, false, false, nil, false, sourceView, sourceRect, nil)
|
||||||
return false
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
component.inputInteraction.navigationController()?.view.window?.endEditing(true)
|
component.inputInteraction.navigationController()?.view.window?.endEditing(true)
|
||||||
@ -1550,7 +1553,9 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let (item, itemKey) = self.item(atPoint: recognizer.location(in: self)), let itemLayer = self.visibleItemLayers[itemKey] {
|
if let (item, itemKey) = self.item(atPoint: recognizer.location(in: self)), let itemLayer = self.visibleItemLayers[itemKey] {
|
||||||
component.inputInteraction.performItemAction(item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer)
|
if !itemLayer.displayPlaceholder {
|
||||||
|
component.inputInteraction.performItemAction(item, self, self.scrollView.convert(itemLayer.frame, to: self), itemLayer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,6 +176,14 @@ public final class EntityKeyboardComponent: Component {
|
|||||||
private var topPanelExtension: CGFloat?
|
private var topPanelExtension: CGFloat?
|
||||||
private var isTopPanelExpanded: Bool = false
|
private var isTopPanelExpanded: Bool = false
|
||||||
|
|
||||||
|
public var centralId: AnyHashable? {
|
||||||
|
if let pagerView = self.pagerView.findTaggedView(tag: PagerComponentViewTag()) as? PagerComponent<EntityKeyboardChildEnvironment, EntityKeyboardTopContainerPanelEnvironment>.View {
|
||||||
|
return pagerView.centralId
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
|
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
|
||||||
|
|
||||||
|
|||||||
@ -294,6 +294,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
private let loadingMessage = Promise<ChatLoadingMessageSubject?>(nil)
|
private let loadingMessage = Promise<ChatLoadingMessageSubject?>(nil)
|
||||||
private let performingInlineSearch = ValuePromise<Bool>(false, ignoreRepeated: true)
|
private let performingInlineSearch = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
|
|
||||||
|
private var stateServiceTasks: [AnyHashable: Disposable] = [:]
|
||||||
|
|
||||||
private var preloadHistoryPeerId: PeerId?
|
private var preloadHistoryPeerId: PeerId?
|
||||||
private let preloadHistoryPeerIdDisposable = MetaDisposable()
|
private let preloadHistoryPeerIdDisposable = MetaDisposable()
|
||||||
|
|
||||||
@ -10079,6 +10081,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
completion(.immediate)
|
completion(.immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let updatedServiceTasks = serviceTasksForChatPresentationIntefaceState(context: self.context, chatPresentationInterfaceState: updatedChatPresentationInterfaceState, updateState: { [weak self] f in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, f)
|
||||||
|
|
||||||
|
//strongSelf.chatDisplayNode.updateChatPresentationInterfaceState(f(strongSelf.chatDisplayNode.chatPresentationInterfaceState), transition: transition, interactive: false, completion: { _ in })
|
||||||
|
})
|
||||||
|
for (id, begin) in updatedServiceTasks {
|
||||||
|
if self.stateServiceTasks[id] == nil {
|
||||||
|
self.stateServiceTasks[id] = begin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var removedServiceTaskIds: [AnyHashable] = []
|
||||||
|
for (id, _) in self.stateServiceTasks {
|
||||||
|
if updatedServiceTasks[id] == nil {
|
||||||
|
removedServiceTaskIds.append(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in removedServiceTaskIds {
|
||||||
|
self.stateServiceTasks.removeValue(forKey: id)?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
if let button = leftNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, subject: self.subject, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.leftNavigationButton, target: self, selector: #selector(self.leftNavigationButtonAction)) {
|
if let button = leftNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, subject: self.subject, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.leftNavigationButton, target: self, selector: #selector(self.leftNavigationButtonAction)) {
|
||||||
if self.leftNavigationButton != button {
|
if self.leftNavigationButton != button {
|
||||||
var animated = transition.isAnimated
|
var animated = transition.isAnimated
|
||||||
@ -13008,6 +13033,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, botId: results.botId, result: result, replyToMessageId: replyMessageId, hideVia: hideVia, silentPosting: silentPosting) {
|
if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, botId: results.botId, result: result, replyToMessageId: replyMessageId, hideVia: hideVia, silentPosting: silentPosting) {
|
||||||
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.chatDisplayNode.collapseInput()
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
||||||
var state = state
|
var state = state
|
||||||
state = state.updatedInterfaceState { interfaceState in
|
state = state.updatedInterfaceState { interfaceState in
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import GridMessageSelectionNode
|
|||||||
import SparseItemGrid
|
import SparseItemGrid
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
import ChatInputPanelContainer
|
import ChatInputPanelContainer
|
||||||
|
import PremiumUI
|
||||||
|
|
||||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||||
let itemNode: OverlayMediaItemNode
|
let itemNode: OverlayMediaItemNode
|
||||||
@ -602,6 +603,25 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
strongSelf.inputPanelContainerNode.toggleIfEnabled()
|
strongSelf.inputPanelContainerNode.toggleIfEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.textInputPanelNode?.switchToTextInputIfNeeded = { [weak self] in
|
||||||
|
guard let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let inputNode = strongSelf.inputNode as? ChatEntityKeyboardInputNode, !inputNode.canSwitchToTextInputAutomatically {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceInteraction.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
|
||||||
|
switch state.inputMode {
|
||||||
|
case .media:
|
||||||
|
return (.text, state.keyboardButtonsMessage?.id)
|
||||||
|
default:
|
||||||
|
return (state.inputMode, state.keyboardButtonsMessage?.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
self.inputMediaNodeDataDisposable = (self.inputMediaNodeDataPromise.get()
|
self.inputMediaNodeDataDisposable = (self.inputMediaNodeDataPromise.get()
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -2820,6 +2840,47 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var messages: [EnqueueMessage] = []
|
||||||
|
|
||||||
|
let effectiveInputText = effectivePresentationInterfaceState.interfaceState.composeInputState.inputText
|
||||||
|
|
||||||
|
var inlineStickers: [MediaId: Media] = [:]
|
||||||
|
var firstLockedPremiumEmoji: TelegramMediaFile?
|
||||||
|
effectiveInputText.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: NSRange(location: 0, length: effectiveInputText.length), using: { value, _, _ in
|
||||||
|
if let value = value as? ChatTextInputTextCustomEmojiAttribute {
|
||||||
|
if let file = value.file {
|
||||||
|
inlineStickers[file.fileId] = file
|
||||||
|
if file.isPremiumEmoji && !self.chatPresentationInterfaceState.isPremium {
|
||||||
|
if firstLockedPremiumEmoji == nil {
|
||||||
|
firstLockedPremiumEmoji = file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if let firstLockedPremiumEmoji = firstLockedPremiumEmoji {
|
||||||
|
//let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
//TODO:localize
|
||||||
|
self.controllerInteraction.displayUndo(.sticker(context: context, file: firstLockedPremiumEmoji, title: nil, text: "Subscribe to Telegram Premium to unlock premium emoji.", undoText: "More", customAction: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
|
let controller = PremiumDemoScreen(context: strongSelf.context, subject: .premiumStickers, action: {
|
||||||
|
let controller = PremiumIntroScreen(context: strongSelf.context, source: .stickers)
|
||||||
|
replaceImpl?(controller)
|
||||||
|
})
|
||||||
|
replaceImpl = { [weak controller] c in
|
||||||
|
controller?.replace(with: c)
|
||||||
|
}
|
||||||
|
strongSelf.controller?.present(controller, in: .window(.root), with: nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let timestamp = CACurrentMediaTime()
|
let timestamp = CACurrentMediaTime()
|
||||||
if self.lastSendTimestamp + 0.15 > timestamp {
|
if self.lastSendTimestamp + 0.15 > timestamp {
|
||||||
return
|
return
|
||||||
@ -2828,23 +2889,11 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
self.updateTypingActivity(false)
|
self.updateTypingActivity(false)
|
||||||
|
|
||||||
var messages: [EnqueueMessage] = []
|
|
||||||
|
|
||||||
let effectiveInputText = effectivePresentationInterfaceState.interfaceState.composeInputState.inputText
|
|
||||||
let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines)
|
let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let peerId = effectivePresentationInterfaceState.chatLocation.peerId
|
let peerId = effectivePresentationInterfaceState.chatLocation.peerId
|
||||||
if peerId?.namespace != Namespaces.Peer.SecretChat, let interactiveEmojis = self.interactiveEmojis, interactiveEmojis.emojis.contains(trimmedInputText) {
|
if peerId?.namespace != Namespaces.Peer.SecretChat, let interactiveEmojis = self.interactiveEmojis, interactiveEmojis.emojis.contains(trimmedInputText) {
|
||||||
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: trimmedInputText)), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil))
|
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: trimmedInputText)), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil))
|
||||||
} else {
|
} else {
|
||||||
var inlineStickers: [MediaId: Media] = [:]
|
|
||||||
effectiveInputText.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: NSRange(location: 0, length: effectiveInputText.length), using: { value, _, _ in
|
|
||||||
if let value = value as? ChatTextInputTextCustomEmojiAttribute {
|
|
||||||
if let file = value.file {
|
|
||||||
inlineStickers[file.fileId] = file
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let inputText = convertMarkdownToAttributes(effectiveInputText)
|
let inputText = convertMarkdownToAttributes(effectiveInputText)
|
||||||
|
|
||||||
for text in breakChatInputText(trimChatInputText(inputText)) {
|
for text in breakChatInputText(trimChatInputText(inputText)) {
|
||||||
|
|||||||
@ -815,6 +815,15 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var canSwitchToTextInputAutomatically: Bool {
|
||||||
|
if let pagerView = self.entityKeyboardView.componentView as? EntityKeyboardComponent.View, let centralId = pagerView.centralId {
|
||||||
|
if centralId == AnyHashable("emoji") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private final class GifContext {
|
private final class GifContext {
|
||||||
private var componentValue: GifPagerContentComponent? {
|
private var componentValue: GifPagerContentComponent? {
|
||||||
didSet {
|
didSet {
|
||||||
|
|||||||
@ -7,6 +7,8 @@ import AccountContext
|
|||||||
import Emoji
|
import Emoji
|
||||||
import ChatInterfaceState
|
import ChatInterfaceState
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
struct PossibleContextQueryTypes: OptionSet {
|
struct PossibleContextQueryTypes: OptionSet {
|
||||||
var rawValue: Int32
|
var rawValue: Int32
|
||||||
@ -109,7 +111,9 @@ func textInputStateContextQueryRangeAndType(_ inputState: ChatTextInputState) ->
|
|||||||
let string = (inputString as String)
|
let string = (inputString as String)
|
||||||
let trimmedString = string.trimmingTrailingSpaces()
|
let trimmedString = string.trimmingTrailingSpaces()
|
||||||
if string.count < 3, trimmedString.isSingleEmoji {
|
if string.count < 3, trimmedString.isSingleEmoji {
|
||||||
return [(NSRange(location: 0, length: inputString.length - (string.count - trimmedString.count)), [.emoji], nil)]
|
if inputText.attribute(ChatTextInputAttributes.customEmoji, at: 0, effectiveRange: nil) == nil {
|
||||||
|
return [(NSRange(location: 0, length: inputString.length - (string.count - trimmedString.count)), [.emoji], nil)]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var possibleTypes = PossibleContextQueryTypes([.command, .mention, .hashtag, .emojiSearch])
|
var possibleTypes = PossibleContextQueryTypes([.command, .mention, .hashtag, .emojiSearch])
|
||||||
@ -173,6 +177,49 @@ func textInputStateContextQueryRangeAndType(_ inputState: ChatTextInputState) ->
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func serviceTasksForChatPresentationIntefaceState(context: AccountContext, chatPresentationInterfaceState: ChatPresentationInterfaceState, updateState: @escaping ((ChatPresentationInterfaceState) -> ChatPresentationInterfaceState) -> Void) -> [AnyHashable: () -> Disposable] {
|
||||||
|
var missingEmoji = Set<Int64>()
|
||||||
|
let inputText = chatPresentationInterfaceState.interfaceState.composeInputState.inputText
|
||||||
|
inputText.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: NSRange(location: 0, length: inputText.length), using: { value, _, _ in
|
||||||
|
if let value = value as? ChatTextInputTextCustomEmojiAttribute {
|
||||||
|
if value.file == nil {
|
||||||
|
missingEmoji.insert(value.fileId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var result: [AnyHashable: () -> Disposable] = [:]
|
||||||
|
for id in missingEmoji {
|
||||||
|
result["emoji-\(id)"] = {
|
||||||
|
return (context.engine.stickers.resolveInlineStickers(fileIds: [id])
|
||||||
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
|
if let file = result[id] {
|
||||||
|
updateState({ state -> ChatPresentationInterfaceState in
|
||||||
|
return state.updatedInterfaceState { interfaceState -> ChatInterfaceState in
|
||||||
|
var inputState = interfaceState.composeInputState
|
||||||
|
let text = NSMutableAttributedString(attributedString: inputState.inputText)
|
||||||
|
|
||||||
|
inputState.inputText.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: NSRange(location: 0, length: inputText.length), using: { value, range, _ in
|
||||||
|
if let value = value as? ChatTextInputTextCustomEmojiAttribute {
|
||||||
|
if value.fileId == id {
|
||||||
|
text.removeAttribute(ChatTextInputAttributes.customEmoji, range: range)
|
||||||
|
text.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(stickerPack: nil, fileId: file.fileId.id, file: file), range: range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
inputState.inputText = text
|
||||||
|
|
||||||
|
return interfaceState.withUpdatedComposeInputState(inputState)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func inputContextQueriesForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState) -> [ChatPresentationInputQuery] {
|
func inputContextQueriesForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState) -> [ChatPresentationInputQuery] {
|
||||||
let inputState = chatPresentationInterfaceState.interfaceState.effectiveInputState
|
let inputState = chatPresentationInterfaceState.interfaceState.effectiveInputState
|
||||||
let inputString: NSString = inputState.inputText.string as NSString
|
let inputString: NSString = inputState.inputText.string as NSString
|
||||||
|
|||||||
@ -143,15 +143,15 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
|
|
||||||
static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
||||||
switch item {
|
switch item {
|
||||||
case .keyboard, .stickers, .inputButtons, .silentPost, .commands, .scheduledMessages:
|
case .keyboard, .stickers, .inputButtons, .silentPost, .commands, .scheduledMessages:
|
||||||
return (image?.size.width ?? 0.0) + CGFloat(8.0)
|
return 32.0
|
||||||
case let .messageAutoremoveTimeout(timeout):
|
case let .messageAutoremoveTimeout(timeout):
|
||||||
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
||||||
if let _ = timeout, let text = text {
|
if let _ = timeout, let text = text {
|
||||||
imageWidth = ceil((text as NSString).size(withAttributes: [.font: accessoryButtonFont]).width) + 10.0
|
imageWidth = ceil((text as NSString).size(withAttributes: [.font: accessoryButtonFont]).width) + 10.0
|
||||||
}
|
}
|
||||||
|
|
||||||
return max(imageWidth, 24.0)
|
return max(imageWidth, 24.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,6 +413,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
var paste: (ChatTextInputPanelPasteData) -> Void = { _ in }
|
var paste: (ChatTextInputPanelPasteData) -> Void = { _ in }
|
||||||
var updateHeight: (Bool) -> Void = { _ in }
|
var updateHeight: (Bool) -> Void = { _ in }
|
||||||
var toggleExpandMediaInput: (() -> Void)?
|
var toggleExpandMediaInput: (() -> Void)?
|
||||||
|
var switchToTextInputIfNeeded: (() -> Void)?
|
||||||
|
|
||||||
var updateActivity: () -> Void = { }
|
var updateActivity: () -> Void = { }
|
||||||
|
|
||||||
@ -891,7 +892,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
let recognizer = TouchDownGestureRecognizer(target: self, action: #selector(self.textInputBackgroundViewTap(_:)))
|
let recognizer = TouchDownGestureRecognizer(target: self, action: #selector(self.textInputBackgroundViewTap(_:)))
|
||||||
recognizer.touchDown = { [weak self] in
|
recognizer.touchDown = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.ensureFocused()
|
strongSelf.ensureFocusedOnTap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textInputNode.view.addGestureRecognizer(recognizer)
|
textInputNode.view.addGestureRecognizer(recognizer)
|
||||||
@ -2904,6 +2905,16 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
self.textInputNode?.becomeFirstResponder()
|
self.textInputNode?.becomeFirstResponder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ensureFocusedOnTap() {
|
||||||
|
if self.textInputNode == nil {
|
||||||
|
self.loadTextInputNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.textInputNode?.becomeFirstResponder()
|
||||||
|
|
||||||
|
self.switchToTextInputIfNeeded?()
|
||||||
|
}
|
||||||
|
|
||||||
func backwardsDeleteText() {
|
func backwardsDeleteText() {
|
||||||
guard let textInputNode = self.textInputNode else {
|
guard let textInputNode = self.textInputNode else {
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user