mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
238 lines
14 KiB
Swift
238 lines
14 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import TelegramCore
|
|
import Postbox
|
|
import Display
|
|
import AccountContext
|
|
import Emoji
|
|
import ChatInterfaceState
|
|
import ChatPresentationInterfaceState
|
|
import SwiftSignalKit
|
|
import TextFormat
|
|
import ChatContextQuery
|
|
|
|
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).startStrict(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(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file), range: range)
|
|
}
|
|
}
|
|
})
|
|
|
|
inputState.inputText = text
|
|
|
|
return interfaceState.withUpdatedComposeInputState(inputState)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func inputContextQueriesForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState) -> [ChatPresentationInputQuery] {
|
|
let inputState = chatPresentationInterfaceState.interfaceState.effectiveInputState
|
|
let inputString: NSString = inputState.inputText.string as NSString
|
|
var result: [ChatPresentationInputQuery] = []
|
|
for (possibleQueryRange, possibleTypes, additionalStringRange) in textInputStateContextQueryRangeAndType(inputState) {
|
|
let query = inputString.substring(with: possibleQueryRange)
|
|
if possibleTypes == [.emoji] {
|
|
result.append(.emoji(query.basicEmoji.0))
|
|
} else if possibleTypes == [.hashtag] {
|
|
result.append(.hashtag(query))
|
|
} else if possibleTypes == [.mention] {
|
|
var types: ChatInputQueryMentionTypes = [.members]
|
|
if possibleQueryRange.lowerBound == 1 {
|
|
types.insert(.contextBots)
|
|
}
|
|
result.append(.mention(query: query, types: types))
|
|
} else if possibleTypes == [.command] {
|
|
result.append(.command(query))
|
|
} else if possibleTypes == [.contextRequest], let additionalStringRange = additionalStringRange {
|
|
let additionalString = inputString.substring(with: additionalStringRange)
|
|
result.append(.contextRequest(addressName: query, query: additionalString))
|
|
} else if possibleTypes == [.emojiSearch], !query.isEmpty, let inputLanguage = chatPresentationInterfaceState.interfaceState.inputLanguage {
|
|
result.append(.emojiSearch(query: query, languageCode: inputLanguage, range: possibleQueryRange))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext) -> ChatTextInputPanelState {
|
|
var contextPlaceholder: NSAttributedString?
|
|
loop: for (_, result) in chatPresentationInterfaceState.inputQueryResults {
|
|
if case let .contextRequestResult(peer, _) = result, case let .user(botUser) = peer, let botInfo = botUser.botInfo, let inlinePlaceholder = botInfo.inlinePlaceholder {
|
|
let inputQueries = inputContextQueriesForChatPresentationIntefaceState(chatPresentationInterfaceState)
|
|
for inputQuery in inputQueries {
|
|
if case let .contextRequest(addressName, query) = inputQuery, query.isEmpty {
|
|
let baseFontSize: CGFloat = max(chatTextInputMinFontSize, chatPresentationInterfaceState.fontSize.baseDisplaySize)
|
|
|
|
let string = NSMutableAttributedString()
|
|
string.append(NSAttributedString(string: "@" + addressName, font: Font.regular(baseFontSize), textColor: UIColor.clear))
|
|
string.append(NSAttributedString(string: " " + inlinePlaceholder, font: Font.regular(baseFontSize), textColor: chatPresentationInterfaceState.theme.chat.inputPanel.inputPlaceholderColor))
|
|
contextPlaceholder = string
|
|
}
|
|
}
|
|
|
|
break loop
|
|
}
|
|
}
|
|
|
|
var currentAutoremoveTimeout: Int32? = chatPresentationInterfaceState.autoremoveTimeout
|
|
var canSetupAutoremoveTimeout = false
|
|
|
|
var canSendTextMessages = true
|
|
|
|
var accessoryItems: [ChatTextInputAccessoryItem] = []
|
|
|
|
if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramSecretChat {
|
|
var extendedSearchLayout = false
|
|
loop: for (_, result) in chatPresentationInterfaceState.inputQueryResults {
|
|
if case let .contextRequestResult(peer, _) = result, peer != nil {
|
|
extendedSearchLayout = true
|
|
break loop
|
|
}
|
|
}
|
|
|
|
if !extendedSearchLayout {
|
|
currentAutoremoveTimeout = peer.messageAutoremoveTimeout
|
|
canSetupAutoremoveTimeout = true
|
|
}
|
|
} else if let group = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup {
|
|
if !group.hasBannedPermission(.banChangeInfo) {
|
|
canSetupAutoremoveTimeout = true
|
|
}
|
|
canSendTextMessages = !group.hasBannedPermission(.banSendText)
|
|
} else if let user = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser {
|
|
if user.botInfo == nil {
|
|
canSetupAutoremoveTimeout = true
|
|
}
|
|
} else if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
|
|
if channel.hasPermission(.changeInfo) {
|
|
canSetupAutoremoveTimeout = true
|
|
}
|
|
canSendTextMessages = channel.hasBannedPermission(.banSendText) == nil
|
|
}
|
|
|
|
if canSetupAutoremoveTimeout {
|
|
if case .scheduledMessages = chatPresentationInterfaceState.subject {
|
|
} else if chatPresentationInterfaceState.renderedPeer?.peerId != context.account.peerId {
|
|
if currentAutoremoveTimeout != nil || chatPresentationInterfaceState.renderedPeer?.peer is TelegramSecretChat {
|
|
accessoryItems.append(.messageAutoremoveTimeout(currentAutoremoveTimeout))
|
|
}
|
|
}
|
|
}
|
|
|
|
switch chatPresentationInterfaceState.inputMode {
|
|
case .media:
|
|
accessoryItems.append(.input(isEnabled: true, inputMode: .keyboard))
|
|
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
|
case .inputButtons:
|
|
return ChatTextInputPanelState(accessoryItems: [.botInput(isEnabled: true, inputMode: .keyboard)], contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
|
case .none, .text:
|
|
if let _ = chatPresentationInterfaceState.interfaceState.editMessage {
|
|
accessoryItems.append(.input(isEnabled: true, inputMode: .emoji))
|
|
|
|
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
|
} else {
|
|
var accessoryItems: [ChatTextInputAccessoryItem] = []
|
|
let isTextEmpty = chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0
|
|
let hasForward = chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil
|
|
|
|
|
|
if case .scheduledMessages = chatPresentationInterfaceState.subject {
|
|
} else {
|
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
|
let giftIsEnabled = !premiumConfiguration.isPremiumDisabled && premiumConfiguration.showPremiumGiftInAttachMenu && premiumConfiguration.showPremiumGiftInTextField
|
|
if isTextEmpty, giftIsEnabled, let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, !peer.isDeleted && peer.botInfo == nil && !peer.flags.contains(.isSupport) && !peer.isPremium && !chatPresentationInterfaceState.premiumGiftOptions.isEmpty && chatPresentationInterfaceState.suggestPremiumGift {
|
|
accessoryItems.append(.gift)
|
|
}
|
|
}
|
|
|
|
var extendedSearchLayout = false
|
|
loop: for (_, result) in chatPresentationInterfaceState.inputQueryResults {
|
|
if case let .contextRequestResult(peer, _) = result, peer != nil {
|
|
extendedSearchLayout = true
|
|
break loop
|
|
}
|
|
}
|
|
if !extendedSearchLayout {
|
|
if case .scheduledMessages = chatPresentationInterfaceState.subject {
|
|
} else if chatPresentationInterfaceState.renderedPeer?.peerId != context.account.peerId {
|
|
if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramSecretChat, chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 {
|
|
accessoryItems.append(.messageAutoremoveTimeout(peer.messageAutoremoveTimeout))
|
|
} else if currentAutoremoveTimeout != nil && chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 {
|
|
accessoryItems.append(.messageAutoremoveTimeout(currentAutoremoveTimeout))
|
|
}
|
|
}
|
|
}
|
|
|
|
if isTextEmpty && chatPresentationInterfaceState.hasScheduledMessages && !hasForward {
|
|
accessoryItems.append(.scheduledMessages)
|
|
}
|
|
|
|
var stickersEnabled = true
|
|
var stickersAreEmoji = !isTextEmpty
|
|
if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel {
|
|
if isTextEmpty, case .broadcast = peer.info, canSendMessagesToPeer(peer) {
|
|
accessoryItems.append(.silentPost(chatPresentationInterfaceState.interfaceState.silentPosting))
|
|
}
|
|
if peer.hasBannedPermission(.banSendStickers) != nil {
|
|
stickersEnabled = false
|
|
}
|
|
} else if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramGroup {
|
|
if peer.hasBannedPermission(.banSendStickers) {
|
|
stickersEnabled = false
|
|
}
|
|
}
|
|
|
|
if isTextEmpty && chatPresentationInterfaceState.hasBots && chatPresentationInterfaceState.hasBotCommands && !hasForward {
|
|
accessoryItems.append(.commands)
|
|
}
|
|
|
|
if !canSendTextMessages {
|
|
if stickersEnabled && !stickersAreEmoji && !hasForward {
|
|
accessoryItems.append(.input(isEnabled: true, inputMode: .stickers))
|
|
}
|
|
} else {
|
|
stickersAreEmoji = stickersAreEmoji || hasForward
|
|
if stickersEnabled {
|
|
accessoryItems.append(.input(isEnabled: true, inputMode: stickersAreEmoji ? .emoji : .stickers))
|
|
} else {
|
|
accessoryItems.append(.input(isEnabled: true, inputMode: .emoji))
|
|
}
|
|
}
|
|
|
|
if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id {
|
|
accessoryItems.append(.botInput(isEnabled: true, inputMode: .bot))
|
|
}
|
|
|
|
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
|
|
}
|
|
}
|
|
}
|