Send button update

This commit is contained in:
Isaac 2025-10-03 02:22:18 +08:00
parent 70be4f840f
commit c962e6f56a
4 changed files with 198 additions and 234 deletions

View File

@ -385,7 +385,7 @@ public final class ChatInputMessageAccessoryPanel: Component {
let size = CGSize(width: availableSize.width, height: 52.0)
let containerInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 6.0, right: 0.0)
let containerInsets = UIEdgeInsets(top: 8.0, left: 12.0, bottom: 6.0, right: 0.0)
let lineSize = CGSize(width: 2.0, height: size.height - containerInsets.top - containerInsets.bottom)
let lineFrame = CGRect(origin: CGPoint(x: containerInsets.left, y: containerInsets.top), size: lineSize)

View File

@ -133,6 +133,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
private let presentationContext: ChatPresentationContext?
private let strings: PresentationStrings
public let micButtonBackgroundView: GlassBackgroundView
public let micButtonTintMaskView: UIImageView
public let micButton: ChatTextInputMediaRecordingButton
@ -146,6 +147,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
public let textNode: ImmediateAnimatedCountLabelNode
public let expandMediaInputButton: HighlightTrackingButton
private let expandMediaInputButtonBackgroundView: GlassBackgroundView
private let expandMediaInputButtonIcon: GlassBackgroundView.ContentImageView
private var effectBadgeView: EffectBadgeView?
@ -173,13 +175,14 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
let strings = presentationInterfaceState.strings
self.strings = strings
self.micButtonBackgroundView = GlassBackgroundView()
self.maskContentView = UIView()
self.micButtonTintMaskView = UIImageView()
self.micButtonTintMaskView.tintColor = .black
self.micButton = ChatTextInputMediaRecordingButton(context: context, theme: theme, pause: true, strings: strings, presentController: presentController)
self.micButton.animationOutput = self.micButtonTintMaskView
self.maskContentView.addSubview(self.micButtonTintMaskView)
self.micButtonBackgroundView.maskContentView.addSubview(self.micButtonTintMaskView)
self.sendContainerNode = ASDisplayNode()
self.sendContainerNode.layer.allowsGroupOpacity = true
@ -192,12 +195,14 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
self.textNode.isUserInteractionEnabled = false
self.expandMediaInputButton = HighlightTrackingButton()
self.expandMediaInputButtonBackgroundView = GlassBackgroundView()
self.expandMediaInputButtonBackgroundView.isUserInteractionEnabled = false
self.expandMediaInputButton.addSubview(self.expandMediaInputButtonBackgroundView)
self.expandMediaInputButtonIcon = GlassBackgroundView.ContentImageView()
self.maskContentView.addSubview(self.expandMediaInputButtonIcon.tintMask)
self.expandMediaInputButtonBackgroundView.contentView.addSubview(self.expandMediaInputButtonIcon)
self.expandMediaInputButtonIcon.image = PresentationResourcesChat.chatInputPanelExpandButtonImage(presentationInterfaceState.theme)
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor.withAlphaComponent(1.0)
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.panelControlColor.withAlphaComponent(1.0))
self.expandMediaInputButtonIcon.alpha = theme.chat.inputPanel.panelControlColor.alpha
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.panelControlColor
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.panelControlColor)
super.init()
@ -225,6 +230,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
}
self.micButton.layer.allowsGroupOpacity = true
self.view.addSubview(self.micButtonBackgroundView)
self.view.addSubview(self.micButton)
self.addSubnode(self.sendContainerNode)
@ -232,7 +238,6 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
self.sendContainerNode.addSubnode(self.sendButton)
self.sendContainerNode.addSubnode(self.textNode)
self.view.addSubview(self.expandMediaInputButton)
self.expandMediaInputButton.addSubview(self.expandMediaInputButtonIcon)
self.expandMediaInputButton.highligthedChanged = { [weak self] highlighted in
guard let self else {
@ -265,9 +270,8 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
public func updateTheme(theme: PresentationTheme, wallpaper: TelegramWallpaper) {
self.micButton.updateTheme(theme: theme)
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.panelControlColor.withAlphaComponent(1.0)
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.panelControlColor.withAlphaComponent(1.0))
self.expandMediaInputButtonIcon.alpha = theme.chat.inputPanel.panelControlColor.alpha
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.panelControlColor
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.panelControlColor)
}
private var absoluteRect: (CGRect, CGSize)?
@ -286,7 +290,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
self.validLayout = size
var innerSize = size
innerSize.width = 38.0 + 3.0 * 2.0
innerSize.width = 40.0 + 3.0 * 2.0
var starsAmount: Int64?
if let sendPaidMessageStars = interfaceState.sendPaidMessageStars, interfaceState.interfaceState.editMessage == nil {
@ -336,19 +340,26 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
self.sendButton.imageNode.alpha = 1.0
self.textNode.isHidden = true
}
transition.updateFrame(view: self.micButtonBackgroundView, frame: CGRect(origin: CGPoint(), size: size))
self.micButtonBackgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition))
transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(x: 7.0, y: 0.0), size: CGSize(width: size.width - 7.0, height: size.height)))
transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(), size: size))
self.micButton.layoutItems()
transition.updateFrame(view: self.sendButtonBackgroundView, frame: CGRect(origin: CGPoint(), size: innerSize).insetBy(dx: 3.0, dy: 3.0))
self.sendButtonBackgroundView.tintColor = interfaceState.theme.chat.inputPanel.panelControlAccentColor
transition.updateFrame(layer: self.sendButton.layer, frame: CGRect(origin: CGPoint(), size: innerSize))
transition.updateFrame(node: self.sendContainerNode, frame: CGRect(origin: CGPoint(), size: innerSize))
let sendContainerFrame = CGRect(origin: CGPoint(), size: innerSize)
transition.updatePosition(node: self.sendContainerNode, position: sendContainerFrame.center)
transition.updateBounds(node: self.sendContainerNode, bounds: CGRect(origin: CGPoint(), size: sendContainerFrame.size))
let backgroundSize = CGSize(width: innerSize.width, height: 40.0)
let backgroundFrame = CGRect(origin: CGPoint(x: showTitle ? 5.0 + UIScreenPixel : floorToScreenPixels((size.width - backgroundSize.width) / 2.0), y: floorToScreenPixels((size.height - backgroundSize.height) / 2.0)), size: backgroundSize)
transition.updateFrame(view: self.expandMediaInputButton, frame: CGRect(origin: CGPoint(), size: size))
transition.updateFrame(view: self.expandMediaInputButtonBackgroundView, frame: CGRect(origin: CGPoint(), size: size))
self.expandMediaInputButtonBackgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition))
if let image = self.expandMediaInputButtonIcon.image {
let expandIconFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) * 0.5), y: floor((size.height - image.size.height) * 0.5)), size: image.size)
self.expandMediaInputButtonIcon.center = expandIconFrame.center

