mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Bot start button improvements
This commit is contained in:
@@ -34,6 +34,8 @@ import UndoUI
|
||||
import PremiumUI
|
||||
import StickerPeekUI
|
||||
import LottieComponent
|
||||
import SolidRoundedButtonNode
|
||||
import TooltipUI
|
||||
|
||||
private let accessoryButtonFont = Font.medium(14.0)
|
||||
private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers])
|
||||
@@ -488,6 +490,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
private let menuButtonIconNode: MenuIconNode
|
||||
private let menuButtonTextNode: ImmediateTextNode
|
||||
|
||||
private let startButton: SolidRoundedButtonNode
|
||||
|
||||
let sendAsAvatarButtonNode: HighlightableButtonNode
|
||||
let sendAsAvatarReferenceNode: ContextReferenceContentNode
|
||||
let sendAsAvatarContainerNode: ContextControllerSourceNode
|
||||
@@ -575,6 +579,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
return self.actionButtons.micButton
|
||||
}
|
||||
|
||||
private let startingBotDisposable = MetaDisposable()
|
||||
private let statusDisposable = MetaDisposable()
|
||||
override var interfaceInteraction: ChatPanelInterfaceInteraction? {
|
||||
didSet {
|
||||
@@ -585,9 +590,28 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self?.updateIsProcessingInlineRequest(value)
|
||||
}))
|
||||
}
|
||||
if let startingBot = self.interfaceInteraction?.statuses?.startingBot {
|
||||
self.startingBotDisposable.set((startingBot |> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.startingBotProgress = value
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var startingBotProgress = false {
|
||||
didSet {
|
||||
// if self.startingBotProgress != oldValue {
|
||||
// if self.startingBotProgress {
|
||||
// self.startButton.transitionToProgress()
|
||||
// } else {
|
||||
// self.startButton.transitionFromProgress()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
func updateInputTextState(_ state: ChatTextInputState, keepSendButtonEnabled: Bool, extendedSearchLayout: Bool, accessoryItems: [ChatTextInputAccessoryItem], animated: Bool) {
|
||||
if let currentState = self.presentationInterfaceState {
|
||||
var updateAccessoryButtons = false
|
||||
@@ -695,6 +719,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
private let presentationContext: ChatPresentationContext?
|
||||
|
||||
private var tooltipController: TooltipScreen?
|
||||
|
||||
init(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
|
||||
self.presentationInterfaceState = presentationInterfaceState
|
||||
self.presentationContext = presentationContext
|
||||
@@ -738,6 +764,10 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.menuButtonIconNode.customColor = presentationInterfaceState.theme.chat.inputPanel.actionControlForegroundColor
|
||||
self.menuButtonTextNode = ImmediateTextNode()
|
||||
|
||||
self.startButton = SolidRoundedButtonNode(title: presentationInterfaceState.strings.Bot_Start, theme: SolidRoundedButtonTheme(theme: presentationInterfaceState.theme), height: 50.0, cornerRadius: 11.0, gloss: true)
|
||||
self.startButton.progressType = .embedded
|
||||
self.startButton.isHidden = true
|
||||
|
||||
self.sendAsAvatarButtonNode = HighlightableButtonNode()
|
||||
self.sendAsAvatarReferenceNode = ContextReferenceContentNode()
|
||||
self.sendAsAvatarContainerNode = ContextControllerSourceNode()
|
||||
@@ -820,6 +850,22 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
self.startButton.pressed = { [weak self] in
|
||||
guard let self, let presentationInterfaceState = self.presentationInterfaceState else {
|
||||
return
|
||||
}
|
||||
if presentationInterfaceState.peerIsBlocked {
|
||||
self.interfaceInteraction?.unblockPeer()
|
||||
} else {
|
||||
self.interfaceInteraction?.sendBotStart(presentationInterfaceState.botStartPayload)
|
||||
}
|
||||
|
||||
if let tooltipController = self.tooltipController {
|
||||
self.tooltipController = nil
|
||||
tooltipController.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
self.attachmentButton.addTarget(self, action: #selector(self.attachmentButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.attachmentButtonDisabledNode.addTarget(self, action: #selector(self.attachmentButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
@@ -920,6 +966,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.clippingNode.addSubnode(self.menuButton)
|
||||
self.clippingNode.addSubnode(self.attachmentButton)
|
||||
self.clippingNode.addSubnode(self.attachmentButtonDisabledNode)
|
||||
|
||||
self.clippingNode.addSubnode(self.startButton)
|
||||
|
||||
self.clippingNode.addSubnode(self.actionButtons)
|
||||
self.clippingNode.addSubnode(self.counterTextNode)
|
||||
@@ -972,6 +1020,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
deinit {
|
||||
self.statusDisposable.dispose()
|
||||
self.tooltipController?.dismiss()
|
||||
}
|
||||
|
||||
func loadTextInputNodeIfNeeded() {
|
||||
@@ -1153,6 +1202,110 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
}
|
||||
return minimalHeight
|
||||
}
|
||||
|
||||
private var animatingTransition = false
|
||||
private func animateBotButtonInFromMenu(transition: ContainedViewLayoutTransition) {
|
||||
guard !self.animatingTransition else {
|
||||
return
|
||||
}
|
||||
guard let menuIconSnapshotView = self.menuButtonIconNode.view.snapshotView(afterScreenUpdates: false), let menuTextSnapshotView = self.menuButtonTextNode.view.snapshotView(afterScreenUpdates: false) else {
|
||||
self.startButton.highlightEnabled = true
|
||||
self.menuButton.isHidden = true
|
||||
return
|
||||
}
|
||||
if transition.isAnimated {
|
||||
self.animatingTransition = true
|
||||
self.startButton.highlightEnabled = false
|
||||
}
|
||||
|
||||
self.menuButton.isHidden = true
|
||||
|
||||
transition.animateFrame(layer: self.startButton.layer, from: self.menuButton.frame)
|
||||
transition.animateFrame(layer: self.startButton.buttonBackgroundNode.layer, from: CGRect(origin: .zero, size: self.menuButton.frame.size))
|
||||
transition.animatePosition(node: self.startButton.titleNode, from: CGPoint(x: self.menuButton.frame.width / 2.0, y: self.menuButton.frame.height / 2.0))
|
||||
|
||||
let targetButtonCornerRadius = self.startButton.buttonCornerRadius
|
||||
self.startButton.buttonBackgroundNode.cornerRadius = self.menuButton.cornerRadius
|
||||
transition.updateCornerRadius(node: self.startButton.buttonBackgroundNode, cornerRadius: targetButtonCornerRadius)
|
||||
transition.animateTransformScale(node: self.startButton.titleNode, from: 0.4)
|
||||
self.startButton.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
||||
let menuContentDelta = (self.startButton.frame.width - self.menuButton.frame.width) / 2.0
|
||||
menuIconSnapshotView.frame = self.menuButtonIconNode.frame.offsetBy(dx: self.menuButton.frame.minX, dy: self.menuButton.frame.minY)
|
||||
self.view.addSubview(menuIconSnapshotView)
|
||||
menuIconSnapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak menuIconSnapshotView] _ in
|
||||
menuIconSnapshotView?.removeFromSuperview()
|
||||
})
|
||||
transition.updatePosition(layer: menuIconSnapshotView.layer, position: CGPoint(x: menuIconSnapshotView.center.x + menuContentDelta, y: self.startButton.position.y))
|
||||
|
||||
menuTextSnapshotView.frame = self.menuButtonTextNode.frame.offsetBy(dx: self.menuButton.frame.minX + 19.0, dy: self.menuButton.frame.minY)
|
||||
self.view.addSubview(menuTextSnapshotView)
|
||||
menuTextSnapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak menuTextSnapshotView, weak self] _ in
|
||||
menuTextSnapshotView?.removeFromSuperview()
|
||||
self?.animatingTransition = false
|
||||
self?.startButton.highlightEnabled = true
|
||||
})
|
||||
transition.updatePosition(layer: menuTextSnapshotView.layer, position: CGPoint(x: menuTextSnapshotView.center.x + menuContentDelta, y: self.startButton.position.y))
|
||||
}
|
||||
|
||||
func animateBotButtonOutToMenu(transition: ContainedViewLayoutTransition) {
|
||||
guard !self.animatingTransition else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let menuIconSnapshotView = self.menuButtonIconNode.view.snapshotView(afterScreenUpdates: false), let menuTextSnapshotView = self.menuButtonTextNode.view.snapshotView(afterScreenUpdates: false) else {
|
||||
self.startButton.highlightEnabled = true
|
||||
self.menuButton.isHidden = false
|
||||
return
|
||||
}
|
||||
|
||||
if transition.isAnimated {
|
||||
self.animatingTransition = true
|
||||
self.startButton.highlightEnabled = false
|
||||
}
|
||||
|
||||
let sourceButtonFrame = self.startButton.frame
|
||||
transition.updateFrame(node: self.startButton, frame: self.menuButton.frame)
|
||||
transition.updateFrame(node: self.startButton.buttonBackgroundNode, frame: CGRect(origin: .zero, size: self.menuButton.frame.size))
|
||||
let sourceButtonTextPosition = self.startButton.titleNode.position
|
||||
transition.updatePosition(node: self.startButton.titleNode, position: CGPoint(x: self.menuButton.frame.width / 2.0, y: self.menuButton.frame.height / 2.0))
|
||||
|
||||
let sourceButtonCornerRadius = self.startButton.buttonCornerRadius
|
||||
transition.updateCornerRadius(node: self.startButton.buttonBackgroundNode, cornerRadius: self.menuButton.cornerRadius)
|
||||
transition.animateTransformScale(layer: self.startButton.titleNode.layer, from: CGPoint(x: 1.0, y: 1.0), to: CGPoint(x: 0.4, y: 0.4))
|
||||
Queue.mainQueue().justDispatch {
|
||||
self.startButton.titleNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
let menuContentDelta = (sourceButtonFrame.width - self.menuButton.frame.width) / 2.0
|
||||
var menuIconSnapshotViewFrame = self.menuButtonIconNode.frame.offsetBy(dx: self.menuButton.frame.minX + menuContentDelta, dy: self.menuButton.frame.minY)
|
||||
menuIconSnapshotViewFrame.origin.y = self.startButton.position.y - menuIconSnapshotViewFrame.height / 2.0
|
||||
menuIconSnapshotView.frame = menuIconSnapshotViewFrame
|
||||
self.view.addSubview(menuIconSnapshotView)
|
||||
menuIconSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
transition.updatePosition(layer: menuIconSnapshotView.layer, position: CGPoint(x: menuIconSnapshotView.center.x - menuContentDelta, y: self.menuButton.position.y))
|
||||
|
||||
var menuTextSnapshotViewFrame = self.menuButtonTextNode.frame.offsetBy(dx: self.menuButton.frame.minX + 19.0 + menuContentDelta, dy: self.menuButton.frame.minY)
|
||||
menuTextSnapshotViewFrame.origin.y = self.startButton.position.y - menuTextSnapshotViewFrame.height / 2.0
|
||||
menuTextSnapshotView.frame = menuTextSnapshotViewFrame
|
||||
self.view.addSubview(menuTextSnapshotView)
|
||||
menuTextSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
transition.updatePosition(layer: menuTextSnapshotView.layer, position: CGPoint(x: menuTextSnapshotView.center.x - menuContentDelta, y: self.menuButton.position.y), completion: { [weak self, weak menuIconSnapshotView, weak menuTextSnapshotView] _ in
|
||||
self?.animatingTransition = false
|
||||
|
||||
menuIconSnapshotView?.removeFromSuperview()
|
||||
menuTextSnapshotView?.removeFromSuperview()
|
||||
|
||||
self?.menuButton.isHidden = false
|
||||
self?.startButton.isHidden = true
|
||||
self?.startButton.frame = sourceButtonFrame
|
||||
self?.startButton.buttonBackgroundNode.frame = CGRect(origin: .zero, size: sourceButtonFrame.size)
|
||||
self?.startButton.titleNode.position = sourceButtonTextPosition
|
||||
self?.startButton.titleNode.layer.removeAllAnimations()
|
||||
self?.startButton.buttonBackgroundNode.cornerRadius = sourceButtonCornerRadius
|
||||
self?.startButton.highlightEnabled = true
|
||||
})
|
||||
}
|
||||
|
||||
private var absoluteRect: (CGRect, CGSize)?
|
||||
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
@@ -1161,7 +1314,15 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
if !self.actionButtons.frame.width.isZero {
|
||||
self.actionButtons.updateAbsoluteRect(CGRect(origin: rect.origin.offsetBy(dx: self.actionButtons.frame.minX, dy: self.actionButtons.frame.minY), size: self.actionButtons.frame.size), within: containerSize, transition: transition)
|
||||
}
|
||||
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
|
||||
if let tooltipController = self.tooltipController, self.view.window != nil {
|
||||
tooltipController.location = .point(location, .bottom)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat {
|
||||
let previousAdditionalSideInsets = self.validLayout?.4
|
||||
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded)
|
||||
@@ -1229,6 +1390,127 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
self.textInputNode?.isUserInteractionEnabled = !sendingTextDisabled
|
||||
|
||||
var displayBotStartButton = false
|
||||
if case .scheduledMessages = interfaceState.subject {
|
||||
|
||||
} else {
|
||||
if let chatHistoryState = interfaceState.chatHistoryState, case .loaded(true) = chatHistoryState {
|
||||
if let user = interfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
||||
displayBotStartButton = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var inputHasText = false
|
||||
if let textInputNode = self.textInputNode, let attributedText = textInputNode.attributedText, attributedText.length != 0 {
|
||||
inputHasText = true
|
||||
}
|
||||
|
||||
var hasMenuButton = false
|
||||
var menuButtonExpanded = false
|
||||
var isSendAsButton = false
|
||||
|
||||
var shouldDisplayMenuButton = false
|
||||
if interfaceState.hasBotCommands {
|
||||
shouldDisplayMenuButton = true
|
||||
} else if case .webView = interfaceState.botMenuButton {
|
||||
shouldDisplayMenuButton = true
|
||||
}
|
||||
|
||||
let mediaRecordingState = interfaceState.inputTextPanelState.mediaRecordingState
|
||||
if let sendAsPeers = interfaceState.sendAsPeers, !sendAsPeers.isEmpty && interfaceState.editMessageState == nil {
|
||||
hasMenuButton = true
|
||||
menuButtonExpanded = false
|
||||
isSendAsButton = true
|
||||
self.sendAsAvatarNode.isHidden = false
|
||||
|
||||
var currentPeer = sendAsPeers.first(where: { $0.peer.id == interfaceState.currentSendAsPeerId})?.peer
|
||||
if currentPeer == nil {
|
||||
currentPeer = sendAsPeers.first?.peer
|
||||
}
|
||||
if let context = self.context, let peer = currentPeer {
|
||||
self.sendAsAvatarNode.setPeer(context: context, theme: interfaceState.theme, peer: EnginePeer(peer), emptyColor: interfaceState.theme.list.mediaPlaceholderColor)
|
||||
}
|
||||
} else if let peer = interfaceState.renderedPeer?.peer as? TelegramUser, let _ = peer.botInfo, shouldDisplayMenuButton && interfaceState.editMessageState == nil {
|
||||
hasMenuButton = true
|
||||
|
||||
if !inputHasText {
|
||||
switch interfaceState.inputMode {
|
||||
case .none, .inputButtons:
|
||||
menuButtonExpanded = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
self.sendAsAvatarNode.isHidden = true
|
||||
} else {
|
||||
self.sendAsAvatarNode.isHidden = true
|
||||
}
|
||||
if mediaRecordingState != nil {
|
||||
hasMenuButton = false
|
||||
}
|
||||
|
||||
let buttonInset: CGFloat = max(leftInset, 16.0)
|
||||
let maximumButtonWidth: CGFloat = min(430.0, width)
|
||||
let buttonHeight = self.startButton.updateLayout(width: maximumButtonWidth - buttonInset * 2.0, transition: transition)
|
||||
let buttonSize = CGSize(width: maximumButtonWidth - buttonInset * 2.0, height: buttonHeight)
|
||||
self.startButton.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: 6.0), size: buttonSize)
|
||||
|
||||
var hideOffset: CGPoint = .zero
|
||||
if displayBotStartButton {
|
||||
if hasMenuButton {
|
||||
hideOffset = CGPoint(x: width, y: 0.0)
|
||||
} else {
|
||||
hideOffset = CGPoint(x: 0.0, y: 80.0)
|
||||
}
|
||||
if self.startButton.isHidden {
|
||||
self.startButton.isHidden = false
|
||||
if hasMenuButton {
|
||||
self.animateBotButtonInFromMenu(transition: transition)
|
||||
} else {
|
||||
transition.animatePosition(layer: self.startButton.layer, from: CGPoint(x: 0.0, y: 80.0), to: CGPoint(), additive: true)
|
||||
}
|
||||
}
|
||||
|
||||
if let context = self.context {
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
|
||||
if let tooltipController = self.tooltipController {
|
||||
if self.view.window != nil {
|
||||
tooltipController.location = .point(location, .bottom)
|
||||
}
|
||||
} else {
|
||||
let controller = TooltipScreen(account: context.account, text: interfaceState.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
controller.alwaysVisible = true
|
||||
self.tooltipController = controller
|
||||
|
||||
let delay: Double
|
||||
if case .regular = metrics.widthClass {
|
||||
delay = 0.1
|
||||
} else {
|
||||
delay = 0.35
|
||||
}
|
||||
Queue.mainQueue().after(delay, {
|
||||
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
|
||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||
controller.location = .point(location, .bottom)
|
||||
self.interfaceInteraction?.presentControllerInCurrent(controller, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if !self.startButton.isHidden {
|
||||
if hasMenuButton {
|
||||
self.animateBotButtonOutToMenu(transition: transition)
|
||||
} else {
|
||||
transition.animatePosition(node: self.startButton, to: CGPoint(x: 0.0, y: 80.0), additive: true, completion: { _ in
|
||||
self.startButton.isHidden = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var buttonTitleUpdated = false
|
||||
var menuTextSize = self.menuButtonTextNode.frame.size
|
||||
if self.presentationInterfaceState != interfaceState {
|
||||
@@ -1243,6 +1525,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
let themeUpdated = previousState?.theme !== interfaceState.theme
|
||||
if themeUpdated {
|
||||
self.menuButtonIconNode.customColor = interfaceState.theme.chat.inputPanel.actionControlForegroundColor
|
||||
self.startButton.updateTheme(SolidRoundedButtonTheme(theme: interfaceState.theme))
|
||||
}
|
||||
if let sendAsPeers = interfaceState.sendAsPeers, !sendAsPeers.isEmpty {
|
||||
self.menuButtonIconNode.enqueueState(.close, animated: false)
|
||||
@@ -1526,57 +1809,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
}
|
||||
self.accessoryItemButtons = updatedButtons
|
||||
}
|
||||
|
||||
let mediaRecordingState = interfaceState.inputTextPanelState.mediaRecordingState
|
||||
|
||||
var inputHasText = false
|
||||
if let textInputNode = self.textInputNode, let attributedText = textInputNode.attributedText, attributedText.length != 0 {
|
||||
inputHasText = true
|
||||
}
|
||||
|
||||
var hasMenuButton = false
|
||||
var menuButtonExpanded = false
|
||||
var isSendAsButton = false
|
||||
|
||||
var shouldDisplayMenuButton = false
|
||||
if interfaceState.hasBotCommands {
|
||||
shouldDisplayMenuButton = true
|
||||
} else if case .webView = interfaceState.botMenuButton {
|
||||
shouldDisplayMenuButton = true
|
||||
}
|
||||
|
||||
if let sendAsPeers = interfaceState.sendAsPeers, !sendAsPeers.isEmpty && interfaceState.editMessageState == nil {
|
||||
hasMenuButton = true
|
||||
menuButtonExpanded = false
|
||||
isSendAsButton = true
|
||||
self.sendAsAvatarNode.isHidden = false
|
||||
|
||||
var currentPeer = sendAsPeers.first(where: { $0.peer.id == interfaceState.currentSendAsPeerId})?.peer
|
||||
if currentPeer == nil {
|
||||
currentPeer = sendAsPeers.first?.peer
|
||||
}
|
||||
if let context = self.context, let peer = currentPeer {
|
||||
self.sendAsAvatarNode.setPeer(context: context, theme: interfaceState.theme, peer: EnginePeer(peer), emptyColor: interfaceState.theme.list.mediaPlaceholderColor)
|
||||
}
|
||||
} else if let peer = interfaceState.renderedPeer?.peer as? TelegramUser, let _ = peer.botInfo, shouldDisplayMenuButton && interfaceState.editMessageState == nil {
|
||||
hasMenuButton = true
|
||||
|
||||
if !inputHasText {
|
||||
switch interfaceState.inputMode {
|
||||
case .none, .inputButtons:
|
||||
menuButtonExpanded = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
self.sendAsAvatarNode.isHidden = true
|
||||
} else {
|
||||
self.sendAsAvatarNode.isHidden = true
|
||||
}
|
||||
if mediaRecordingState != nil {
|
||||
hasMenuButton = false
|
||||
}
|
||||
|
||||
|
||||
let leftMenuInset: CGFloat
|
||||
let menuButtonHeight: CGFloat = 33.0
|
||||
let menuCollapsedButtonWidth: CGFloat = isSendAsButton ? menuButtonHeight : 38.0
|
||||
@@ -1599,17 +1832,27 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
let baseWidth = width - leftInset - leftMenuInset - rightInset
|
||||
let (accessoryButtonsWidth, textFieldHeight) = self.calculateTextFieldMetrics(width: baseWidth, maxHeight: maxHeight, metrics: metrics)
|
||||
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
|
||||
|
||||
let menuButtonFrame = CGRect(x: leftInset + 10.0, y: panelHeight - minimalHeight + floorToScreenPixels((minimalHeight - menuButtonHeight) / 2.0), width: menuButtonExpanded ? menuButtonWidth : menuCollapsedButtonWidth, height: menuButtonHeight)
|
||||
var panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
|
||||
if displayBotStartButton {
|
||||
panelHeight += 27.0
|
||||
}
|
||||
|
||||
let menuButtonOriginY: CGFloat
|
||||
if displayBotStartButton {
|
||||
menuButtonOriginY = floorToScreenPixels((minimalHeight - menuButtonHeight) / 2.0)
|
||||
} else {
|
||||
menuButtonOriginY = panelHeight - minimalHeight + floorToScreenPixels((minimalHeight - menuButtonHeight) / 2.0)
|
||||
}
|
||||
|
||||
let menuButtonFrame = CGRect(x: leftInset + 10.0, y: menuButtonOriginY, width: menuButtonExpanded ? menuButtonWidth : menuCollapsedButtonWidth, height: menuButtonHeight)
|
||||
transition.updateFrameAsPositionAndBounds(node: self.menuButton, frame: menuButtonFrame)
|
||||
transition.updateFrame(node: self.menuButtonBackgroundNode, frame: CGRect(origin: CGPoint(), size: menuButtonFrame.size))
|
||||
transition.updateFrame(node: self.menuButtonClippingNode, frame: CGRect(origin: CGPoint(x: 19.0, y: 0.0), size: CGSize(width: menuButtonWidth - 19.0, height: menuButtonFrame.height)))
|
||||
var buttonTitlteTransition = transition
|
||||
var menuButtonTitleTransition = transition
|
||||
if buttonTitleUpdated {
|
||||
buttonTitlteTransition = .immediate
|
||||
menuButtonTitleTransition = .immediate
|
||||
}
|
||||
buttonTitlteTransition.updateFrame(node: self.menuButtonTextNode, frame: CGRect(origin: CGPoint(x: 16.0, y: 7.0 - UIScreenPixel), size: menuTextSize))
|
||||
menuButtonTitleTransition.updateFrame(node: self.menuButtonTextNode, frame: CGRect(origin: CGPoint(x: 16.0, y: 7.0 - UIScreenPixel), size: menuTextSize))
|
||||
transition.updateAlpha(node: self.menuButtonTextNode, alpha: menuButtonExpanded ? 1.0 : 0.0)
|
||||
transition.updateFrame(node: self.menuButtonIconNode, frame: CGRect(x: isSendAsButton ? 1.0 + UIScreenPixel : (4.0 + UIScreenPixel), y: 1.0 + UIScreenPixel, width: 30.0, height: 30.0))
|
||||
|
||||
@@ -1917,7 +2160,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
var leftInset = leftInset
|
||||
leftInset += leftMenuInset
|
||||
|
||||
transition.updateFrame(layer: self.attachmentButton.layer, frame: CGRect(origin: CGPoint(x: leftInset + 2.0 - UIScreenPixel, y: panelHeight - minimalHeight), size: CGSize(width: 40.0, height: minimalHeight)))
|
||||
transition.updateFrame(layer: self.attachmentButton.layer, frame: CGRect(origin: CGPoint(x: hideOffset.x + leftInset + 2.0 - UIScreenPixel, y: hideOffset.y + panelHeight - minimalHeight), size: CGSize(width: 40.0, height: minimalHeight)))
|
||||
transition.updateFrame(node: self.attachmentButtonDisabledNode, frame: self.attachmentButton.frame)
|
||||
|
||||
var composeButtonsOffset: CGFloat = 0.0
|
||||
@@ -1929,7 +2172,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
self.updateCounterTextNode(transition: transition)
|
||||
|
||||
let actionButtonsFrame = CGRect(origin: CGPoint(x: width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset, y: panelHeight - minimalHeight), size: CGSize(width: 44.0, height: minimalHeight))
|
||||
let actionButtonsFrame = CGRect(origin: CGPoint(x: hideOffset.x + width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset, y: hideOffset.y + panelHeight - minimalHeight), size: CGSize(width: 44.0, height: minimalHeight))
|
||||
transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame)
|
||||
if let (rect, containerSize) = self.absoluteRect {
|
||||
self.actionButtons.updateAbsoluteRect(CGRect(x: rect.origin.x + actionButtonsFrame.origin.x, y: rect.origin.y + actionButtonsFrame.origin.y, width: actionButtonsFrame.width, height: actionButtonsFrame.height), within: containerSize, transition: transition)
|
||||
@@ -1991,7 +2234,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
textInputViewRealInsets = calculateTextFieldRealInsets(presentationInterfaceState: presentationInterfaceState, accessoryButtonsWidth: accessoryButtonsWidth)
|
||||
}
|
||||
|
||||
let textInputFrame = CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)
|
||||
let textInputFrame = CGRect(x: hideOffset.x + leftInset + textFieldInsets.left, y: hideOffset.y + textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)
|
||||
transition.updateFrame(node: self.textInputContainer, frame: textInputFrame)
|
||||
transition.updateFrame(node: self.textInputContainerBackgroundNode, frame: CGRect(origin: CGPoint(), size: textInputFrame.size))
|
||||
transition.updateAlpha(node: self.textInputContainer, alpha: audioRecordingItemsAlpha)
|
||||
@@ -2025,7 +2268,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
let _ = placeholderApply()
|
||||
|
||||
contextPlaceholderNode.frame = CGRect(origin: CGPoint(x: leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size)
|
||||
transition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: hideOffset.x + leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size))
|
||||
contextPlaceholderNode.alpha = audioRecordingItemsAlpha
|
||||
} else if let contextPlaceholderNode = self.contextPlaceholderNode {
|
||||
self.contextPlaceholderNode = nil
|
||||
@@ -2060,7 +2303,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.slowmodePlaceholderNode?.isHidden = true
|
||||
}
|
||||
|
||||
var nextButtonTopRight = CGPoint(x: width - rightInset - textFieldInsets.right - accessoryButtonInset, y: panelHeight - textFieldInsets.bottom - minimalInputHeight)
|
||||
var nextButtonTopRight = CGPoint(x: hideOffset.x + width - rightInset - textFieldInsets.right - accessoryButtonInset, y: hideOffset.y + panelHeight - textFieldInsets.bottom - minimalInputHeight)
|
||||
for (item, button) in self.accessoryItemButtons.reversed() {
|
||||
let buttonSize = CGSize(width: button.buttonWidth, height: minimalInputHeight)
|
||||
button.updateLayout(item: item, size: buttonSize)
|
||||
@@ -2080,7 +2323,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
nextButtonTopRight.x -= accessoryButtonSpacing
|
||||
}
|
||||
|
||||
let textInputBackgroundFrame = CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)
|
||||
let textInputBackgroundFrame = CGRect(x: hideOffset.x + leftInset + textFieldInsets.left, y: hideOffset.y + textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)
|
||||
transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: textInputBackgroundFrame)
|
||||
transition.updateAlpha(node: self.textInputBackgroundNode, alpha: audioRecordingItemsAlpha)
|
||||
|
||||
@@ -2105,7 +2348,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
textLockIconTransition.updateFrame(node: textLockIconNode, frame: CGRect(origin: CGPoint(x: -image.size.width - 4.0, y: floor((textPlaceholderFrame.height - image.size.height) / 2.0)), size: image.size))
|
||||
}
|
||||
} else {
|
||||
textPlaceholderFrame = CGRect(origin: CGPoint(x: leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: self.textPlaceholderNode.frame.size)
|
||||
textPlaceholderFrame = CGRect(origin: CGPoint(x: hideOffset.x + leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: self.textPlaceholderNode.frame.size)
|
||||
|
||||
if let textLockIconNode = self.textLockIconNode {
|
||||
self.textLockIconNode = nil
|
||||
@@ -2238,7 +2481,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var clippingDelta: CGFloat = 0.0
|
||||
if case let .media(_, _, focused) = interfaceState.inputMode, focused {
|
||||
clippingDelta = -panelHeight
|
||||
|
||||
Reference in New Issue
Block a user