mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
608 lines
34 KiB
Swift
608 lines
34 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
import TelegramCore
|
|
import TelegramPresentationData
|
|
import AccountContext
|
|
import ChatPresentationInterfaceState
|
|
import ChatInterfaceState
|
|
import TelegramNotices
|
|
import PresentationDataUtils
|
|
import TelegramCallsUI
|
|
import AttachmentUI
|
|
import WebUI
|
|
|
|
func updateChatPresentationInterfaceStateImpl(
|
|
selfController: ChatControllerImpl,
|
|
transition: ContainedViewLayoutTransition,
|
|
interactive: Bool,
|
|
saveInterfaceState: Bool,
|
|
_ f: (ChatPresentationInterfaceState) -> ChatPresentationInterfaceState,
|
|
completion externalCompletion: @escaping (ContainedViewLayoutTransition) -> Void
|
|
) {
|
|
var completion = externalCompletion
|
|
var temporaryChatPresentationInterfaceState = f(selfController.presentationInterfaceState)
|
|
|
|
if selfController.presentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup != temporaryChatPresentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup || selfController.presentationInterfaceState.keyboardButtonsMessage?.id != temporaryChatPresentationInterfaceState.keyboardButtonsMessage?.id {
|
|
if let keyboardButtonsMessage = temporaryChatPresentationInterfaceState.keyboardButtonsMessage, let keyboardMarkup = keyboardButtonsMessage.visibleButtonKeyboardMarkup {
|
|
if selfController.presentationInterfaceState.interfaceState.editMessage == nil && selfController.presentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 && keyboardButtonsMessage.id != temporaryChatPresentationInterfaceState.interfaceState.messageActionsState.closedButtonKeyboardMessageId && keyboardButtonsMessage.id != temporaryChatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId && temporaryChatPresentationInterfaceState.botStartPayload == nil {
|
|
temporaryChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInputMode({ _ in
|
|
return .inputButtons(persistent: keyboardMarkup.flags.contains(.persistent))
|
|
})
|
|
}
|
|
|
|
if case let .peer(peerId) = selfController.chatLocation, peerId.namespace == Namespaces.Peer.CloudChannel || peerId.namespace == Namespaces.Peer.CloudGroup {
|
|
if temporaryChatPresentationInterfaceState.interfaceState.replyMessageSubject == nil && temporaryChatPresentationInterfaceState.interfaceState.messageActionsState.processedSetupReplyMessageId != keyboardButtonsMessage.id {
|
|
temporaryChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInterfaceState({
|
|
$0.withUpdatedReplyMessageSubject(ChatInterfaceState.ReplyMessageSubject(
|
|
messageId: keyboardButtonsMessage.id,
|
|
quote: nil
|
|
)).withUpdatedMessageActionsState({ value in
|
|
var value = value
|
|
value.processedSetupReplyMessageId = keyboardButtonsMessage.id
|
|
return value
|
|
}) })
|
|
}
|
|
}
|
|
} else {
|
|
temporaryChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInputMode({ mode in
|
|
if case .inputButtons = mode {
|
|
return .text
|
|
} else {
|
|
return mode
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
if let keyboardButtonsMessage = temporaryChatPresentationInterfaceState.keyboardButtonsMessage, keyboardButtonsMessage.requestsSetupReply {
|
|
if temporaryChatPresentationInterfaceState.interfaceState.replyMessageSubject == nil && temporaryChatPresentationInterfaceState.interfaceState.messageActionsState.processedSetupReplyMessageId != keyboardButtonsMessage.id {
|
|
temporaryChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInterfaceState({ $0.withUpdatedReplyMessageSubject(ChatInterfaceState.ReplyMessageSubject(
|
|
messageId: keyboardButtonsMessage.id,
|
|
quote: nil
|
|
)).withUpdatedMessageActionsState({ value in
|
|
var value = value
|
|
value.processedSetupReplyMessageId = keyboardButtonsMessage.id
|
|
return value
|
|
}) })
|
|
}
|
|
}
|
|
|
|
let inputTextPanelState = inputTextPanelStateForChatPresentationInterfaceState(temporaryChatPresentationInterfaceState, context: selfController.context)
|
|
var updatedChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInputTextPanelState({ _ in return inputTextPanelState })
|
|
|
|
let contextQueryUpdates = contextQueryResultStateForChatInterfacePresentationState(updatedChatPresentationInterfaceState, context: selfController.context, currentQueryStates: &selfController.contextQueryStates, requestBotLocationStatus: { [weak selfController] peerId in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
let _ = (ApplicationSpecificNotice.updateInlineBotLocationRequestState(accountManager: selfController.context.sharedContext.accountManager, peerId: peerId, timestamp: Int32(Date().timeIntervalSince1970 + 10 * 60))
|
|
|> deliverOnMainQueue).startStandalone(next: { [weak selfController] value in
|
|
guard let selfController, value else {
|
|
return
|
|
}
|
|
selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_Cancel, action: {
|
|
}), TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_OK, action: { [weak selfController] in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
let _ = ApplicationSpecificNotice.setInlineBotLocationRequest(accountManager: selfController.context.sharedContext.accountManager, peerId: peerId, value: 0).startStandalone()
|
|
})]), in: .window(.root))
|
|
})
|
|
})
|
|
|
|
for (kind, update) in contextQueryUpdates {
|
|
switch update {
|
|
case .remove:
|
|
if let (_, disposable) = selfController.contextQueryStates[kind] {
|
|
disposable.dispose()
|
|
selfController.contextQueryStates.removeValue(forKey: kind)
|
|
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedInputQueryResult(queryKind: kind, { _ in
|
|
return nil
|
|
})
|
|
}
|
|
if case .contextRequest = kind {
|
|
selfController.performingInlineSearch.set(false)
|
|
}
|
|
case let .update(query, signal):
|
|
let currentQueryAndDisposable = selfController.contextQueryStates[kind]
|
|
currentQueryAndDisposable?.1.dispose()
|
|
|
|
var inScope = true
|
|
var inScopeResult: ((ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?)?
|
|
selfController.contextQueryStates[kind] = (query, (signal
|
|
|> deliverOnMainQueue).startStrict(next: { [weak selfController] result in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if Thread.isMainThread && inScope {
|
|
inScope = false
|
|
inScopeResult = result
|
|
} else {
|
|
selfController.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
|
$0.updatedInputQueryResult(queryKind: kind, { previousResult in
|
|
return result(previousResult)
|
|
})
|
|
})
|
|
}
|
|
}, error: { [weak selfController] error in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if case .contextRequest = kind {
|
|
selfController.performingInlineSearch.set(false)
|
|
}
|
|
|
|
switch error {
|
|
case .generic:
|
|
break
|
|
case let .inlineBotLocationRequest(peerId):
|
|
selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_ShareInlineBotLocationConfirmation, actions: [TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_Cancel, action: { [weak selfController] in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
let _ = ApplicationSpecificNotice.setInlineBotLocationRequest(accountManager: selfController.context.sharedContext.accountManager, peerId: peerId, value: Int32(Date().timeIntervalSince1970 + 10 * 60)).startStandalone()
|
|
}), TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_OK, action: { [weak selfController] in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
let _ = ApplicationSpecificNotice.setInlineBotLocationRequest(accountManager: selfController.context.sharedContext.accountManager, peerId: peerId, value: 0).startStandalone()
|
|
})]), in: .window(.root))
|
|
}
|
|
}, completed: { [weak selfController] in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if case .contextRequest = kind {
|
|
selfController.performingInlineSearch.set(false)
|
|
}
|
|
}))
|
|
inScope = false
|
|
if let inScopeResult = inScopeResult {
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedInputQueryResult(queryKind: kind, { previousResult in
|
|
return inScopeResult(previousResult)
|
|
})
|
|
} else {
|
|
if case .contextRequest = kind {
|
|
selfController.performingInlineSearch.set(true)
|
|
}
|
|
}
|
|
|
|
if case let .peer(peerId) = selfController.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat {
|
|
if case .contextRequest = query {
|
|
let _ = (ApplicationSpecificNotice.getSecretChatInlineBotUsage(accountManager: selfController.context.sharedContext.accountManager)
|
|
|> deliverOnMainQueue).startStandalone(next: { [weak selfController] value in
|
|
guard let selfController, !value else {
|
|
return
|
|
}
|
|
let _ = ApplicationSpecificNotice.setSecretChatInlineBotUsage(accountManager: selfController.context.sharedContext.accountManager).startStandalone()
|
|
selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_SecretChatContextBotAlert, actions: [TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var isBot = false
|
|
if let peer = updatedChatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil {
|
|
isBot = true
|
|
} else {
|
|
isBot = false
|
|
}
|
|
selfController.chatDisplayNode.historyNode.chatHasBots = updatedChatPresentationInterfaceState.hasBots || isBot
|
|
|
|
if let (updatedSearchQuerySuggestionState, updatedSearchQuerySuggestionSignal) = searchQuerySuggestionResultStateForChatInterfacePresentationState(updatedChatPresentationInterfaceState, context: selfController.context, currentQuery: selfController.searchQuerySuggestionState?.0) {
|
|
selfController.searchQuerySuggestionState?.1.dispose()
|
|
var inScope = true
|
|
var inScopeResult: ((ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?)?
|
|
selfController.searchQuerySuggestionState = (updatedSearchQuerySuggestionState, (updatedSearchQuerySuggestionSignal |> deliverOnMainQueue).startStrict(next: { [weak selfController] result in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if Thread.isMainThread && inScope {
|
|
inScope = false
|
|
inScopeResult = result
|
|
} else {
|
|
selfController.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
|
$0.updatedSearchQuerySuggestionResult { previousResult in
|
|
return result(previousResult)
|
|
}
|
|
})
|
|
}
|
|
}))
|
|
inScope = false
|
|
if let inScopeResult = inScopeResult {
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedSearchQuerySuggestionResult { previousResult in
|
|
return inScopeResult(previousResult)
|
|
}
|
|
}
|
|
}
|
|
|
|
var canHaveUrlPreview = true
|
|
if case let .customChatContents(customChatContents) = updatedChatPresentationInterfaceState.subject {
|
|
switch customChatContents.kind {
|
|
case .hashTagSearch:
|
|
break
|
|
case .quickReplyMessageInput:
|
|
break
|
|
case .businessLinkSetup:
|
|
canHaveUrlPreview = false
|
|
case .postSuggestions:
|
|
break
|
|
}
|
|
}
|
|
|
|
if canHaveUrlPreview, let (updatedUrlPreviewState, updatedUrlPreviewSignal) = urlPreviewStateForInputText(updatedChatPresentationInterfaceState.interfaceState.composeInputState.inputText, context: selfController.context, currentQuery: selfController.urlPreviewQueryState?.0, forPeerId: selfController.chatLocation.peerId) {
|
|
selfController.urlPreviewQueryState?.1.dispose()
|
|
var inScope = true
|
|
var inScopeResult: ((TelegramMediaWebpage?) -> (TelegramMediaWebpage, String)?)?
|
|
let linkPreviews: Signal<Bool, NoError>
|
|
if case let .peer(peerId) = selfController.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat {
|
|
linkPreviews = interactiveChatLinkPreviewsEnabled(accountManager: selfController.context.sharedContext.accountManager, displayAlert: { [weak selfController] f in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
selfController.present(textAlertController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, title: nil, text: selfController.presentationData.strings.Conversation_SecretLinkPreviewAlert, actions: [
|
|
TextAlertAction(type: .defaultAction, title: selfController.presentationData.strings.Common_Yes, action: {
|
|
f.f(true)
|
|
}), TextAlertAction(type: .genericAction, title: selfController.presentationData.strings.Common_No, action: {
|
|
f.f(false)
|
|
})]), in: .window(.root))
|
|
})
|
|
} else {
|
|
var bannedEmbedLinks = false
|
|
if let channel = selfController.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.hasBannedPermission(.banEmbedLinks) != nil {
|
|
bannedEmbedLinks = true
|
|
} else if let group = selfController.presentationInterfaceState.renderedPeer?.peer as? TelegramGroup, group.hasBannedPermission(.banEmbedLinks) {
|
|
bannedEmbedLinks = true
|
|
}
|
|
if bannedEmbedLinks {
|
|
linkPreviews = .single(false)
|
|
} else {
|
|
linkPreviews = .single(true)
|
|
}
|
|
}
|
|
let filteredPreviewSignal = linkPreviews
|
|
|> take(1)
|
|
|> mapToSignal { value -> Signal<(TelegramMediaWebpage?) -> (TelegramMediaWebpage, String)?, NoError> in
|
|
if value {
|
|
return updatedUrlPreviewSignal
|
|
} else {
|
|
return .single({ _ in return nil })
|
|
}
|
|
}
|
|
|
|
selfController.urlPreviewQueryState = (updatedUrlPreviewState, (filteredPreviewSignal |> deliverOnMainQueue).startStrict(next: { [weak selfController] result in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if Thread.isMainThread && inScope {
|
|
inScope = false
|
|
inScopeResult = result
|
|
} else {
|
|
selfController.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
|
if let (webpage, webpageUrl) = result($0.urlPreview?.webPage) {
|
|
let updatedPreview = ChatPresentationInterfaceState.UrlPreview(
|
|
url: webpageUrl,
|
|
webPage: webpage,
|
|
positionBelowText: $0.urlPreview?.positionBelowText ?? true,
|
|
largeMedia: $0.urlPreview?.largeMedia
|
|
)
|
|
return $0.updatedUrlPreview(updatedPreview)
|
|
} else {
|
|
return $0.updatedUrlPreview(nil)
|
|
}
|
|
})
|
|
}
|
|
}))
|
|
inScope = false
|
|
if let inScopeResult = inScopeResult {
|
|
if let (webpage, webpageUrl) = inScopeResult(updatedChatPresentationInterfaceState.urlPreview?.webPage) {
|
|
let updatedPreview = ChatPresentationInterfaceState.UrlPreview(
|
|
url: webpageUrl,
|
|
webPage: webpage,
|
|
positionBelowText: updatedChatPresentationInterfaceState.urlPreview?.positionBelowText ?? true,
|
|
largeMedia: updatedChatPresentationInterfaceState.urlPreview?.largeMedia
|
|
)
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedUrlPreview(updatedPreview)
|
|
} else {
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedUrlPreview(nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
let isEditingMedia: Bool = updatedChatPresentationInterfaceState.editMessageState?.content != .plaintext
|
|
let editingUrlPreviewText: NSAttributedString? = isEditingMedia ? nil : updatedChatPresentationInterfaceState.interfaceState.editMessage?.inputState.inputText
|
|
if let (updatedEditingUrlPreviewState, updatedEditingUrlPreviewSignal) = urlPreviewStateForInputText(editingUrlPreviewText, context: selfController.context, currentQuery: selfController.editingUrlPreviewQueryState?.0, forPeerId: selfController.chatLocation.peerId) {
|
|
selfController.editingUrlPreviewQueryState?.1.dispose()
|
|
var inScope = true
|
|
var inScopeResult: ((TelegramMediaWebpage?) -> (TelegramMediaWebpage, String)?)?
|
|
selfController.editingUrlPreviewQueryState = (updatedEditingUrlPreviewState, (updatedEditingUrlPreviewSignal |> deliverOnMainQueue).startStrict(next: { [weak selfController] result in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if Thread.isMainThread && inScope {
|
|
inScope = false
|
|
inScopeResult = result
|
|
} else {
|
|
selfController.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
|
if let (webpage, webpageUrl) = result($0.editingUrlPreview?.webPage) {
|
|
let updatedPreview = ChatPresentationInterfaceState.UrlPreview(
|
|
url: webpageUrl,
|
|
webPage: webpage,
|
|
positionBelowText: $0.editingUrlPreview?.positionBelowText ?? true,
|
|
largeMedia: $0.editingUrlPreview?.largeMedia
|
|
)
|
|
return $0.updatedEditingUrlPreview(updatedPreview)
|
|
} else {
|
|
return $0.updatedEditingUrlPreview(nil)
|
|
}
|
|
})
|
|
}
|
|
}))
|
|
inScope = false
|
|
if let inScopeResult = inScopeResult {
|
|
if let (webpage, webpageUrl) = inScopeResult(updatedChatPresentationInterfaceState.editingUrlPreview?.webPage) {
|
|
let updatedPreview = ChatPresentationInterfaceState.UrlPreview(
|
|
url: webpageUrl,
|
|
webPage: webpage,
|
|
positionBelowText: updatedChatPresentationInterfaceState.editingUrlPreview?.positionBelowText ?? true,
|
|
largeMedia: updatedChatPresentationInterfaceState.editingUrlPreview?.largeMedia
|
|
)
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedEditingUrlPreview(updatedPreview)
|
|
} else {
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedEditingUrlPreview(nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
if let replyMessageId = updatedChatPresentationInterfaceState.interfaceState.replyMessageSubject?.messageId {
|
|
if selfController.replyMessageState?.0 != replyMessageId {
|
|
selfController.replyMessageState?.1.dispose()
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedReplyMessage(nil)
|
|
let disposable = MetaDisposable()
|
|
selfController.replyMessageState = (replyMessageId, disposable)
|
|
disposable.set((selfController.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: replyMessageId))
|
|
|> deliverOnMainQueue).start(next: { [weak selfController] message in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
if message != selfController.presentationInterfaceState.replyMessage.flatMap(EngineMessage.init) {
|
|
selfController.updateChatPresentationInterfaceState(interactive: false, { presentationInterfaceState in
|
|
return presentationInterfaceState.updatedReplyMessage(message?._asMessage())
|
|
})
|
|
}
|
|
}))
|
|
}
|
|
} else {
|
|
if let replyMessageState = selfController.replyMessageState {
|
|
selfController.replyMessageState = nil
|
|
replyMessageState.1.dispose()
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedReplyMessage(nil)
|
|
}
|
|
}
|
|
|
|
if let updated = selfController.updateSearch(updatedChatPresentationInterfaceState) {
|
|
updatedChatPresentationInterfaceState = updated
|
|
}
|
|
|
|
let recordingActivityValue: ChatRecordingActivity
|
|
if let mediaRecordingState = updatedChatPresentationInterfaceState.inputTextPanelState.mediaRecordingState {
|
|
switch mediaRecordingState {
|
|
case .audio:
|
|
recordingActivityValue = .voice
|
|
case .video(ChatVideoRecordingStatus.recording, _):
|
|
recordingActivityValue = .instantVideo
|
|
default:
|
|
recordingActivityValue = .none
|
|
}
|
|
} else {
|
|
recordingActivityValue = .none
|
|
}
|
|
if recordingActivityValue != selfController.recordingActivityValue {
|
|
selfController.recordingActivityValue = recordingActivityValue
|
|
selfController.recordingActivityPromise.set(recordingActivityValue)
|
|
}
|
|
|
|
if (selfController.presentationInterfaceState.interfaceState.selectionState == nil) != (updatedChatPresentationInterfaceState.interfaceState.selectionState == nil) {
|
|
selfController.isSelectingMessagesUpdated?(updatedChatPresentationInterfaceState.interfaceState.selectionState != nil)
|
|
selfController.updateNextChannelToReadVisibility()
|
|
}
|
|
|
|
if updatedChatPresentationInterfaceState.displayHistoryFilterAsList {
|
|
var canDisplayAsList = false
|
|
if updatedChatPresentationInterfaceState.search != nil {
|
|
if updatedChatPresentationInterfaceState.search?.resultsState != nil {
|
|
canDisplayAsList = true
|
|
}
|
|
if updatedChatPresentationInterfaceState.historyFilter != nil {
|
|
canDisplayAsList = true
|
|
}
|
|
if case .peer(selfController.context.account.peerId) = updatedChatPresentationInterfaceState.chatLocation {
|
|
canDisplayAsList = true
|
|
}
|
|
}
|
|
if selfController.alwaysShowSearchResultsAsList {
|
|
canDisplayAsList = true
|
|
}
|
|
|
|
if !canDisplayAsList {
|
|
updatedChatPresentationInterfaceState = updatedChatPresentationInterfaceState.updatedDisplayHistoryFilterAsList(false)
|
|
}
|
|
}
|
|
|
|
selfController.presentationInterfaceState = updatedChatPresentationInterfaceState
|
|
|
|
selfController.updateSlowmodeStatus()
|
|
|
|
switch updatedChatPresentationInterfaceState.inputMode {
|
|
case .media:
|
|
break
|
|
default:
|
|
selfController.chatDisplayNode.collapseInput()
|
|
}
|
|
|
|
selfController.tempHideAccessoryPanels = selfController.presentationInterfaceState.search != nil
|
|
|
|
if selfController.isNodeLoaded {
|
|
selfController.chatDisplayNode.updateChatPresentationInterfaceState(updatedChatPresentationInterfaceState, transition: transition, interactive: interactive, completion: completion)
|
|
} else {
|
|
completion(.immediate)
|
|
}
|
|
|
|
let updatedServiceTasks = serviceTasksForChatPresentationIntefaceState(context: selfController.context, chatPresentationInterfaceState: updatedChatPresentationInterfaceState, updateState: { [weak selfController] f in
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
selfController.updateChatPresentationInterfaceState(animated: false, interactive: false, f)
|
|
|
|
//selfController.chatDisplayNode.updateChatPresentationInterfaceState(f(selfController.chatDisplayNode.chatPresentationInterfaceState), transition: transition, interactive: false, completion: { _ in })
|
|
})
|
|
for (id, begin) in updatedServiceTasks {
|
|
if selfController.stateServiceTasks[id] == nil {
|
|
selfController.stateServiceTasks[id] = begin()
|
|
}
|
|
}
|
|
var removedServiceTaskIds: [AnyHashable] = []
|
|
for (id, _) in selfController.stateServiceTasks {
|
|
if updatedServiceTasks[id] == nil {
|
|
removedServiceTaskIds.append(id)
|
|
}
|
|
}
|
|
for id in removedServiceTaskIds {
|
|
selfController.stateServiceTasks.removeValue(forKey: id)?.dispose()
|
|
}
|
|
|
|
if let button = leftNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, subject: selfController.subject, strings: updatedChatPresentationInterfaceState.strings, currentButton: selfController.leftNavigationButton, target: selfController, selector: #selector(selfController.leftNavigationButtonAction)) {
|
|
if selfController.leftNavigationButton != button {
|
|
var animated = transition.isAnimated
|
|
if let currentButton = selfController.leftNavigationButton?.action, currentButton == button.action {
|
|
animated = false
|
|
}
|
|
animated = false
|
|
selfController.navigationItem.setLeftBarButton(button.buttonItem, animated: animated)
|
|
selfController.leftNavigationButton = button
|
|
}
|
|
} else if let _ = selfController.leftNavigationButton {
|
|
selfController.navigationItem.setLeftBarButton(nil, animated: transition.isAnimated)
|
|
selfController.leftNavigationButton = nil
|
|
}
|
|
|
|
var buttonsAnimated = transition.isAnimated
|
|
if let button = rightNavigationButtonForChatInterfaceState(context: selfController.context, presentationInterfaceState: updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: selfController.rightNavigationButton, target: selfController, selector: #selector(selfController.rightNavigationButtonAction), chatInfoNavigationButton: selfController.chatInfoNavigationButton, moreInfoNavigationButton: selfController.moreInfoNavigationButton) {
|
|
if selfController.rightNavigationButton != button {
|
|
if let currentButton = selfController.rightNavigationButton?.action, currentButton == button.action {
|
|
buttonsAnimated = false
|
|
}
|
|
if case .replyThread = selfController.chatLocation {
|
|
buttonsAnimated = false
|
|
}
|
|
selfController.rightNavigationButton = button
|
|
}
|
|
} else if let _ = selfController.rightNavigationButton {
|
|
selfController.rightNavigationButton = nil
|
|
}
|
|
|
|
if let button = secondaryRightNavigationButtonForChatInterfaceState(context: selfController.context, presentationInterfaceState: updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: selfController.secondaryRightNavigationButton, target: selfController, selector: #selector(selfController.secondaryRightNavigationButtonAction), chatInfoNavigationButton: selfController.chatInfoNavigationButton, moreInfoNavigationButton: selfController.moreInfoNavigationButton) {
|
|
if selfController.secondaryRightNavigationButton != button {
|
|
if let currentButton = selfController.secondaryRightNavigationButton?.action, currentButton == button.action {
|
|
buttonsAnimated = false
|
|
}
|
|
if case .replyThread = selfController.chatLocation {
|
|
buttonsAnimated = false
|
|
}
|
|
selfController.secondaryRightNavigationButton = button
|
|
}
|
|
} else if let _ = selfController.secondaryRightNavigationButton {
|
|
selfController.secondaryRightNavigationButton = nil
|
|
}
|
|
|
|
var rightBarButtons: [UIBarButtonItem] = []
|
|
if let rightNavigationButton = selfController.rightNavigationButton {
|
|
rightBarButtons.append(rightNavigationButton.buttonItem)
|
|
}
|
|
if let secondaryRightNavigationButton = selfController.secondaryRightNavigationButton {
|
|
rightBarButtons.append(secondaryRightNavigationButton.buttonItem)
|
|
}
|
|
var rightBarButtonsUpdated = false
|
|
let currentRightBarButtons = selfController.navigationItem.rightBarButtonItems ?? []
|
|
if rightBarButtons.count != currentRightBarButtons.count {
|
|
rightBarButtonsUpdated = true
|
|
} else {
|
|
for i in 0 ..< rightBarButtons.count {
|
|
if rightBarButtons[i] !== currentRightBarButtons[i] {
|
|
rightBarButtonsUpdated = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if rightBarButtonsUpdated {
|
|
selfController.navigationItem.setRightBarButtonItems(rightBarButtons, animated: buttonsAnimated)
|
|
}
|
|
|
|
if let controllerInteraction = selfController.controllerInteraction {
|
|
if updatedChatPresentationInterfaceState.interfaceState.selectionState != controllerInteraction.selectionState {
|
|
controllerInteraction.selectionState = updatedChatPresentationInterfaceState.interfaceState.selectionState
|
|
let isBlackout = controllerInteraction.selectionState != nil
|
|
let previousCompletion = completion
|
|
completion = { [weak selfController] transition in
|
|
previousCompletion(transition)
|
|
|
|
guard let selfController else {
|
|
return
|
|
}
|
|
(selfController.navigationController as? NavigationController)?.updateMasterDetailsBlackout(isBlackout ? .master : nil, transition: transition)
|
|
}
|
|
selfController.updateItemNodesSelectionStates(animated: transition.isAnimated)
|
|
}
|
|
}
|
|
|
|
if saveInterfaceState {
|
|
selfController.saveInterfaceState(includeScrollState: false)
|
|
}
|
|
|
|
if let navigationController = selfController.navigationController as? NavigationController, isTopmostChatController(selfController) {
|
|
var voiceChatOverlayController: VoiceChatOverlayController?
|
|
for controller in navigationController.globalOverlayControllers {
|
|
if let controller = controller as? VoiceChatOverlayController {
|
|
voiceChatOverlayController = controller
|
|
break
|
|
}
|
|
}
|
|
|
|
if let controller = voiceChatOverlayController {
|
|
controller.updateVisibility()
|
|
}
|
|
}
|
|
|
|
selfController.presentationInterfaceStatePromise.set(selfController.presentationInterfaceState)
|
|
|
|
if case .tag = selfController.chatDisplayNode.historyNode.tag {
|
|
} else {
|
|
if let historyFilter = selfController.presentationInterfaceState.historyFilter, historyFilter.isActive {
|
|
selfController.chatDisplayNode.historyNode.updateTag(tag: .customTag(historyFilter.customTag, nil))
|
|
} else {
|
|
selfController.chatDisplayNode.historyNode.updateTag(tag: nil)
|
|
}
|
|
}
|
|
|
|
selfController.updateDownButtonVisibility()
|
|
|
|
if selfController.presentationInterfaceState.hasBirthdayToday {
|
|
selfController.displayBirthdayTooltip()
|
|
}
|
|
|
|
if case .standard(.embedded) = selfController.presentationInterfaceState.mode, let controllerInteraction = selfController.controllerInteraction, let interfaceInteraction = selfController.interfaceInteraction {
|
|
if let titleAccessoryPanelNode = titlePanelForChatPresentationInterfaceState(selfController.presentationInterfaceState, context: selfController.context, currentPanel: selfController.customNavigationPanelNode as? ChatTitleAccessoryPanelNode, controllerInteraction: controllerInteraction, interfaceInteraction: interfaceInteraction, force: true) {
|
|
selfController.customNavigationPanelNode = titleAccessoryPanelNode as? ChatControllerCustomNavigationPanelNode
|
|
} else {
|
|
selfController.customNavigationPanelNode = nil
|
|
}
|
|
}
|
|
|
|
selfController.stateUpdated?(transition)
|
|
}
|