diff --git a/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift b/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift index 09b3dd0b3d..f5488c542f 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputMessageAccessoryPanel/Sources/ChatInputMessageAccessoryPanel.swift @@ -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) diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift index 1884747a7e..26889d8e14 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift @@ -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 diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index d965e9d6af..5ce99b52dc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -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 diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 89a02bb4b3..d44c8df3b2 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -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