Various fixes

This commit is contained in:
Ilya Laktyushin 2022-07-22 17:46:09 +03:00
parent 237f86f7ca
commit e1b4af1461
27 changed files with 329 additions and 111 deletions

View File

@ -322,7 +322,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
private var spoilersRevealed = false private var spoilersRevealed = false
private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)? public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
private let animationCache: AnimationCache private let animationCache: AnimationCache
private let animationRenderer: MultiAnimationRenderer private let animationRenderer: MultiAnimationRenderer

View File

@ -675,6 +675,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
}, schedule: { [weak textInputPanelNode] in }, schedule: { [weak textInputPanelNode] in
textInputPanelNode?.sendMessage(.schedule) textInputPanelNode?.sendMessage(.schedule)
}) })
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
strongSelf.presentInGlobalOverlay(controller) strongSelf.presentInGlobalOverlay(controller)
}, openScheduledMessages: { }, openScheduledMessages: {
}, openPeersNearby: { }, openPeersNearby: {

View File

@ -489,6 +489,9 @@ private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutP
methods.append(.savedCredentials(savedCredentials)) methods.append(.savedCredentials(savedCredentials))
} }
} }
if !form.additionalPaymentMethods.isEmpty {
methods.append(contentsOf: form.additionalPaymentMethods.map { .other($0) })
}
return methods return methods
} }
@ -1416,6 +1419,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
} }
}) })
return return
case let .other(method):
let _ = method
return
} }
} }

View File

