[WIP] Video message send context menu

This commit is contained in:
Isaac 2024-05-13 23:37:30 +04:00
parent 8736981248
commit 3da1b96775
6 changed files with 224 additions and 49 deletions

View File

@ -32,13 +32,20 @@ func convertFrame(_ frame: CGRect, from fromView: UIView, to toView: UIView) ->
return targetWindowFrame return targetWindowFrame
} }
public enum ChatSendMessageContextScreenMediaPreviewLayoutType {
case message
case videoMessage
}
public protocol ChatSendMessageContextScreenMediaPreview: AnyObject { public protocol ChatSendMessageContextScreenMediaPreview: AnyObject {
var isReady: Signal<Bool, NoError> { get } var isReady: Signal<Bool, NoError> { get }
var view: UIView { get } var view: UIView { get }
var globalClippingRect: CGRect? { get } var globalClippingRect: CGRect? { get }
var layoutType: ChatSendMessageContextScreenMediaPreviewLayoutType { get }
func animateIn(transition: Transition) func animateIn(transition: Transition)
func animateOut(transition: Transition) func animateOut(transition: Transition)
func animateOutOnSend(transition: Transition)
func update(containerSize: CGSize, transition: Transition) -> CGSize func update(containerSize: CGSize, transition: Transition) -> CGSize
} }
@ -482,6 +489,18 @@ final class ChatSendMessageContextScreenComponent: Component {
maxTextHeight -= environment.safeInsets.bottom maxTextHeight -= environment.safeInsets.bottom
} }
let messageItemViewContainerSize: CGSize
if let mediaPreview = component.mediaPreview {
switch mediaPreview.layoutType {
case .message:
messageItemViewContainerSize = CGSize(width: availableSize.width - 16.0 - 40.0, height: availableSize.height)
case .videoMessage:
messageItemViewContainerSize = CGSize(width: availableSize.width, height: availableSize.height)
}
} else {
messageItemViewContainerSize = CGSize(width: availableSize.width - 16.0 - 40.0, height: availableSize.height)
}
let messageItemSize = messageItemView.update( let messageItemSize = messageItemView.update(
context: component.context, context: component.context,
presentationData: presentationData, presentationData: presentationData,
@ -494,7 +513,7 @@ final class ChatSendMessageContextScreenComponent: Component {
explicitBackgroundSize: explicitMessageBackgroundSize, explicitBackgroundSize: explicitMessageBackgroundSize,
maxTextWidth: localSourceTextInputViewFrame.width, maxTextWidth: localSourceTextInputViewFrame.width,
maxTextHeight: maxTextHeight, maxTextHeight: maxTextHeight,
containerSize: CGSize(width: availableSize.width - 16.0 - 40.0, height: availableSize.height), containerSize: messageItemViewContainerSize,
effect: self.presentationAnimationState.key == .animatedIn ? self.selectedMessageEffect : nil, effect: self.presentationAnimationState.key == .animatedIn ? self.selectedMessageEffect : nil,
transition: transition transition: transition
) )
@ -799,6 +818,15 @@ final class ChatSendMessageContextScreenComponent: Component {
let sourceActionsStackFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 1.0 - actionsStackSize.width, y: sourceMessageItemFrame.maxY + messageActionsSpacing), size: actionsStackSize) let sourceActionsStackFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 1.0 - actionsStackSize.width, y: sourceMessageItemFrame.maxY + messageActionsSpacing), size: actionsStackSize)
var readyMessageItemFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 8.0 - messageItemSize.width, y: readySendButtonFrame.maxY - 6.0 - messageItemSize.height), size: messageItemSize) var readyMessageItemFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 8.0 - messageItemSize.width, y: readySendButtonFrame.maxY - 6.0 - messageItemSize.height), size: messageItemSize)
if let mediaPreview = component.mediaPreview {
switch mediaPreview.layoutType {
case .message:
break
case .videoMessage:
readyMessageItemFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - messageItemSize.width) * 0.5), y: readySendButtonFrame.maxY - 6.0 - messageItemSize.height), size: messageItemSize)
}
}
var readyActionsStackFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 1.0 - actionsStackSize.width, y: readyMessageItemFrame.maxY + messageActionsSpacing), size: actionsStackSize) var readyActionsStackFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 1.0 - actionsStackSize.width, y: readyMessageItemFrame.maxY + messageActionsSpacing), size: actionsStackSize)
let bottomOverflow = readyActionsStackFrame.maxY - (availableSize.height - environment.safeInsets.bottom) let bottomOverflow = readyActionsStackFrame.maxY - (availableSize.height - environment.safeInsets.bottom)
@ -874,7 +902,7 @@ final class ChatSendMessageContextScreenComponent: Component {
transition.setAlpha(view: actionsStackNode.view, alpha: 0.0) transition.setAlpha(view: actionsStackNode.view, alpha: 0.0)
transition.setScale(view: actionsStackNode.view, scale: 0.001) transition.setScale(view: actionsStackNode.view, scale: 0.001)
messageItemView.animateOut(transition: transition) messageItemView.animateOut(toEmpty: self.animateOutToEmpty, transition: transition)
} }
} else { } else {
switch self.presentationAnimationState { switch self.presentationAnimationState {

View File

@ -166,6 +166,8 @@ final class MessageItemView: UIView {
super.init(frame: frame) super.init(frame: frame)
self.isUserInteractionEnabled = false
self.addSubview(self.backgroundWallpaperNode.view) self.addSubview(self.backgroundWallpaperNode.view)
self.addSubview(self.backgroundNode.view) self.addSubview(self.backgroundNode.view)
@ -182,9 +184,13 @@ final class MessageItemView: UIView {
} }
} }
func animateOut(transition: Transition) { func animateOut(toEmpty: Bool, transition: Transition) {
if let mediaPreview = self.mediaPreview { if let mediaPreview = self.mediaPreview {
mediaPreview.animateOut(transition: transition) if toEmpty {
mediaPreview.animateOutOnSend(transition: transition)
} else {
mediaPreview.animateOut(transition: transition)
}
} }
} }
@ -274,9 +280,16 @@ final class MessageItemView: UIView {
let mediaPreviewSize = sourceMediaPreview.update(containerSize: containerSize, transition: transition) let mediaPreviewSize = sourceMediaPreview.update(containerSize: containerSize, transition: transition)
let backgroundSize = CGSize(width: mediaPreviewSize.width + 7.0, height: mediaPreviewSize.height) var backgroundSize = CGSize(width: mediaPreviewSize.width, height: mediaPreviewSize.height)
let mediaPreviewFrame: CGRect
switch sourceMediaPreview.layoutType {
case .message:
backgroundSize.width += 7.0
mediaPreviewFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: mediaPreviewSize)
case .videoMessage:
mediaPreviewFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: mediaPreviewSize)
}
let mediaPreviewFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: mediaPreviewSize)
transition.setFrame(view: sourceMediaPreview.view, frame: mediaPreviewFrame) transition.setFrame(view: sourceMediaPreview.view, frame: mediaPreviewFrame)
if let effectIcon = self.effectIcon, let effectIconSize { if let effectIcon = self.effectIcon, let effectIconSize {
@ -295,10 +308,21 @@ final class MessageItemView: UIView {
self.effectIconBackgroundView = effectIconBackgroundView self.effectIconBackgroundView = effectIconBackgroundView
self.insertSubview(effectIconBackgroundView, belowSubview: effectIconView) self.insertSubview(effectIconBackgroundView, belowSubview: effectIconView)
} }
effectIconBackgroundView.backgroundColor = presentationData.theme.chat.message.mediaDateAndStatusFillColor
let effectIconBackgroundSize = CGSize(width: effectIconSize.width + 8.0 * 2.0, height: 18.0) let effectIconBackgroundSize = CGSize(width: effectIconSize.width + 8.0 * 2.0, height: 18.0)
let effectIconBackgroundFrame = CGRect(origin: CGPoint(x: mediaPreviewFrame.maxX - effectIconBackgroundSize.width - 6.0, y: mediaPreviewFrame.maxY - effectIconBackgroundSize.height - 6.0), size: effectIconBackgroundSize)
let effectIconBackgroundFrame: CGRect
switch sourceMediaPreview.layoutType {
case .message:
effectIconBackgroundFrame = CGRect(origin: CGPoint(x: mediaPreviewFrame.maxX - effectIconBackgroundSize.width - 6.0, y: mediaPreviewFrame.maxY - effectIconBackgroundSize.height - 6.0), size: effectIconBackgroundSize)
effectIconBackgroundView.backgroundColor = presentationData.theme.chat.message.mediaDateAndStatusFillColor
case .videoMessage:
effectIconBackgroundFrame = CGRect(origin: CGPoint(x: mediaPreviewFrame.maxX - effectIconBackgroundSize.width - 34.0, y: mediaPreviewFrame.maxY - effectIconBackgroundSize.height - 6.0), size: effectIconBackgroundSize)
let serviceMessageColors = serviceMessageColorComponents(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)
effectIconBackgroundView.backgroundColor = serviceMessageColors.dateFillStatic
}
let effectIconFrame = CGRect(origin: CGPoint(x: effectIconBackgroundFrame.minX + floor((effectIconBackgroundFrame.width - effectIconSize.width) * 0.5), y: effectIconBackgroundFrame.minY + floor((effectIconBackgroundFrame.height - effectIconSize.height) * 0.5)), size: effectIconSize) let effectIconFrame = CGRect(origin: CGPoint(x: effectIconBackgroundFrame.minX + floor((effectIconBackgroundFrame.width - effectIconSize.width) * 0.5), y: effectIconBackgroundFrame.minY + floor((effectIconBackgroundFrame.height - effectIconSize.height) * 0.5)), size: effectIconSize)

View File

@ -511,6 +511,9 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
private let persistentItems: Bool private let persistentItems: Bool
private let isExternalPreview: Bool private let isExternalPreview: Bool
var globalClippingRect: CGRect? var globalClippingRect: CGRect?
var layoutType: ChatSendMessageContextScreenMediaPreviewLayoutType {
return .message
}
fileprivate var wallpaperBackgroundNode: WallpaperBackgroundNode? fileprivate var wallpaperBackgroundNode: WallpaperBackgroundNode?
private let scrollNode: ASScrollNode private let scrollNode: ASScrollNode
@ -656,7 +659,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
} }
func animateOut(transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) { func animateOut(transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) {
if let wallpaperBackgroundNode = self.wallpaperBackgroundNode{ if let wallpaperBackgroundNode = self.wallpaperBackgroundNode {
wallpaperBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak self] _ in wallpaperBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak self] _ in
completion() completion()
@ -714,6 +717,10 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
} }
} }
func animateOutOnSend(transition: Transition) {
transition.setAlpha(view: self.view, alpha: 0.0)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true return true
} }