View File

@ -234,7 +234,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
public let textInputBackgroundNode: ASImageNode
public var textInputBackgroundTapRecognizer: TouchDownGestureRecognizer?
public let actionButtons: ChatTextInputActionButtonsNode
public let mediaActionButtons: ChatTextInputActionButtonsNode
public let sendActionButtons: ChatTextInputActionButtonsNode
private let slowModeButton: BoostSlowModeButton
public var mediaRecordingAccessibilityArea: AccessibilityAreaNode?
private let counterTextNode: ImmediateTextNode
@ -345,12 +346,13 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
override public var context: AccountContext? {
didSet {
self.actionButtons.micButton.statusBarHost = self.context?.sharedContext.mainWindow?.statusBarHost
self.sendActionButtons.micButton.statusBarHost = self.context?.sharedContext.mainWindow?.statusBarHost
self.mediaActionButtons.micButton.statusBarHost = self.context?.sharedContext.mainWindow?.statusBarHost
}
}
public var micButton: ChatTextInputMediaRecordingButton? {
return self.actionButtons.micButton
return self.mediaActionButtons.micButton
}
private let statusDisposable = MetaDisposable()
@ -474,7 +476,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
private let textInputViewInternalInsets: UIEdgeInsets
private let accessoryButtonSpacing: CGFloat = 0.0
private let accessoryButtonInset: CGFloat = 6.0
private let accessoryButtonInset: CGFloat = 4.0
private var spoilersRevealed = false
@ -492,7 +494,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.presentationInterfaceState = presentationInterfaceState
self.presentationContext = presentationContext
self.textInputViewInternalInsets = UIEdgeInsets(top: 5.0, left: 16.0, bottom: 4.0, right: 15.0)
self.textInputViewInternalInsets = UIEdgeInsets(top: 5.0, left: 12.0, bottom: 4.0, right: 11.0)
var hasSpoilers = true
var hasQuotes = true
@ -576,7 +578,15 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.searchLayoutClearButton = HighlightTrackingButton()
self.searchLayoutClearButtonIcon = GlassBackgroundView.ContentImageView()
self.actionButtons = ChatTextInputActionButtonsNode(context: context, presentationInterfaceState: presentationInterfaceState, presentationContext: presentationContext, presentController: presentController)
self.sendActionButtons = ChatTextInputActionButtonsNode(context: context, presentationInterfaceState: presentationInterfaceState, presentationContext: presentationContext, presentController: presentController)
self.sendActionButtons.micButtonBackgroundView.alpha = 0.0
self.sendActionButtons.micButton.alpha = 0.0
self.sendActionButtons.micButtonTintMaskView.alpha = 0.0
self.sendActionButtons.expandMediaInputButton.alpha = 0.0
self.mediaActionButtons = ChatTextInputActionButtonsNode(context: context, presentationInterfaceState: presentationInterfaceState, presentationContext: presentationContext, presentController: presentController)
self.mediaActionButtons.sendContainerNode.alpha = 0.0
self.counterTextNode = ImmediateTextNode()
self.counterTextNode.textAlignment = .center
@ -685,11 +695,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
self.attachmentButtonDisabledNode.addTarget(self, action: #selector(self.attachmentButtonPressed), forControlEvents: .touchUpInside)
self.actionButtons.sendButtonLongPressed = { [weak self] node, gesture in
self.sendActionButtons.sendButtonLongPressed = { [weak self] node, gesture in
self?.interfaceInteraction?.displaySendMessageOptions(node, gesture)
}
self.actionButtons.micButton.recordingDisabled = { [weak self] in
self.mediaActionButtons.micButton.recordingDisabled = { [weak self] in
if let strongSelf = self {
if strongSelf.presentationInterfaceState?.voiceMessagesAvailable == false {
self?.interfaceInteraction?.displayRestrictedInfo(.premiumVoiceMessages, .tooltip)
@ -699,7 +709,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
self.actionButtons.micButton.beginRecording = { [weak self] in
self.mediaActionButtons.micButton.beginRecording = { [weak self] in
if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState, let interfaceInteraction = strongSelf.interfaceInteraction {
let isVideo: Bool
switch presentationInterfaceState.interfaceState.mediaRecordingMode {
@ -711,7 +721,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
interfaceInteraction.beginMediaRecording(isVideo)
}
}
self.actionButtons.micButton.endRecording = { [weak self] sendMedia in
self.mediaActionButtons.micButton.endRecording = { [weak self] sendMedia in
if let strongSelf = self, let interfaceState = strongSelf.presentationInterfaceState, let interfaceInteraction = strongSelf.interfaceInteraction {
if let _ = interfaceState.inputTextPanelState.mediaRecordingState {
if sendMedia {
@ -726,44 +736,45 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
strongSelf.tooltipController?.dismiss()
}
}
self.actionButtons.micButton.offsetRecordingControls = { [weak self] in
self.mediaActionButtons.micButton.offsetRecordingControls = { [weak self] in
if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState {
if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = strongSelf.validLayout {
let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded)
}
}
}
self.actionButtons.micButton.updateCancelTranslation = { [weak self] in
self.mediaActionButtons.micButton.updateCancelTranslation = { [weak self] in
if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState {
if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) = strongSelf.validLayout {
let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, maxOverlayHeight: maxOverlayHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded)
}
}
}
self.actionButtons.micButton.stopRecording = { [weak self] in
self.mediaActionButtons.micButton.stopRecording = { [weak self] in
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
interfaceInteraction.stopMediaRecording()
strongSelf.tooltipController?.dismiss()
}
}
self.actionButtons.micButton.updateLocked = { [weak self] _ in
self.mediaActionButtons.micButton.updateLocked = { [weak self] _ in
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
interfaceInteraction.lockMediaRecording()
}
}
self.actionButtons.micButton.switchMode = { [weak self] in
self.mediaActionButtons.micButton.switchMode = { [weak self] in
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
interfaceInteraction.switchMediaRecordingMode()
}
}
self.actionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), forControlEvents: .touchUpInside)
self.actionButtons.sendContainerNode.alpha = 0.0
self.actionButtons.updateAccessibility()
self.sendActionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), forControlEvents: .touchUpInside)
self.sendActionButtons.sendContainerNode.alpha = 0.0
self.sendActionButtons.updateAccessibility()
self.mediaActionButtons.updateAccessibility()
self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), for: .touchUpInside)
self.actionButtons.expandMediaInputButton.alpha = 0.0
self.mediaActionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), for: .touchUpInside)
self.mediaActionButtons.expandMediaInputButton.alpha = 0.0
self.searchLayoutClearButton.highligthedChanged = { [weak self] highlighted in
guard let self else {
@ -802,7 +813,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.clippingNode.addSubnode(self.startButton)
self.clippingNode.addSubnode(self.actionButtons)
self.clippingNode.addSubnode(self.sendActionButtons)
self.clippingNode.addSubnode(self.mediaActionButtons)
self.clippingNode.addSubnode(self.counterTextNode)
self.clippingNode.addSubnode(self.slowModeButton)
@ -942,7 +954,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
if let presentationInterfaceState = self.presentationInterfaceState {
refreshChatTextInputTypingAttributes(textInputNode.textView, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
textInputNode.textContainerInset = calculateTextFieldRealInsets(presentationInterfaceState: presentationInterfaceState, accessoryButtonsWidth: accessoryButtonsWidth, actionControlsWidth: self.actionButtons.frame.width)
textInputNode.textContainerInset = calculateTextFieldRealInsets(presentationInterfaceState: presentationInterfaceState, accessoryButtonsWidth: accessoryButtonsWidth, actionControlsWidth: self.sendActionButtons.frame.width)
}
if let textInputNodeLayout = self.textInputNodeLayout {
@ -1040,7 +1052,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
return max(33.0, maxHeight - (textFieldInsets.top + textFieldInsets.bottom + self.textInputViewInternalInsets.top + self.textInputViewInternalInsets.bottom))
}
private func calculateTextFieldMetrics(width: CGFloat, actionControlsWidth: CGFloat, maxHeight: CGFloat, metrics: LayoutMetrics) -> (accessoryButtonsWidth: CGFloat, textFieldHeight: CGFloat, isOverflow: Bool) {
private func calculateTextFieldMetrics(width: CGFloat, sendActionControlsWidth: CGFloat, maxHeight: CGFloat, metrics: LayoutMetrics) -> (accessoryButtonsWidth: CGFloat, textFieldHeight: CGFloat, isOverflow: Bool) {
let maxHeight = max(maxHeight, 40.0)
let textFieldInsets = self.textFieldInsets(metrics: metrics)
@ -1072,7 +1084,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
if let presentationInterfaceState = self.presentationInterfaceState {
textInputViewRealInsets = calculateTextFieldRealInsets(presentationInterfaceState: presentationInterfaceState, accessoryButtonsWidth: accessoryButtonsWidth, actionControlsWidth: actionControlsWidth)
textInputViewRealInsets = calculateTextFieldRealInsets(presentationInterfaceState: presentationInterfaceState, accessoryButtonsWidth: accessoryButtonsWidth, actionControlsWidth: sendActionControlsWidth)
}
var textFieldHeight: CGFloat
@ -1221,8 +1233,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) {
self.absoluteRect = (rect, containerSize)
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)
if !self.sendActionButtons.frame.width.isZero {
self.sendActionButtons.updateAbsoluteRect(CGRect(origin: rect.origin.offsetBy(dx: self.sendActionButtons.frame.minX, dy: self.sendActionButtons.frame.minY), size: self.sendActionButtons.frame.size), within: containerSize, transition: transition)
}
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil)
@ -1624,7 +1636,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.attachmentButtonIcon.tintColor = interfaceState.theme.chat.inputPanel.panelControlColor
}
self.actionButtons.updateTheme(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper)
self.sendActionButtons.updateTheme(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper)
self.mediaActionButtons.updateTheme(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper)
self.searchLayoutClearButtonIcon.image = PresentationResourcesChat.chatInputTextFieldClearImage(interfaceState.theme)
self.searchLayoutClearButtonIcon.tintColor = interfaceState.theme.chat.inputPanel.inputControlColor
@ -1742,7 +1755,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
updatedPlaceholder = placeholder
self.actionButtons.sendButtonLongPressEnabled = !isScheduledMessages
self.sendActionButtons.sendButtonLongPressEnabled = !isScheduledMessages
}
var sendButtonHasApplyIcon = interfaceState.interfaceState.editMessage != nil
@ -1760,12 +1773,12 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
if updateSendButtonIcon {
if !self.actionButtons.animatingSendButton {
let imageNode = self.actionButtons.sendButton.imageNode
if !self.sendActionButtons.animatingSendButton {
let imageNode = self.sendActionButtons.sendButton.imageNode
if transition.isAnimated && !self.actionButtons.sendContainerNode.alpha.isZero && self.actionButtons.sendButton.layer.animation(forKey: "opacity") == nil, let previousImage = imageNode.image {
if transition.isAnimated && !self.sendActionButtons.sendContainerNode.alpha.isZero && self.sendActionButtons.sendButton.layer.animation(forKey: "opacity") == nil, let previousImage = imageNode.image {
let tempView = UIImageView(image: previousImage)
self.actionButtons.sendButton.view.addSubview(tempView)
self.sendActionButtons.sendButton.view.addSubview(tempView)
tempView.frame = imageNode.frame
tempView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak tempView] _ in
tempView?.removeFromSuperview()
@ -1775,14 +1788,14 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
imageNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2)
}
self.actionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon
if self.actionButtons.sendButtonHasApplyIcon {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyIconImage(interfaceState.theme), for: [])
self.sendActionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon
if self.sendActionButtons.sendButtonHasApplyIcon {
self.sendActionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyIconImage(interfaceState.theme), for: [])
} else {
if isScheduledMessages {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: [])
self.sendActionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: [])
} else {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendIconImage(interfaceState.theme), for: [])
self.sendActionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendIconImage(interfaceState.theme), for: [])
}
}
}
@ -1882,34 +1895,15 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
attachmentButtonX = -48.0
}
self.actionButtons.micButton.updateMode(mode: interfaceState.interfaceState.mediaRecordingMode, animated: transition.isAnimated)
self.mediaActionButtons.micButton.updateMode(mode: interfaceState.interfaceState.mediaRecordingMode, animated: transition.isAnimated)
var hideMicButton = false
if inputHasText || self.extendedSearchLayout {
hideMicButton = true
}
if let mediaRecordingState {
switch mediaRecordingState {
case .audio:
break
case let .video(status, _):
switch status {
case .recording:
break
case .editing:
hideMicButton = true
}
case .waitingForPreview:
break
}
}
self.updateActionButtons(hasText: inputHasText, hideMicButton: hideMicButton, animated: transition.isAnimated)
self.updateActionButtons(hasText: inputHasText, transition: transition)
var actionButtonsSize = CGSize(width: 40.0, height: 40.0)
var sendActionButtonsSize = CGSize(width: 40.0, height: 40.0)
if let presentationInterfaceState = self.presentationInterfaceState {
var showTitle = false
if !self.actionButtons.sendContainerNode.alpha.isZero {
if !self.sendActionButtons.sendContainerNode.alpha.isZero {
if let _ = presentationInterfaceState.sendPaidMessageStars {
showTitle = true
} else if case let .customChatContents(customChatContents) = interfaceState.subject {
@ -1919,11 +1913,12 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
}
actionButtonsSize = self.actionButtons.updateLayout(size: CGSize(width: 40.0, height: minimalHeight), isMediaInputExpanded: isMediaInputExpanded, showTitle: showTitle, currentMessageEffectId: presentationInterfaceState.interfaceState.sendMessageEffect, transition: transition, interfaceState: presentationInterfaceState)
sendActionButtonsSize = self.sendActionButtons.updateLayout(size: CGSize(width: 40.0, height: minimalHeight), isMediaInputExpanded: isMediaInputExpanded, showTitle: showTitle, currentMessageEffectId: presentationInterfaceState.interfaceState.sendMessageEffect, transition: transition, interfaceState: presentationInterfaceState)
actionButtonsSize = self.mediaActionButtons.updateLayout(size: CGSize(width: 40.0, height: minimalHeight), isMediaInputExpanded: isMediaInputExpanded, showTitle: false, currentMessageEffectId: presentationInterfaceState.interfaceState.sendMessageEffect, transition: transition, interfaceState: presentationInterfaceState)
}
let baseWidth = width - leftInset - leftMenuInset - rightInset - rightSlowModeInset
let (accessoryButtonsWidth, textFieldHeight, isTextFieldOverflow) = self.calculateTextFieldMetrics(width: baseWidth, actionControlsWidth: actionButtonsSize.width, maxHeight: maxHeight, metrics: metrics)
let (accessoryButtonsWidth, textFieldHeight, isTextFieldOverflow) = self.calculateTextFieldMetrics(width: baseWidth, sendActionControlsWidth: sendActionButtonsSize.width, maxHeight: maxHeight, metrics: metrics)
var panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
if displayBotStartButton {
panelHeight += 27.0
@ -1986,6 +1981,10 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
if additionalSideInsets.right > 0.0 {
textFieldInsets.right += additionalSideInsets.right / 3.0
}
if inputHasText || self.extendedSearchLayout || hasMediaDraft {
} else {
textFieldInsets.right = 54.0
}
if mediaRecordingState != nil {
textFieldInsets.left = 8.0
}
@ -2042,29 +2041,29 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
switch mediaRecordingState {
case let .audio(recorder, isLocked):
let hadAudioRecorder = self.actionButtons.micButton.audioRecorder != nil
let hadAudioRecorder = self.mediaActionButtons.micButton.audioRecorder != nil
if !hadAudioRecorder, isLocked {
self.actionButtons.micButton.lock()
self.mediaActionButtons.micButton.lock()
}
self.actionButtons.micButton.audioRecorder = recorder
self.mediaActionButtons.micButton.audioRecorder = recorder
audioRecordingTimeNode.audioRecorder = recorder
case let .video(status, _):
let hadVideoRecorder = self.actionButtons.micButton.videoRecordingStatus != nil
let hadVideoRecorder = self.mediaActionButtons.micButton.videoRecordingStatus != nil
if !hadVideoRecorder, isLocked {
self.actionButtons.micButton.lock()
self.mediaActionButtons.micButton.lock()
}
switch status {
case let .recording(recordingStatus):
audioRecordingTimeNode.videoRecordingStatus = recordingStatus
self.actionButtons.micButton.videoRecordingStatus = recordingStatus
self.mediaActionButtons.micButton.videoRecordingStatus = recordingStatus
case .editing:
audioRecordingTimeNode.videoRecordingStatus = nil
self.actionButtons.micButton.videoRecordingStatus = nil
self.mediaActionButtons.micButton.videoRecordingStatus = nil
hideInfo = true
}
case .waitingForPreview:
Queue.mainQueue().after(0.5, {
self.actionButtons.micButton.audioRecorder = nil
self.mediaActionButtons.micButton.audioRecorder = nil
})
}
@ -2075,7 +2074,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
let cancelTransformThreshold: CGFloat = 8.0
let indicatorTranslation = max(0.0, self.actionButtons.micButton.cancelTranslation - cancelTransformThreshold)
let indicatorTranslation = max(0.0, self.mediaActionButtons.micButton.cancelTranslation - cancelTransformThreshold)
let audioRecordingCancelIndicatorFrame = CGRect(
origin: CGPoint(
@ -2083,7 +2082,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
y: (accessoryPanel != nil ? 52.0 : 0.0) + panelHeight - minimalHeight + floor((minimalHeight - audioRecordingCancelIndicator.bounds.size.height) / 2.0)),
size: audioRecordingCancelIndicator.bounds.size)
audioRecordingCancelIndicator.frame = audioRecordingCancelIndicatorFrame
if self.actionButtons.micButton.cancelTranslation > cancelTransformThreshold {
if self.mediaActionButtons.micButton.cancelTranslation > cancelTransformThreshold {
let progress: CGFloat = max(0.0, min(1.0, (audioRecordingCancelIndicatorFrame.minX - 100.0) / 10.0))
audioRecordingCancelIndicator.alpha = progress
} else {
@ -2097,7 +2096,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
audioRecordingCancelIndicator.updateIsDisplayingCancel(isLocked, animated: !animateCancelSlideIn)
if isLocked || self.actionButtons.micButton.cancelTranslation > cancelTransformThreshold {
if isLocked || self.mediaActionButtons.micButton.cancelTranslation > cancelTransformThreshold {
var deltaOffset: CGFloat = 0.0
if audioRecordingCancelIndicator.layer.animation(forKey: "slide_juggle") != nil, let presentationLayer = audioRecordingCancelIndicator.layer.presentation() {
let translation = CGPoint(x: presentationLayer.transform.m41, y: presentationLayer.transform.m42)
@ -2187,8 +2186,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
audioRecordingCancelIndicator.layer.animateAlpha(from: CGFloat(audioRecordingCancelIndicator.layer.presentation()?.opacity ?? 1), to: 0, duration: 0.15, delay: 0, removeOnCompletion: false)
}
} else if self.audioRecordingInfoContainerNode != nil {
self.actionButtons.micButton.audioRecorder = nil
self.actionButtons.micButton.videoRecordingStatus = nil
self.mediaActionButtons.micButton.audioRecorder = nil
self.mediaActionButtons.micButton.videoRecordingStatus = nil
transition.updateAlpha(layer: self.textInputBackgroundNode.layer, alpha: 1.0)
if let audioRecordingInfoContainerNode = self.audioRecordingInfoContainerNode {
@ -2487,9 +2486,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.slowmodePlaceholderNode?.isHidden = true
}
var nextButtonTopRight = CGPoint(x: textInputContainerBackgroundFrame.width - accessoryButtonInset - rightSlowModeInset - actionButtonsSize.width + (inputHasText ? 4.0 : (8.0 + 1.0)), y: textInputContainerBackgroundFrame.height - minimalInputHeight)
var nextButtonTopRight = CGPoint(x: textInputContainerBackgroundFrame.width - accessoryButtonInset, y: textInputContainerBackgroundFrame.height - minimalInputHeight)
if self.extendedSearchLayout {
nextButtonTopRight.x += 8.0 + 1.0
nextButtonTopRight.x -= 46.0
} else if inputHasText || hasMediaDraft {
nextButtonTopRight.x -= sendActionButtonsSize.width
}
for (item, button) in self.accessoryItemButtons.reversed() {
let buttonSize = CGSize(width: button.buttonWidth, height: minimalInputHeight)
@ -2604,10 +2605,26 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
let actionButtonsFrame = CGRect(origin: CGPoint(x: hideOffset.x + width - rightInset - 8.0 - actionButtonsSize.width + composeButtonsOffset, y: textInputContainerBackgroundFrame.maxY - actionButtonsSize.height), size: actionButtonsSize)
transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame)
var actionButtonsFrame = CGRect(origin: CGPoint(x: textInputContainerBackgroundFrame.maxX + 6.0, y: textInputContainerBackgroundFrame.maxY - actionButtonsSize.height), size: actionButtonsSize)
if inputHasText || self.extendedSearchLayout {
actionButtonsFrame.origin.x = width + 8.0
}
transition.updateFrame(node: self.mediaActionButtons, 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)
self.mediaActionButtons.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)
}
var sendActionButtonsFrame = CGRect(origin: CGPoint(x: textInputContainerBackgroundFrame.maxX - sendActionButtonsSize.width, y: textInputContainerBackgroundFrame.maxY - sendActionButtonsSize.height), size: sendActionButtonsSize)
if inputHasText || hasMediaDraft {
transition.updateTransformScale(node: self.sendActionButtons, scale: CGPoint(x: 1.0, y: 1.0))
} else {
sendActionButtonsFrame.origin.x += (sendActionButtonsSize.width - 3.0 * 2.0) * 0.5 - 3.0
transition.updateTransformScale(node: self.sendActionButtons, scale: CGPoint(x: 0.001, y: 0.001))
}
transition.updatePosition(node: self.sendActionButtons, position: sendActionButtonsFrame.center)
transition.updateBounds(node: self.sendActionButtons, bounds: CGRect(origin: CGPoint(), size: sendActionButtonsFrame.size))
if let (rect, containerSize) = self.absoluteRect {
self.sendActionButtons.updateAbsoluteRect(CGRect(x: rect.origin.x + sendActionButtonsFrame.origin.x, y: rect.origin.y + sendActionButtonsFrame.origin.y, width: sendActionButtonsFrame.width, height: sendActionButtonsFrame.height), within: containerSize, transition: transition)
}
let slowModeButtonFrame = CGRect(origin: CGPoint(x: hideOffset.x + width - rightInset - 5.0 - slowModeButtonSize.width + composeButtonsOffset, y: hideOffset.y + panelHeight - minimalHeight + 6.0), size: slowModeButtonSize)
@ -2631,9 +2648,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
return true
}
self.clippingNode.insertSubnode(mediaRecordingAccessibilityArea, aboveSubnode: self.actionButtons)
self.clippingNode.insertSubnode(mediaRecordingAccessibilityArea, aboveSubnode: self.mediaActionButtons)
}
self.actionButtons.isAccessibilityElement = false
self.mediaActionButtons.isAccessibilityElement = false
let size: CGFloat = 120.0
mediaRecordingAccessibilityArea.frame = CGRect(origin: CGPoint(x: actionButtonsFrame.midX - size / 2.0, y: actionButtonsFrame.midY - size / 2.0), size: CGSize(width: size, height: size))
if added {
@ -2643,17 +2660,18 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
})
}
} else {
self.actionButtons.isAccessibilityElement = true
self.mediaActionButtons.isAccessibilityElement = true
if let mediaRecordingAccessibilityArea = self.mediaRecordingAccessibilityArea {
self.mediaRecordingAccessibilityArea = nil
mediaRecordingAccessibilityArea.removeFromSupernode()
}
}
let searchLayoutClearButtonSize = CGSize(width: 40.0, height: 40.0)
self.actionButtons.micButton.isHidden = additionalSideInsets.right > 0.0
let searchLayoutClearButtonSize = CGSize(width: 46.0, height: 40.0)
self.mediaActionButtons.micButton.isHidden = additionalSideInsets.right > 0.0
self.mediaActionButtons.micButtonTintMaskView.isHidden = self.mediaActionButtons.micButton.isHidden
let clearButtonFrame = CGRect(origin: CGPoint(x: textInputContainerBackgroundFrame.width - searchLayoutClearButtonSize.width, y: floor((textInputContainerBackgroundFrame.height - searchLayoutClearButtonSize.height) * 0.5)), size: searchLayoutClearButtonSize)
let clearButtonFrame = CGRect(origin: CGPoint(x: textInputContainerBackgroundFrame.width - searchLayoutClearButtonSize.width, y: textInputFrame.maxY - 40.0 + floor((40.0 - searchLayoutClearButtonSize.height) * 0.5)), size: searchLayoutClearButtonSize)
transition.updateFrame(layer: self.searchLayoutClearButton.layer, frame: clearButtonFrame)
if let image = self.searchLayoutClearButtonIcon.image {
let clearIconFrame = CGRect(origin: CGPoint(x: floor((searchLayoutClearButtonSize.width - image.size.width) / 2.0), y: floor((searchLayoutClearButtonSize.height - image.size.height) / 2.0)), size: image.size)
@ -2740,7 +2758,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
mediaInputDisabled = false
}
self.actionButtons.micButton.fadeDisabled = mediaInputDisabled
self.mediaActionButtons.micButton.fadeDisabled = mediaInputDisabled
var viewOnceIsVisible = false
var recordMoreIsVisible = false
@ -3372,7 +3390,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
composeButtonsOffset = 40.0
}
let (_, textFieldHeight, _) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - self.leftMenuInset - self.rightSlowModeInset + self.currentTextInputBackgroundWidthOffset, actionControlsWidth: self.actionButtons.bounds.width, maxHeight: maxHeight, metrics: metrics)
let (_, textFieldHeight, _) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - self.leftMenuInset - self.rightSlowModeInset + self.currentTextInputBackgroundWidthOffset, sendActionControlsWidth: self.sendActionButtons.bounds.width, maxHeight: maxHeight, metrics: metrics)
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
var textFieldMinHeight: CGFloat = 33.0
if let presentationInterfaceState = self.presentationInterfaceState {
@ -3643,10 +3661,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
private func updateTextNodeText(animated: Bool) {
var inputHasText = false
var hideMicButton = false
if let textInputNode = self.textInputNode, let attributedText = textInputNode.attributedText, attributedText.length != 0 {
inputHasText = true
hideMicButton = true
}
var isScheduledMessages = false
@ -3664,21 +3680,17 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
let _ = hideMicButton
self.updateTextHeight(animated: animated)
}
private func updateActionButtons(hasText: Bool, hideMicButton: Bool, animated: Bool) {
var hideMicButton = hideMicButton
private func updateActionButtons(hasText: Bool, transition: ContainedViewLayoutTransition) {
let alphaTransition: ContainedViewLayoutTransition = transition.isAnimated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
var hideMicButton = false
var mediaInputIsActive = false
var keepSendButtonEnabled = self.keepSendButtonEnabled
if let presentationInterfaceState = self.presentationInterfaceState {
if let mediaRecordingState = presentationInterfaceState.inputTextPanelState.mediaRecordingState {
if case .video(.editing, false) = mediaRecordingState {
hideMicButton = true
}
}
if case .media = presentationInterfaceState.inputMode {
mediaInputIsActive = true
}
@ -3699,114 +3711,71 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
var animateWithBounce = false
if self.extendedSearchLayout {
hideMicButton = true
if !self.actionButtons.sendContainerNode.alpha.isZero {
self.actionButtons.sendContainerNode.alpha = 0.0
self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0
self.actionButtons.updateAccessibility()
if animated {
self.actionButtons.animatingSendButton = true
self.actionButtons.sendContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.actionButtons.animatingSendButton = false
strongSelf.applyUpdateSendButtonIcon()
}
})
self.actionButtons.sendContainerNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2)
if !self.sendActionButtons.sendContainerNode.alpha.isZero {
self.sendActionButtons.updateAccessibility()
self.sendActionButtons.animatingSendButton = true
alphaTransition.updateAlpha(node: self.sendActionButtons.sendContainerNode, alpha: 0.0, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.sendActionButtons.animatingSendButton = false
strongSelf.applyUpdateSendButtonIcon()
}
})
if let sendButtonRadialStatusNode = self.sendActionButtons.sendButtonRadialStatusNode {
alphaTransition.updateAlpha(node: sendButtonRadialStatusNode, alpha: 0.0)
}
}
if self.searchLayoutClearButton.alpha.isZero {
self.searchLayoutClearButton.alpha = 1.0
self.searchLayoutClearButtonIcon.alpha = 1.0
if animated {
self.searchLayoutClearButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.searchLayoutClearButton.layer.animateScale(from: 0.8, to: 1.0, duration: 0.2)
self.searchLayoutClearButtonIcon.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.searchLayoutClearButtonIcon.layer.animateScale(from: 0.8, to: 1.0, duration: 0.2)
}
alphaTransition.updateAlpha(layer: self.searchLayoutClearButton.layer, alpha: 1.0)
alphaTransition.updateAlpha(layer: self.searchLayoutClearButtonIcon.layer, alpha: 1.0)
}
} else {
animateWithBounce = true
if !self.searchLayoutClearButton.alpha.isZero {
animateWithBounce = false
self.searchLayoutClearButton.alpha = 0.0
self.searchLayoutClearButtonIcon.alpha = 0.0
if animated {
self.searchLayoutClearButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.searchLayoutClearButton.layer.animateScale(from: 1.0, to: 0.8, duration: 0.2)
self.searchLayoutClearButtonIcon.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.searchLayoutClearButtonIcon.layer.animateScale(from: 1.0, to: 0.8, duration: 0.2)
}
alphaTransition.updateAlpha(layer: self.searchLayoutClearButton.layer, alpha: 0.0)
alphaTransition.updateAlpha(layer: self.searchLayoutClearButtonIcon.layer, alpha: 0.0)
}
let hasSlowModeButton = self.rightSlowModeInset > 0.0
if hasSlowModeButton {
hideMicButton = true
if self.slowModeButton.alpha.isZero {
self.slowModeButton.alpha = 1.0
if animated {
self.slowModeButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
if animateWithBounce {
self.slowModeButton.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
} else {
self.slowModeButton.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
}
}
alphaTransition.updateAlpha(node: self.slowModeButton, alpha: 1.0)
}
} else {
if !self.slowModeButton.alpha.isZero {
self.slowModeButton.alpha = 0.0
if animated {
self.slowModeButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
alphaTransition.updateAlpha(node: self.slowModeButton, alpha: 0.0)
}
}
if (hasText || keepSendButtonEnabled && !mediaInputIsActive && !hasSlowModeButton) {
hideMicButton = true
if self.actionButtons.sendContainerNode.alpha.isZero && self.rightSlowModeInset.isZero {
self.actionButtons.sendContainerNode.alpha = 1.0
self.actionButtons.sendButtonRadialStatusNode?.alpha = 1.0
self.actionButtons.updateAccessibility()
if animated {
self.actionButtons.sendContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
if animateWithBounce {
self.actionButtons.sendContainerNode.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
} else {
self.actionButtons.sendContainerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
}
if self.sendActionButtons.sendContainerNode.alpha.isZero && self.rightSlowModeInset.isZero {
alphaTransition.updateAlpha(node: self.sendActionButtons.sendContainerNode, alpha: 1.0)
if let sendButtonRadialStatusNode = self.sendActionButtons.sendButtonRadialStatusNode {
alphaTransition.updateAlpha(node: sendButtonRadialStatusNode, alpha: 1.0)
}
}
} else {
if !self.actionButtons.sendContainerNode.alpha.isZero {
self.actionButtons.sendContainerNode.alpha = 0.0
self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0
self.actionButtons.updateAccessibility()
if animated {
self.actionButtons.animatingSendButton = true
self.actionButtons.sendContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.actionButtons.animatingSendButton = false
strongSelf.applyUpdateSendButtonIcon()
}
})
self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
if !self.sendActionButtons.sendContainerNode.alpha.isZero {
self.sendActionButtons.animatingSendButton = true
alphaTransition.updateAlpha(node: self.sendActionButtons.sendContainerNode, alpha: 0.0, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.sendActionButtons.animatingSendButton = false
strongSelf.applyUpdateSendButtonIcon()
}
})
if let sendButtonRadialStatusNode = self.sendActionButtons.sendButtonRadialStatusNode {
alphaTransition.updateAlpha(node: sendButtonRadialStatusNode, alpha: 0.0)
}
self.sendActionButtons.updateAccessibility()
}
}
}
let hideExpandMediaInput = hideMicButton
let hideExpandMediaInput = false
if mediaInputIsActive {
hideMicButton = true
@ -3825,54 +3794,38 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
if hideMicButton {
if !self.actionButtons.micButton.alpha.isZero {
alphaTransition.updateAlpha(layer: self.actionButtons.micButton.layer, alpha: 0.0)
if hideMicButton || (mediaInputIsActive && !hideExpandMediaInput) {
if !self.mediaActionButtons.micButton.alpha.isZero {
alphaTransition.updateAlpha(layer: self.mediaActionButtons.micButton.layer, alpha: 0.0)
alphaTransition.updateAlpha(layer: self.mediaActionButtons.micButtonBackgroundView.layer, alpha: 0.0)
alphaTransition.updateAlpha(layer: self.mediaActionButtons.micButtonTintMaskView.layer, alpha: 0.0)
}
} else {
let micAlpha: CGFloat = self.actionButtons.micButton.fadeDisabled ? 0.5 : 1.0
if !self.actionButtons.micButton.alpha.isEqual(to: micAlpha) {
self.actionButtons.micButton.alpha = micAlpha
if animated {
self.actionButtons.micButton.layer.animateAlpha(from: 0.0, to: micAlpha, duration: 0.1)
if animateWithBounce {
self.actionButtons.micButton.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
} else {
self.actionButtons.micButton.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
}
}
let micAlpha: CGFloat = self.mediaActionButtons.micButton.fadeDisabled ? 0.5 : 1.0
if !self.mediaActionButtons.micButton.alpha.isEqual(to: micAlpha) {
alphaTransition.updateAlpha(layer: self.mediaActionButtons.micButton.layer, alpha: micAlpha)
alphaTransition.updateAlpha(layer: self.mediaActionButtons.micButtonBackgroundView.layer, alpha: micAlpha)
alphaTransition.updateAlpha(layer: self.mediaActionButtons.micButtonTintMaskView.layer, alpha: micAlpha)
}
}
if mediaInputIsActive && !hideExpandMediaInput {
if self.actionButtons.expandMediaInputButton.alpha.isZero {
self.actionButtons.expandMediaInputButton.alpha = 1.0
if animated {
self.actionButtons.expandMediaInputButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
if animateWithBounce {
self.actionButtons.expandMediaInputButton.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
} else {
self.actionButtons.expandMediaInputButton.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
}
}
if self.mediaActionButtons.expandMediaInputButton.alpha.isZero {
alphaTransition.updateAlpha(layer: self.mediaActionButtons.expandMediaInputButton.layer, alpha: 1.0)
}
} else {
if !self.actionButtons.expandMediaInputButton.alpha.isZero {
self.actionButtons.expandMediaInputButton.alpha = 0.0
if animated {
self.actionButtons.expandMediaInputButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
if !self.mediaActionButtons.expandMediaInputButton.alpha.isZero {
alphaTransition.updateAlpha(layer: self.mediaActionButtons.expandMediaInputButton.layer, alpha: 0.0)
}
}
self.actionButtons.updateAccessibility()
self.sendActionButtons.updateAccessibility()
self.mediaActionButtons.updateAccessibility()
}
private func updateTextHeight(animated: Bool) {
if let (width, leftInset, rightInset, _, additionalSideInsets, maxHeight, _, metrics, _, _) = self.validLayout {
let (_, textFieldHeight, _) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - additionalSideInsets.right - self.leftMenuInset - self.rightSlowModeInset + self.currentTextInputBackgroundWidthOffset, actionControlsWidth: self.actionButtons.bounds.width, maxHeight: maxHeight, metrics: metrics)
let (_, textFieldHeight, _) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - additionalSideInsets.right - self.leftMenuInset - self.rightSlowModeInset + self.currentTextInputBackgroundWidthOffset, sendActionControlsWidth: self.sendActionButtons.bounds.width, maxHeight: maxHeight, metrics: metrics)
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
if !self.bounds.size.height.isEqual(to: panelHeight) {
self.updateHeight(animated)
@ -3904,7 +3857,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
public func chatInputTextNodeShouldReturn() -> Bool {
if self.actionButtons.sendButton.supernode != nil && !self.actionButtons.sendButton.isHidden && !self.actionButtons.sendContainerNode.alpha.isZero {
if self.sendActionButtons.sendButton.supernode != nil && !self.sendActionButtons.sendButton.isHidden && !self.sendActionButtons.sendContainerNode.alpha.isZero {
self.sendButtonPressed()
}
return false
@ -3928,15 +3881,15 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
if sendButtonHasApplyIcon != self.actionButtons.sendButtonHasApplyIcon {
self.actionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon
if self.actionButtons.sendButtonHasApplyIcon {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyIconImage(interfaceState.theme), for: [])
if sendButtonHasApplyIcon != self.sendActionButtons.sendButtonHasApplyIcon {
self.sendActionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon
if self.sendActionButtons.sendButtonHasApplyIcon {
self.sendActionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyIconImage(interfaceState.theme), for: [])
} else {
if case .scheduledMessages = interfaceState.subject {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleIconImage(interfaceState.theme), for: [])
self.sendActionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleIconImage(interfaceState.theme), for: [])
} else {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendIconImage(interfaceState.theme), for: [])
self.sendActionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendIconImage(interfaceState.theme), for: [])
}
}
}
@ -4732,11 +4685,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
public func frameForInputActionButton() -> CGRect? {
if !self.actionButtons.alpha.isZero {
if self.actionButtons.micButton.alpha.isZero {
return self.actionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0)
if !self.mediaActionButtons.alpha.isZero {
if self.mediaActionButtons.micButton.alpha.isZero {
return self.mediaActionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: -3.0, dy: 0.0)
} else {
return self.actionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0)
return self.mediaActionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: -3.0, dy: 0.0)
}
}
return nil

View File

@ -3876,7 +3876,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
}
func sendButtonFrame() -> CGRect? {
if let frame = self.textInputPanelNode?.actionButtons.frame {
if let frame = self.textInputPanelNode?.sendActionButtons.frame {
return self.textInputPanelNode?.convert(frame, to: self)
} else {
return nil