@ -17,6 +17,7 @@ enum BotCheckoutPaymentMethod: Equatable {
case savedCredentials(BotPaymentSavedCredentials) case savedCredentials(BotPaymentSavedCredentials)
case webToken(BotCheckoutPaymentWebToken) case webToken(BotCheckoutPaymentWebToken)
case applePay case applePay
case other(BotPaymentMethod)
var title: String { var title: String {
switch self { switch self {
@ -29,6 +30,8 @@ enum BotCheckoutPaymentMethod: Equatable {
return token.title return token.title
case .applePay: case .applePay:
return "Apple Pay" return "Apple Pay"
case let .other(method):
return method.title
} }
} }
} }
@ -68,6 +71,9 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
case .applePay: case .applePay:
title = "Apple Pay" title = "Apple Pay"
icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed() icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed()
case let .other(method):
title = method.title
icon = nil
} }
let value: Bool? let value: Bool?
if let currentMethod = currentMethod { if let currentMethod = currentMethod {

View File

@ -4,18 +4,23 @@ import SwiftSignalKit
public enum ChatTextInputAccessoryItem: Equatable { public enum ChatTextInputAccessoryItem: Equatable {
public enum Key: Hashable { public enum Key: Hashable {
case keyboard case input
case stickers case botInput
case inputButtons
case commands case commands
case silentPost case silentPost
case messageAutoremoveTimeout case messageAutoremoveTimeout
case scheduledMessages case scheduledMessages
} }
case keyboard public enum InputMode: Hashable {
case stickers(isEnabled: Bool, isEmoji: Bool) case keyboard
case inputButtons case stickers
case emoji
case bot
}
case input(isEnabled: Bool, inputMode: InputMode)
case botInput(isEnabled: Bool, inputMode: InputMode)
case commands case commands
case silentPost(Bool) case silentPost(Bool)
case messageAutoremoveTimeout(Int32?) case messageAutoremoveTimeout(Int32?)
@ -23,12 +28,10 @@ public enum ChatTextInputAccessoryItem: Equatable {
public var key: Key { public var key: Key {
switch self { switch self {
case .keyboard: case .input:
return .keyboard return .input
case .stickers: case .botInput:
return .stickers return .botInput
case .inputButtons:
return .inputButtons
case .commands: case .commands:
return .commands return .commands
case .silentPost: case .silentPost:

View File

@ -19,6 +19,7 @@ swift_library(
"//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState", "//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState",
"//submodules/ContextUI:ContextUI", "//submodules/ContextUI:ContextUI",
"//submodules/AppBundle:AppBundle", "//submodules/AppBundle:AppBundle",
"//submodules/TextFormat:TextFormat",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -8,6 +8,7 @@ import AccountContext
import ContextUI import ContextUI
import TelegramCore import TelegramCore
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import TextFormat
public final class ChatSendMessageActionSheetController: ViewController { public final class ChatSendMessageActionSheetController: ViewController {
private var controllerNode: ChatSendMessageActionSheetControllerNode { private var controllerNode: ChatSendMessageActionSheetControllerNode {
@ -33,6 +34,8 @@ public final class ChatSendMessageActionSheetController: ViewController {
private let hapticFeedback = HapticFeedback() private let hapticFeedback = HapticFeedback()
public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, interfaceState: ChatPresentationInterfaceState, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, completion: @escaping () -> Void, sendMessage: @escaping (Bool) -> Void, schedule: @escaping () -> Void) { public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, interfaceState: ChatPresentationInterfaceState, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, completion: @escaping () -> Void, sendMessage: @escaping (Bool) -> Void, schedule: @escaping () -> Void) {
self.context = context self.context = context
self.interfaceState = interfaceState self.interfaceState = interfaceState
@ -79,13 +82,18 @@ public final class ChatSendMessageActionSheetController: ViewController {
var reminders = false var reminders = false
var isSecret = false var isSecret = false
var canSchedule = false var canSchedule = false
var hasEntityKeyboard = false
if case let .peer(peerId) = self.interfaceState.chatLocation { if case let .peer(peerId) = self.interfaceState.chatLocation {
reminders = peerId == context.account.peerId reminders = peerId == context.account.peerId
isSecret = peerId.namespace == Namespaces.Peer.SecretChat isSecret = peerId.namespace == Namespaces.Peer.SecretChat
canSchedule = !isSecret canSchedule = !isSecret
} }
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, forwardedCount: forwardedCount, send: { [weak self] in if case .media = self.interfaceState.inputMode {
hasEntityKeyboard = true
}
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, forwardedCount: forwardedCount, hasEntityKeyboard: hasEntityKeyboard, send: { [weak self] in
self?.sendMessage(false) self?.sendMessage(false)
self?.dismiss(cancel: false) self?.dismiss(cancel: false)
}, sendSilently: { [weak self] in }, sendSilently: { [weak self] in

View File

@ -9,6 +9,7 @@ import TelegramPresentationData
import AccountContext import AccountContext
import AppBundle import AppBundle
import ContextUI import ContextUI
import TextFormat
private let leftInset: CGFloat = 16.0 private let leftInset: CGFloat = 16.0
private let rightInset: CGFloat = 16.0 private let rightInset: CGFloat = 16.0
@ -158,6 +159,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
private let textInputNode: EditableTextNode private let textInputNode: EditableTextNode
private let attachment: Bool private let attachment: Bool
private let forwardedCount: Int? private let forwardedCount: Int?
private let hasEntityKeyboard: Bool
private let send: (() -> Void)? private let send: (() -> Void)?
private let cancel: (() -> Void)? private let cancel: (() -> Void)?
@ -183,7 +185,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
private var animateInputField = false private var animateInputField = false
init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) { init(context: AccountContext, presentationData: PresentationData, reminders: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool, forwardedCount: Int?, hasEntityKeyboard: Bool, send: (() -> Void)?, sendSilently: (() -> Void)?, schedule: (() -> Void)?, cancel: (() -> Void)?) {
self.context = context self.context = context
self.presentationData = presentationData self.presentationData = presentationData
self.sourceSendButton = sourceSendButton self.sourceSendButton = sourceSendButton
@ -191,6 +193,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.textInputNode = textInputNode self.textInputNode = textInputNode
self.attachment = attachment self.attachment = attachment
self.forwardedCount = forwardedCount self.forwardedCount = forwardedCount
self.hasEntityKeyboard = hasEntityKeyboard
self.send = send self.send = send
self.cancel = cancel self.cancel = cancel
@ -422,7 +425,11 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let fromFrame = CGRect(origin: CGPoint(), size: CGSize(width: initialWidth, height: self.textFieldFrame.height + 2.0)) let fromFrame = CGRect(origin: CGPoint(), size: CGSize(width: initialWidth, height: self.textFieldFrame.height + 2.0))
let delta = (fromFrame.height - self.messageClipNode.bounds.height) / 2.0 let delta = (fromFrame.height - self.messageClipNode.bounds.height) / 2.0
let inputHeight = layout.inputHeight ?? 0.0 var inputHeight = layout.inputHeight ?? 0.0
if self.hasEntityKeyboard {
inputHeight = layout.standardInputHeight
}
var clipDelta = delta var clipDelta = delta
if inputHeight.isZero || layout.isNonExclusive { if inputHeight.isZero || layout.isNonExclusive {
clipDelta -= self.contentContainerNode.frame.height + 16.0 clipDelta -= self.contentContainerNode.frame.height + 16.0
@ -531,7 +538,11 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let delta = (toFrame.height - self.messageClipNode.bounds.height) / 2.0 let delta = (toFrame.height - self.messageClipNode.bounds.height) / 2.0
if cancel && self.animateInputField { if cancel && self.animateInputField {
let inputHeight = layout.inputHeight ?? 0.0 var inputHeight = layout.inputHeight ?? 0.0
if self.hasEntityKeyboard {
inputHeight = layout.standardInputHeight
}
var clipDelta = delta var clipDelta = delta
if inputHeight.isZero || layout.isNonExclusive { if inputHeight.isZero || layout.isNonExclusive {
clipDelta -= self.contentContainerNode.frame.height + 16.0 clipDelta -= self.contentContainerNode.frame.height + 16.0
@ -589,8 +600,12 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let menuHeightWithInset = contentSize.height + 16.0 let menuHeightWithInset = contentSize.height + 16.0
let insets = layout.insets(options: [.statusBar, .input]) var insets = layout.insets(options: [.statusBar, .input])
let inputHeight = layout.inputHeight ?? 0.0 var inputHeight = layout.inputHeight ?? 0.0
if self.hasEntityKeyboard {
insets.bottom = max(insets.bottom, layout.standardInputHeight)
inputHeight = layout.standardInputHeight
}
let contentOffset = self.scrollNode.view.contentOffset.y let contentOffset = self.scrollNode.view.contentOffset.y

View File

@ -143,6 +143,7 @@ public final class LottieAnimationComponent: Component {
} }
strongSelf.didPlayToCompletion = true strongSelf.didPlayToCompletion = true
let _ = strongSelf.update(component: component, availableSize: availableSize, transition: transition) let _ = strongSelf.update(component: component, availableSize: availableSize, transition: transition)
strongSelf.currentCompletion = nil
} }
animationView.loopMode = .playOnce animationView.loopMode = .playOnce
} else { } else {
@ -175,10 +176,10 @@ public final class LottieAnimationComponent: Component {
updatePlayback = true updatePlayback = true
} }
} }
} else {
self.component = component
} }
self.component = component
if updateColors, let animationView = self.animationView { if updateColors, let animationView = self.animationView {
if let value = component.colors["__allcolors__"] { if let value = component.colors["__allcolors__"] {
for keypath in animationView.allKeypaths(predicate: { $0.keys.last == "Color" }) { for keypath in animationView.allKeypaths(predicate: { $0.keys.last == "Color" }) {

View File

@ -122,12 +122,14 @@ open class TooltipController: ViewController, StandalonePresentableController {
private let dismissImmediatelyOnLayoutUpdate: Bool private let dismissImmediatelyOnLayoutUpdate: Bool
private var timeoutTimer: SwiftSignalKit.Timer? private var timeoutTimer: SwiftSignalKit.Timer?
private var padding: CGFloat
private var layout: ContainerViewLayout? private var layout: ContainerViewLayout?
private var initialArrowOnBottom: Bool private var initialArrowOnBottom: Bool
public var dismissed: ((Bool) -> Void)? public var dismissed: ((Bool) -> Void)?
public init(content: TooltipControllerContent, baseFontSize: CGFloat, timeout: Double = 2.0, dismissByTapOutside: Bool = false, dismissByTapOutsideSource: Bool = false, dismissImmediatelyOnLayoutUpdate: Bool = false, arrowOnBottom: Bool = true) { public init(content: TooltipControllerContent, baseFontSize: CGFloat, timeout: Double = 2.0, dismissByTapOutside: Bool = false, dismissByTapOutsideSource: Bool = false, dismissImmediatelyOnLayoutUpdate: Bool = false, arrowOnBottom: Bool = true, padding: CGFloat = 8.0) {
self.content = content self.content = content
self.baseFontSize = baseFontSize self.baseFontSize = baseFontSize
self.timeout = timeout self.timeout = timeout
@ -135,6 +137,7 @@ open class TooltipController: ViewController, StandalonePresentableController {
self.dismissByTapOutsideSource = dismissByTapOutsideSource self.dismissByTapOutsideSource = dismissByTapOutsideSource
self.dismissImmediatelyOnLayoutUpdate = dismissImmediatelyOnLayoutUpdate self.dismissImmediatelyOnLayoutUpdate = dismissImmediatelyOnLayoutUpdate
self.initialArrowOnBottom = arrowOnBottom self.initialArrowOnBottom = arrowOnBottom
self.padding = padding
super.init(navigationBarPresentationData: nil) super.init(navigationBarPresentationData: nil)
@ -153,6 +156,7 @@ open class TooltipController: ViewController, StandalonePresentableController {
self.displayNode = TooltipControllerNode(content: self.content, baseFontSize: self.baseFontSize, dismiss: { [weak self] tappedInside in self.displayNode = TooltipControllerNode(content: self.content, baseFontSize: self.baseFontSize, dismiss: { [weak self] tappedInside in
self?.dismiss(tappedInside: tappedInside) self?.dismiss(tappedInside: tappedInside)
}, dismissByTapOutside: self.dismissByTapOutside, dismissByTapOutsideSource: self.dismissByTapOutsideSource) }, dismissByTapOutside: self.dismissByTapOutside, dismissByTapOutsideSource: self.dismissByTapOutsideSource)
self.controllerNode.padding = self.padding
self.controllerNode.arrowOnBottom = self.initialArrowOnBottom self.controllerNode.arrowOnBottom = self.initialArrowOnBottom
self.displayNodeDidLoad() self.displayNodeDidLoad()
} }

View File

@ -19,6 +19,8 @@ final class TooltipControllerNode: ASDisplayNode {
var sourceRect: CGRect? var sourceRect: CGRect?
var arrowOnBottom: Bool = true var arrowOnBottom: Bool = true
var padding: CGFloat = 8.0
private var dismissedByTouchOutside = false private var dismissedByTouchOutside = false
private var dismissByTapOutsideSource = false private var dismissByTapOutsideSource = false
@ -122,7 +124,7 @@ final class TooltipControllerNode: ASDisplayNode {
} }
self.arrowOnBottom = arrowOnBottom self.arrowOnBottom = arrowOnBottom
let horizontalOrigin: CGFloat = floor(min(max(8.0, sourceRect.midX - contentSize.width / 2.0), layout.size.width - contentSize.width - 8.0)) let horizontalOrigin: CGFloat = floor(min(max(self.padding, sourceRect.midX - contentSize.width / 2.0), layout.size.width - contentSize.width - self.padding))
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin), size: contentSize)) transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin), size: contentSize))
self.containerNode.relativeArrowPosition = (sourceRect.midX - horizontalOrigin, arrowOnBottom) self.containerNode.relativeArrowPosition = (sourceRect.midX - horizontalOrigin, arrowOnBottom)

View File

@ -373,8 +373,17 @@ private final class GiftComponent: CombinedComponent {
) )
let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitle.size.height + insets.bottom) let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitle.size.height + insets.bottom)
let distance = context.availableSize.width - insets.left - insets.right - label.size.width - subtitle.size.width - discountSize.width - 7.0
let labelOriginY: CGFloat
if distance > 8.0 {
labelOriginY = size.height / 2.0
} else {
labelOriginY = insets.top + title.size.height / 2.0
}
context.add(label context.add(label
.position(CGPoint(x: context.availableSize.width - insets.right - label.size.width / 2.0, y: size.height / 2.0)) .position(CGPoint(x: context.availableSize.width - insets.right - label.size.width / 2.0, y: labelOriginY))
) )
context.add(check context.add(check

View File

@ -348,6 +348,12 @@ final class StickerPackEmojisItemNode: GridItemNode {
self.visibleItemLayers[id] = nil self.visibleItemLayers[id] = nil
} }
} }
for id in self.visibleItemPlaceholderViews.keys {
if !validIds.contains(id) {
self.visibleItemPlaceholderViews[id]?.removeFromSuperview()
self.visibleItemPlaceholderViews[id] = nil
}
}
} }
private func updateShimmerIfNeeded() { private func updateShimmerIfNeeded() {

View File

@ -120,6 +120,21 @@ public struct BotPaymentForm : Equatable {
public let nativeProvider: BotPaymentNativeProvider? public let nativeProvider: BotPaymentNativeProvider?
public let savedInfo: BotPaymentRequestedInfo? public let savedInfo: BotPaymentRequestedInfo?
public let savedCredentials: BotPaymentSavedCredentials? public let savedCredentials: BotPaymentSavedCredentials?
public let additionalPaymentMethods: [BotPaymentMethod]
}
public struct BotPaymentMethod: Equatable {
public let url: String
public let title: String
}
extension BotPaymentMethod {
init(apiPaymentFormMethod: Api.PaymentFormMethod) {
switch apiPaymentFormMethod {
case let .paymentFormMethod(url, title):
self.init(url: url, title: title)
}
}
} }
public enum BotPaymentFormRequestError { public enum BotPaymentFormRequestError {
@ -270,7 +285,6 @@ func _internal_fetchBotPaymentForm(postbox: Postbox, network: Network, source: B
let _ = title let _ = title
let _ = description let _ = description
let _ = photo let _ = photo
let _ = additionalMethods
var peers: [Peer] = [] var peers: [Peer] = []
for user in apiUsers { for user in apiUsers {
@ -297,7 +311,9 @@ func _internal_fetchBotPaymentForm(postbox: Postbox, network: Network, source: B
parsedSavedCredentials = .card(id: id, title: title) parsedSavedCredentials = .card(id: id, title: title)
} }
} }
return BotPaymentForm(id: id, canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, paymentBotId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(providerId)), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials)
let additionalPaymentMethods = additionalMethods?.map({ BotPaymentMethod(apiPaymentFormMethod: $0) }) ?? []
return BotPaymentForm(id: id, canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, paymentBotId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId)), providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(providerId)), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials, additionalPaymentMethods: additionalPaymentMethods)
} }
} }
|> mapError { _ -> BotPaymentFormRequestError in } |> mapError { _ -> BotPaymentFormRequestError in }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1127,6 +1127,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let packReference = packReferences.first, let strongSelf = self else { guard let packReference = packReferences.first, let strongSelf = self else {
return return
} }
strongSelf.chatDisplayNode.dismissTextInput()
let controller = StickerPackScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(packReferences), parentNavigationController: strongSelf.effectiveNavigationController) let controller = StickerPackScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, mainStickerPack: packReference, stickerPacks: Array(packReferences), parentNavigationController: strongSelf.effectiveNavigationController)
strongSelf.present(controller, in: .window(.root)) strongSelf.present(controller, in: .window(.root))
} }
@ -8446,6 +8447,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.controllerInteraction?.scheduleCurrentMessage() strongSelf.controllerInteraction?.scheduleCurrentMessage()
} }
}) })
controller.emojiViewProvider = strongSelf.chatDisplayNode.textInputPanelNode?.emojiViewProvider
strongSelf.sendMessageActionsController = controller strongSelf.sendMessageActionsController = controller
if layout.isNonExclusive { if layout.isNonExclusive {
strongSelf.present(controller, in: .window(.root)) strongSelf.present(controller, in: .window(.root))
@ -15526,7 +15528,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let tooltipController = self.mediaRecordingModeTooltipController { if let tooltipController = self.mediaRecordingModeTooltipController {
tooltipController.updateContent(.text(text), animated: true, extendTimer: true) tooltipController.updateContent(.text(text), animated: true, extendTimer: true)
} else if let rect = rect { } else if let rect = rect {
let tooltipController = TooltipController(content: .text(text), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize) let tooltipController = TooltipController(content: .text(text), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, padding: 2.0)
self.mediaRecordingModeTooltipController = tooltipController self.mediaRecordingModeTooltipController = tooltipController
tooltipController.dismissed = { [weak self, weak tooltipController] _ in tooltipController.dismissed = { [weak self, weak tooltipController] _ in
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.mediaRecordingModeTooltipController === tooltipController { if let strongSelf = self, let tooltipController = tooltipController, strongSelf.mediaRecordingModeTooltipController === tooltipController {
@ -15547,7 +15549,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
self.sendingOptionsTooltipController?.dismiss() self.sendingOptionsTooltipController?.dismiss()
let tooltipController = TooltipController(content: .text(self.presentationData.strings.Conversation_SendingOptionsTooltip), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, timeout: 3.0, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true) let tooltipController = TooltipController(content: .text(self.presentationData.strings.Conversation_SendingOptionsTooltip), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, timeout: 3.0, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true, padding: 2.0)
self.sendingOptionsTooltipController = tooltipController self.sendingOptionsTooltipController = tooltipController
tooltipController.dismissed = { [weak self, weak tooltipController] _ in tooltipController.dismissed = { [weak self, weak tooltipController] _ in
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.sendingOptionsTooltipController === tooltipController { if let strongSelf = self, let tooltipController = tooltipController, strongSelf.sendingOptionsTooltipController === tooltipController {

View File

@ -314,13 +314,13 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
switch chatPresentationInterfaceState.inputMode { switch chatPresentationInterfaceState.inputMode {
case .media: case .media:
accessoryItems.append(.keyboard) accessoryItems.append(.input(isEnabled: true, inputMode: .keyboard))
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState) return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
case .inputButtons: case .inputButtons:
return ChatTextInputPanelState(accessoryItems: [.keyboard], contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState) return ChatTextInputPanelState(accessoryItems: [.botInput(isEnabled: true, inputMode: .keyboard)], contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
case .none, .text: case .none, .text:
if let _ = chatPresentationInterfaceState.interfaceState.editMessage { if let _ = chatPresentationInterfaceState.interfaceState.editMessage {
accessoryItems.append(.stickers(isEnabled: true, isEmoji: true)) accessoryItems.append(.input(isEnabled: true, inputMode: .emoji))
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState) return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)
} else { } else {
@ -371,13 +371,13 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
} }
if stickersEnabled { if stickersEnabled {
accessoryItems.append(.stickers(isEnabled: true, isEmoji: stickersAreEmoji)) accessoryItems.append(.input(isEnabled: true, inputMode: stickersAreEmoji ? .emoji : .stickers))
} else { } else {
accessoryItems.append(.stickers(isEnabled: true, isEmoji: true)) accessoryItems.append(.input(isEnabled: true, inputMode: .emoji))
} }
if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id { if isTextEmpty, let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup, chatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId != message.id {
accessoryItems.append(.inputButtons) accessoryItems.append(.botInput(isEnabled: true, inputMode: .bot))
} }
} }
return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState) return ChatTextInputPanelState(accessoryItems: accessoryItems, contextPlaceholder: contextPlaceholder, mediaRecordingState: chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState)

View File

@ -10,6 +10,8 @@ import AccountContext
import ChatInterfaceState import ChatInterfaceState
import AudioBlob import AudioBlob
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import ComponentFlow
import LottieAnimationComponent
private let offsetThreshold: CGFloat = 10.0 private let offsetThreshold: CGFloat = 10.0
private let dismissOffsetThreshold: CGFloat = 70.0 private let dismissOffsetThreshold: CGFloat = 70.0
@ -185,7 +187,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
private var modeTimeoutTimer: SwiftSignalKit.Timer? private var modeTimeoutTimer: SwiftSignalKit.Timer?
private let innerIconView: UIImageView private let animationView: ComponentView<Empty>
private var recordingOverlay: ChatTextInputAudioRecordingOverlay? private var recordingOverlay: ChatTextInputAudioRecordingOverlay?
private var startTouchLocation: CGPoint? private var startTouchLocation: CGPoint?
@ -288,7 +290,7 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) { init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.innerIconView = UIImageView() self.animationView = ComponentView<Empty>()
self.presentController = presentController self.presentController = presentController
super.init(frame: CGRect()) super.init(frame: CGRect())
@ -297,8 +299,6 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
self.pallete = legacyInputMicPalette(from: theme) self.pallete = legacyInputMicPalette(from: theme)
self.insertSubview(self.innerIconView, at: 0)
self.disablesInteractiveTransitionGestureRecognizer = true self.disablesInteractiveTransitionGestureRecognizer = true
self.updateMode(mode: self.mode, animated: false, force: true) self.updateMode(mode: self.mode, animated: false, force: true)
@ -318,51 +318,81 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
} }
private func updateMode(mode: ChatTextInputMediaRecordingButtonMode, animated: Bool, force: Bool) { private func updateMode(mode: ChatTextInputMediaRecordingButtonMode, animated: Bool, force: Bool) {
let previousMode = self.mode
if mode != self.mode || force { if mode != self.mode || force {
self.mode = mode self.mode = mode
if animated { self.updateAnimation(previousMode: previousMode)
let previousView = UIImageView(image: self.innerIconView.image) }
previousView.frame = self.innerIconView.frame }
self.addSubview(previousView)
previousView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
previousView.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false, completion: { [weak previousView] _ in
previousView?.removeFromSuperview()
})
}
switch self.mode { private func updateAnimation(previousMode: ChatTextInputMediaRecordingButtonMode) {
case .audio: let image: UIImage?
self.icon = PresentationResourcesChat.chatInputPanelVoiceActiveButtonImage(self.theme) switch self.mode {
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme) case .audio:
case .video: self.icon = PresentationResourcesChat.chatInputPanelVoiceActiveButtonImage(self.theme)
self.icon = PresentationResourcesChat.chatInputPanelVideoActiveButtonImage(self.theme) image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVideoButtonImage(self.theme) case .video:
} self.icon = PresentationResourcesChat.chatInputPanelVideoActiveButtonImage(self.theme)
if let image = self.innerIconView.image { image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
let size = self.bounds.size }
let iconSize = image.size
self.innerIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
}
if animated { let size = self.bounds.size
self.innerIconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false) let iconSize: CGSize
self.innerIconView.layer.animateSpring(from: 0.4 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) if let image = image {
iconSize = image.size
} else {
iconSize = size
}
let animationFrame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
let animationName: String
switch self.mode {
case .audio:
animationName = "anim_videoToMic"
case .video:
animationName = "anim_micToVideo"
}
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
if previousMode != mode {
animationMode = .animating(loop: false)
}
let colorKeys = ["__allcolors__"]
var colors: [String: UIColor] = [:]
for colorKey in colorKeys {
colors[colorKey] = self.theme.chat.inputPanel.panelControlColor
}
let _ = animationView.update(
transition: .immediate,
component: AnyComponent(LottieAnimationComponent(
animation: LottieAnimationComponent.AnimationItem(
name: animationName,
mode: animationMode
),
colors: colors,
size: animationFrame.size
)),
environment: {},
containerSize: animationFrame.size
)
// self.innerIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
if let view = animationView.view {
view.isUserInteractionEnabled = false
if view.superview == nil {
self.insertSubview(view, at: 0)
} }
view.frame = animationFrame
} }
} }
func updateTheme(theme: PresentationTheme) { func updateTheme(theme: PresentationTheme) {
self.theme = theme self.theme = theme
switch self.mode { self.updateAnimation(previousMode: self.mode)
case .audio:
self.icon = PresentationResourcesChat.chatInputPanelVoiceActiveButtonImage(self.theme)
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVoiceButtonImage(self.theme)
case .video:
self.icon = PresentationResourcesChat.chatInputPanelVideoActiveButtonImage(self.theme)
self.innerIconView.image = PresentationResourcesChat.chatInputPanelVideoButtonImage(self.theme)
}
self.pallete = legacyInputMicPalette(from: theme) self.pallete = legacyInputMicPalette(from: theme)
self.micDecorationValue?.setColor(self.theme.chat.inputPanel.actionControlFillColor) self.micDecorationValue?.setColor(self.theme.chat.inputPanel.actionControlFillColor)
@ -467,8 +497,8 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
micDecoration.isHidden = false micDecoration.isHidden = false
micDecoration.startAnimating() micDecoration.startAnimating()
innerIconView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) self.animationView.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
innerIconView.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false) self.animationView.view?.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false)
} }
override func animateOut(_ toSmallSize: Bool) { override func animateOut(_ toSmallSize: Bool) {
@ -480,8 +510,8 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.03, delay: 0.15, removeOnCompletion: false) micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.03, delay: 0.15, removeOnCompletion: false)
} else { } else {
micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false) micDecoration.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false)
innerIconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false) self.animationView.view?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, removeOnCompletion: false)
innerIconView.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, removeOnCompletion: false) self.animationView.view?.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, removeOnCompletion: false)
} }
} }
@ -490,8 +520,10 @@ final class ChatTextInputMediaRecordingButton: TGModernConversationInputMicButto
let size = self.bounds.size let size = self.bounds.size
if size != self.previousSize { if size != self.previousSize {
self.previousSize = size self.previousSize = size
let iconSize = self.innerIconView.bounds.size if let view = self.animationView.view {
self.innerIconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize) let iconSize = view.bounds.size
view.frame = CGRect(origin: CGPoint(x: floor((size.width - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
}
} }
} }
} }