View File

@ -39,6 +39,7 @@ swift_library(
"//submodules/TelegramUI/Components/MediaEditor", "//submodules/TelegramUI/Components/MediaEditor",
"//submodules/LegacyMediaPickerUI", "//submodules/LegacyMediaPickerUI",
"//submodules/TelegramAudio", "//submodules/TelegramAudio",
"//submodules/ChatSendMessageActionUI",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -27,6 +27,7 @@ import LocalMediaResources
import ImageCompression import ImageCompression
import LegacyMediaPickerUI import LegacyMediaPickerUI
import TelegramAudio import TelegramAudio
import ChatSendMessageActionUI
struct CameraState: Equatable { struct CameraState: Equatable {
enum Recording: Equatable { enum Recording: Equatable {
@ -553,6 +554,7 @@ public class VideoMessageCameraScreen: ViewController {
fileprivate let containerView: UIView fileprivate let containerView: UIView
fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment> fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment>
fileprivate let previewContainerView: UIView fileprivate let previewContainerView: UIView
fileprivate let previewContainerContentView: UIView
private var previewSnapshotView: UIView? private var previewSnapshotView: UIView?
private var previewBlurView: BlurView private var previewBlurView: BlurView
@ -625,7 +627,10 @@ public class VideoMessageCameraScreen: ViewController {
self.componentHost = ComponentView<ViewControllerComponentContainer.Environment>() self.componentHost = ComponentView<ViewControllerComponentContainer.Environment>()
self.previewContainerView = UIView() self.previewContainerView = UIView()
self.previewContainerView.clipsToBounds = true
self.previewContainerContentView = UIView()
self.previewContainerContentView.clipsToBounds = true
self.previewContainerView.addSubview(self.previewContainerContentView)
let isDualCameraEnabled = Camera.isDualCameraSupported(forRoundVideo: true) let isDualCameraEnabled = Camera.isDualCameraSupported(forRoundVideo: true)
let isFrontPosition = "".isEmpty let isFrontPosition = "".isEmpty
@ -666,13 +671,13 @@ public class VideoMessageCameraScreen: ViewController {
self.containerView.addSubview(self.previewContainerView) self.containerView.addSubview(self.previewContainerView)
self.previewContainerView.addSubview(self.mainPreviewView) self.previewContainerContentView.addSubview(self.mainPreviewView)
if isDualCameraEnabled { if isDualCameraEnabled {
self.previewContainerView.addSubview(self.additionalPreviewView) self.previewContainerContentView.addSubview(self.additionalPreviewView)
} }
self.previewContainerView.addSubview(self.progressView) self.previewContainerContentView.addSubview(self.progressView)
self.previewContainerView.addSubview(self.previewBlurView) self.previewContainerContentView.addSubview(self.previewBlurView)
self.previewContainerView.addSubview(self.loadingView) self.previewContainerContentView.addSubview(self.loadingView)
self.completion.connect { [weak self] result in self.completion.connect { [weak self] result in
if let self { if let self {
@ -837,7 +842,7 @@ public class VideoMessageCameraScreen: ViewController {
private func animatePositionChange() { private func animatePositionChange() {
if let snapshotView = self.mainPreviewView.snapshotView(afterScreenUpdates: false) { if let snapshotView = self.mainPreviewView.snapshotView(afterScreenUpdates: false) {
self.previewContainerView.insertSubview(snapshotView, belowSubview: self.progressView) self.previewContainerContentView.insertSubview(snapshotView, belowSubview: self.progressView)
self.previewSnapshotView = snapshotView self.previewSnapshotView = snapshotView
let action = { [weak self] in let action = { [weak self] in
@ -872,7 +877,7 @@ public class VideoMessageCameraScreen: ViewController {
func resumeCameraCapture() { func resumeCameraCapture() {
if !self.mainPreviewView.isEnabled { if !self.mainPreviewView.isEnabled {
if let snapshotView = self.resultPreviewView?.snapshotView(afterScreenUpdates: false) { if let snapshotView = self.resultPreviewView?.snapshotView(afterScreenUpdates: false) {
self.previewContainerView.insertSubview(snapshotView, belowSubview: self.previewBlurView) self.previewContainerContentView.insertSubview(snapshotView, belowSubview: self.previewBlurView)
self.previewSnapshotView = snapshotView self.previewSnapshotView = snapshotView
} }
self.mainPreviewView.isEnabled = true self.mainPreviewView.isEnabled = true
@ -1148,8 +1153,9 @@ public class VideoMessageCameraScreen: ViewController {
} }
if !self.animatingIn { if !self.animatingIn {
transition.setFrame(view: self.previewContainerView, frame: previewFrame) transition.setFrame(view: self.previewContainerView, frame: previewFrame)
transition.setFrame(view: self.previewContainerContentView, frame: CGRect(origin: CGPoint(), size: previewFrame.size))
} }
transition.setCornerRadius(layer: self.previewContainerView.layer, cornerRadius: previewSide / 2.0) transition.setCornerRadius(layer: self.previewContainerContentView.layer, cornerRadius: previewSide / 2.0)
let previewBounds = CGRect(origin: .zero, size: previewFrame.size) let previewBounds = CGRect(origin: .zero, size: previewFrame.size)
@ -1244,7 +1250,7 @@ public class VideoMessageCameraScreen: ViewController {
}, transition: .easeInOut(duration: 0.2)) }, transition: .easeInOut(duration: 0.2))
} }
} }
self.previewContainerView.addSubview(resultPreviewView) self.previewContainerContentView.addSubview(resultPreviewView)
self.resultPreviewView = resultPreviewView self.resultPreviewView = resultPreviewView
resultPreviewView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) resultPreviewView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
@ -1730,6 +1736,10 @@ public class VideoMessageCameraScreen: ViewController {
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, transition: Transition(transition)) (self.displayNode as! Node).containerLayoutUpdated(layout: layout, transition: Transition(transition))
} }
} }
public func makeSendMessageContextPreview() -> ChatSendMessageContextScreenMediaPreview? {
return VideoMessageSendMessageContextPreview(node: self.node)
}
} }
private func composition(with results: [VideoMessageCameraScreen.CaptureResult]) -> AVComposition { private func composition(with results: [VideoMessageCameraScreen.CaptureResult]) -> AVComposition {
@ -1797,3 +1807,84 @@ private class BlurView: UIVisualEffectView {
self.setup() self.setup()
} }
} }
private final class VideoMessageSendMessageContextPreview: UIView, ChatSendMessageContextScreenMediaPreview {
var isReady: Signal<Bool, NoError> {
return .single(true)
}
var view: UIView {
return self
}
var globalClippingRect: CGRect? {
return nil
}
var layoutType: ChatSendMessageContextScreenMediaPreviewLayoutType {
return .videoMessage
}
private weak var previewContainerContentParentView: UIView?
private let previewContainerContentView: UIView
init(node: VideoMessageCameraScreen.Node) {
self.previewContainerContentParentView = node.previewContainerView
self.previewContainerContentView = node.previewContainerContentView
super.init(frame: CGRect())
}
required init(coder: NSCoder) {
preconditionFailure()
}
func animateIn(transition: Transition) {
self.addSubview(self.previewContainerContentView)
guard let previewContainerContentParentView = self.previewContainerContentParentView else {
return
}
let fromFrame = previewContainerContentParentView.convert(CGRect(origin: CGPoint(), size: self.previewContainerContentView.bounds.size), to: self)
let toFrame = self.previewContainerContentView.frame
transition.animatePosition(view: self.previewContainerContentView, from: CGPoint(x: fromFrame.midX - toFrame.midX, y: fromFrame.midY - toFrame.midY), to: CGPoint(), additive: true)
}
func animateOut(transition: Transition) {
guard let previewContainerContentParentView = self.previewContainerContentParentView else {
return
}
let toFrame = previewContainerContentParentView.convert(CGRect(origin: CGPoint(), size: self.previewContainerContentView.bounds.size), to: self)
let previewContainerContentView = self.previewContainerContentView
transition.setPosition(view: self.previewContainerContentView, position: toFrame.center, completion: { [weak previewContainerContentParentView, weak previewContainerContentView] _ in
guard let previewContainerContentParentView, let previewContainerContentView else {
return
}
previewContainerContentView.frame = CGRect(origin: CGPoint(), size: previewContainerContentView.bounds.size)
previewContainerContentParentView.addSubview(previewContainerContentView)
})
}
func animateOutOnSend(transition: Transition) {
guard let previewContainerContentParentView = self.previewContainerContentParentView else {
return
}
if let snapshotView = self.previewContainerContentView.snapshotView(afterScreenUpdates: false) {
self.addSubview(snapshotView)
transition.setAlpha(view: snapshotView, alpha: 0.0)
}
self.previewContainerContentView.frame = CGRect(origin: CGPoint(), size: self.previewContainerContentView.bounds.size)
previewContainerContentParentView.addSubview(self.previewContainerContentView)
}
func update(containerSize: CGSize, transition: Transition) -> CGSize {
return self.previewContainerContentView.bounds.size
}
}

View File

@ -79,37 +79,61 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
let _ = ApplicationSpecificNotice.incrementSendWhenOnlineTip(accountManager: selfController.context.sharedContext.accountManager, count: 4).startStandalone() let _ = ApplicationSpecificNotice.incrementSendWhenOnlineTip(accountManager: selfController.context.sharedContext.accountManager, count: 4).startStandalone()
} }
let controller = makeChatSendMessageActionSheetController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, peerId: selfController.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputView, emojiViewProvider: selfController.chatDisplayNode.textInputPanelNode?.emojiViewProvider, wallpaperBackgroundNode: selfController.chatDisplayNode.backgroundNode, canSendWhenOnline: sendWhenOnlineAvailable, completion: { [weak selfController] in var mediaPreview: ChatSendMessageContextScreenMediaPreview?
guard let selfController else { if let videoRecorderValue = selfController.videoRecorderValue {
return mediaPreview = videoRecorderValue.makeSendMessageContextPreview()
} }
selfController.supportedOrientations = previousSupportedOrientations
}, sendMessage: { [weak selfController] mode, messageEffect in let controller = makeChatSendMessageActionSheetController(
guard let selfController else { context: selfController.context,
return updatedPresentationData: selfController.updatedPresentationData,
} peerId: selfController.presentationInterfaceState.chatLocation.peerId,
switch mode { forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds,
case .generic: hasEntityKeyboard: hasEntityKeyboard,
selfController.controllerInteraction?.sendCurrentMessage(false, messageEffect.flatMap(ChatSendMessageEffect.init)) gesture: gesture,
case .silently: sourceSendButton: node,
selfController.controllerInteraction?.sendCurrentMessage(true, messageEffect.flatMap(ChatSendMessageEffect.init)) textInputView: textInputView,
case .whenOnline: mediaPreview: mediaPreview,
selfController.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleWhenOnlineTimestamp, messageEffect: messageEffect.flatMap(ChatSendMessageEffect.init)) { [weak selfController] in emojiViewProvider: selfController.chatDisplayNode.textInputPanelNode?.emojiViewProvider,
guard let selfController else { wallpaperBackgroundNode: selfController.chatDisplayNode.backgroundNode,
return canSendWhenOnline: sendWhenOnlineAvailable,
} completion: { [weak selfController] in
selfController.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: selfController.presentationInterfaceState.subject != .scheduledMessages, { guard let selfController else {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) } return
})
selfController.openScheduledMessages()
} }
} selfController.supportedOrientations = previousSupportedOrientations
}, schedule: { [weak selfController] messageEffect in },
guard let selfController else { sendMessage: { [weak selfController] mode, messageEffect in
return guard let selfController else {
} return
selfController.controllerInteraction?.scheduleCurrentMessage() }
}, reactionItems: effectItems, availableMessageEffects: availableMessageEffects, isPremium: hasPremium) switch mode {
case .generic:
selfController.controllerInteraction?.sendCurrentMessage(false, messageEffect.flatMap(ChatSendMessageEffect.init))
case .silently:
selfController.controllerInteraction?.sendCurrentMessage(true, messageEffect.flatMap(ChatSendMessageEffect.init))
case .whenOnline:
selfController.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleWhenOnlineTimestamp, messageEffect: messageEffect.flatMap(ChatSendMessageEffect.init)) { [weak selfController] in
guard let selfController else {
return
}
selfController.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: selfController.presentationInterfaceState.subject != .scheduledMessages, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) }
})
selfController.openScheduledMessages()
}
}
},
schedule: { [weak selfController] messageEffect in
guard let selfController else {
return
}
selfController.controllerInteraction?.scheduleCurrentMessage()
},
reactionItems: effectItems,
availableMessageEffects: availableMessageEffects,
isPremium: hasPremium
)
selfController.sendMessageActionsController = controller selfController.sendMessageActionsController = controller
if layout.isNonExclusive { if layout.isNonExclusive {
selfController.present(controller, in: .window(.root)) selfController.present(controller, in: .window(.root))