View File

@ -59,9 +59,12 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
self.iconImageNode.isUserInteractionEnabled = false self.iconImageNode.isUserInteractionEnabled = false
self.addSubnode(self.iconImageNode) self.addSubnode(self.iconImageNode)
if case .stickers = item { switch item {
self.iconImageNode.isHidden = true case .input, .botInput:
self.animationView = ComponentView<Empty>() self.iconImageNode.isHidden = true
self.animationView = ComponentView<Empty>()
default:
break
} }
if let text = text { if let text = text {
@ -116,12 +119,15 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
static func imageAndInsets(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) -> (UIImage?, String?, String, CGFloat, UIEdgeInsets) { static func imageAndInsets(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) -> (UIImage?, String?, String, CGFloat, UIEdgeInsets) {
switch item { switch item {
case .keyboard: case let .input(isEnabled, inputMode), let .botInput(isEnabled, inputMode):
return (PresentationResourcesChat.chatInputTextFieldKeyboardImage(theme), nil, strings.VoiceOver_Keyboard, 1.0, UIEdgeInsets()) switch inputMode {
case let .stickers(enabled, _): case .keyboard:
return (PresentationResourcesChat.chatInputTextFieldStickersImage(theme), nil, strings.VoiceOver_Stickers, enabled ? 1.0 : 0.4, UIEdgeInsets()) return (PresentationResourcesChat.chatInputTextFieldKeyboardImage(theme), nil, strings.VoiceOver_Keyboard, 1.0, UIEdgeInsets())
case .inputButtons: case .stickers, .emoji:
return (PresentationResourcesChat.chatInputTextFieldInputButtonsImage(theme), nil, strings.VoiceOver_BotKeyboard, 1.0, UIEdgeInsets()) return (PresentationResourcesChat.chatInputTextFieldStickersImage(theme), nil, strings.VoiceOver_Stickers, isEnabled ? 1.0 : 0.4, UIEdgeInsets())
case .bot:
return (PresentationResourcesChat.chatInputTextFieldInputButtonsImage(theme), nil, strings.VoiceOver_BotKeyboard, 1.0, UIEdgeInsets())
}
case .commands: case .commands:
return (PresentationResourcesChat.chatInputTextFieldCommandsImage(theme), nil, strings.VoiceOver_BotCommands, 1.0, UIEdgeInsets()) return (PresentationResourcesChat.chatInputTextFieldCommandsImage(theme), nil, strings.VoiceOver_BotCommands, 1.0, UIEdgeInsets())
case let .silentPost(value): case let .silentPost(value):
@ -143,7 +149,7 @@ 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 .input, .botInput, .silentPost, .commands, .scheduledMessages:
return 32.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)
@ -156,6 +162,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
} }
func updateLayout(item: ChatTextInputAccessoryItem, size: CGSize) { func updateLayout(item: ChatTextInputAccessoryItem, size: CGSize) {
let previousItem = self.item
self.item = item self.item = item
if let image = self.iconImageNode.image { if let image = self.iconImageNode.image {
@ -165,26 +172,112 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size) let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size)
self.iconImageNode.frame = imageFrame self.iconImageNode.frame = imageFrame
if case let .stickers(_, isEmoji) = item, let animationView = self.animationView { if let animationView = self.animationView {
let animationFrame = imageFrame.insetBy(dx: -4.0, dy: -4.0) let animationFrame = imageFrame.insetBy(dx: -4.0, dy: -4.0)
var colors: [String: UIColor] = [:] var previousInputMode: ChatTextInputAccessoryItem.InputMode?
let colorKeys: [String] = [ var inputMode: ChatTextInputAccessoryItem.InputMode?
switch previousItem {
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
previousInputMode = itemInputMode
default:
break
}
switch item {
case let .input(_, itemInputMode), let .botInput(_, itemInputMode):
inputMode = itemInputMode
default:
break
}
let emojiColorKeys = [
"Ellipse 33.Ellipse 33.Stroke 1", "Ellipse 33.Ellipse 33.Stroke 1",
"Ellipse 34.Ellipse 34.Stroke 1", "Ellipse 34.Ellipse 34.Stroke 1",
"Oval.Oval.Fill 1", "Oval.Oval.Fill 1",
"Oval 2.Oval.Fill 1", "Oval 2.Oval.Fill 1",
"Path 85.Path 85.Stroke 1" "Path 85.Path 85.Stroke 1"
] ]
var colorKeys: [String] = ["__allcolors__"]
let animationName: String
var animationMode: LottieAnimationComponent.AnimationItem.Mode = .still(position: .end)
if let inputMode = inputMode {
switch inputMode {
case .keyboard:
if let previousInputMode = previousInputMode {
if case .stickers = previousInputMode {
animationName = "anim_stickerToKey"
animationMode = .animating(loop: false)
} else if case .emoji = previousInputMode {
animationName = "anim_smileToKey"
animationMode = .animating(loop: false)
} else if case .bot = previousInputMode {
animationName = "anim_botToKey"
animationMode = .animating(loop: false)
} else {
animationName = "anim_stickerToKey"
}
} else {
animationName = "anim_stickerToKey"
}
case .stickers:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "anim_keyToSticker"
animationMode = .animating(loop: false)
} else if case .emoji = previousInputMode {
animationName = "anim_smileToSticker"
animationMode = .animating(loop: false)
colorKeys = emojiColorKeys
} else {
animationName = "anim_keyToSticker"
}
} else {
animationName = "anim_keyToSticker"
}
case .emoji:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "anim_keyToSmile"
animationMode = .animating(loop: false)
} else if case .stickers = previousInputMode {
animationName = "anim_stickerToSmile"
animationMode = .animating(loop: false)
colorKeys = emojiColorKeys
} else {
animationName = "anim_keyToSmile"
}
} else {
animationName = "anim_keyToSmile"
}
case .bot:
if let previousInputMode = previousInputMode {
if case .keyboard = previousInputMode {
animationName = "anim_keyToBot"
animationMode = .animating(loop: false)
} else {
animationName = "anim_keyToBot"
}
} else {
animationName = "anim_keyToBot"
}
}
} else {
animationName = ""
}
var colors: [String: UIColor] = [:]
for colorKey in colorKeys { for colorKey in colorKeys {
colors[colorKey] = self.theme.chat.inputPanel.inputControlColor colors[colorKey] = self.theme.chat.inputPanel.inputControlColor
} }
let _ = animationView.update( let _ = animationView.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(LottieAnimationComponent( component: AnyComponent(LottieAnimationComponent(
animation: LottieAnimationComponent.AnimationItem( animation: LottieAnimationComponent.AnimationItem(
name: !isEmoji ? "anim_stickertosmile" : "anim_smiletosticker", name: animationName,
mode: .animateTransitionFromPrevious mode: animationMode
), ),
colors: colors, colors: colors,
size: animationFrame.size size: animationFrame.size
@ -193,6 +286,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
containerSize: animationFrame.size containerSize: animationFrame.size
) )
if let view = animationView.view { if let view = animationView.view {
view.isUserInteractionEnabled = false
if view.superview == nil { if view.superview == nil {
self.view.addSubview(view) self.view.addSubview(view)
} }
@ -586,7 +680,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
private var touchDownGestureRecognizer: TouchDownGestureRecognizer? private var touchDownGestureRecognizer: TouchDownGestureRecognizer?
private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)? var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) { init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
self.presentationInterfaceState = presentationInterfaceState self.presentationInterfaceState = presentationInterfaceState
@ -2942,20 +3036,23 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
for (item, currentButton) in self.accessoryItemButtons { for (item, currentButton) in self.accessoryItemButtons {
if currentButton === button { if currentButton === button {
switch item { switch item {
case let .stickers(enabled, _): case let .input(isEnabled, inputMode), let .botInput(isEnabled, inputMode):
if enabled { switch inputMode {
self.interfaceInteraction?.openStickers() case .keyboard:
} else { self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
self.interfaceInteraction?.displayRestrictedInfo(.stickers, .tooltip) return (.text, state.keyboardButtonsMessage?.id)
})
case .stickers, .emoji:
if isEnabled {
self.interfaceInteraction?.openStickers()
} else {
self.interfaceInteraction?.displayRestrictedInfo(.stickers, .tooltip)
}
case .bot:
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.inputButtons, nil)
})
} }
case .keyboard:
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.text, state.keyboardButtonsMessage?.id)
})
case .inputButtons:
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.inputButtons, nil)
})
case .commands: case .commands:
self.interfaceInteraction?.updateTextInputStateAndMode { _, inputMode in self.interfaceInteraction?.updateTextInputStateAndMode { _, inputMode in
return (ChatTextInputState(inputText: NSAttributedString(string: "/")), .text) return (ChatTextInputState(inputText: NSAttributedString(string: "/")), .text)
@ -3011,7 +3108,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
func frameForStickersButton() -> CGRect? { func frameForStickersButton() -> CGRect? {
for (item, button) in self.accessoryItemButtons { for (item, button) in self.accessoryItemButtons {
if case .stickers = item { if case let .input(_, inputMode) = item, case .stickers = inputMode {
return button.frame.insetBy(dx: 0.0, dy: 6.0) return button.frame.insetBy(dx: 0.0, dy: 6.0)
} }
} }

View File

@ -329,6 +329,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}, schedule: { [weak textInputPanelNode] in }, schedule: { [weak textInputPanelNode] in
textInputPanelNode?.sendMessage(.schedule) textInputPanelNode?.sendMessage(.schedule)
}) })
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
strongSelf.presentInGlobalOverlay(controller, nil) strongSelf.presentInGlobalOverlay(controller, nil)
}, openScheduledMessages: { }, openScheduledMessages: {
}, openPeersNearby: { }, openPeersNearby: {