diff --git a/submodules/AccountContext/Sources/PeerSelectionController.swift b/submodules/AccountContext/Sources/PeerSelectionController.swift index 90794e83dd..21d396b434 100644 --- a/submodules/AccountContext/Sources/PeerSelectionController.swift +++ b/submodules/AccountContext/Sources/PeerSelectionController.swift @@ -55,9 +55,15 @@ public final class PeerSelectionControllerParams { } } +public enum PeerSelectionControllerSendMode { + case generic + case silent + case schedule +} + public protocol PeerSelectionController: ViewController { var peerSelected: ((Peer) -> Void)? { get set } - var multiplePeersSelected: (([Peer], NSAttributedString) -> Void)? { get set } + var multiplePeersSelected: (([Peer], NSAttributedString, PeerSelectionControllerSendMode) -> Void)? { get set } var inProgress: Bool { get set } var customDismiss: (() -> Void)? { get set } } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 1cef931d41..c7dd83d666 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -901,32 +901,32 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo }).start() let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled], multipleSelection: true)) - peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, messageText in + peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, messageText, mode in guard let strongSelf = self, let strongController = peerSelectionController else { return } strongController.dismiss() - for peer in peers { - var result: [EnqueueMessage] = [] - if messageText.string.count > 0 { - let inputText = convertMarkdownToAttributes(messageText) - for text in breakChatInputText(trimChatInputText(inputText)) { - if text.length != 0 { - var attributes: [MessageAttribute] = [] - let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) - if !entities.isEmpty { - attributes.append(TextEntitiesMessageAttribute(entities: entities)) - } - result.append(.message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) + var result: [EnqueueMessage] = [] + if messageText.string.count > 0 { + let inputText = convertMarkdownToAttributes(messageText) + for text in breakChatInputText(trimChatInputText(inputText)) { + if text.length != 0 { + var attributes: [MessageAttribute] = [] + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) } + result.append(.message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) } } - - result.append(contentsOf: messageIds.map { messageId -> EnqueueMessage in - return .forward(source: messageId, grouping: .auto, attributes: [], correlationId: nil) - }) - + } + + result.append(contentsOf: messageIds.map { messageId -> EnqueueMessage in + return .forward(source: messageId, grouping: .auto, attributes: [], correlationId: nil) + }) + + for peer in peers { let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: result) |> deliverOnMainQueue).start(next: { messageIds in if let strongSelf = self { diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 8ec8e50c43..8f033a294f 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -957,7 +957,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi contentParentNode.willUpdateIsExtractedToContextPreview?(false, .animated(duration: 0.2, curve: .easeInOut)) } else { - if let snapshotView = contentParentNode.contentNode.view.snapshotContentTree() { + if let snapshotView = contentParentNode.contentNode.view.snapshotContentTree(keepTransform: true) { self.contentContainerNode.view.addSubview(snapshotView) } diff --git a/submodules/LegacyComponents/Sources/TGCameraController.m b/submodules/LegacyComponents/Sources/TGCameraController.m index 5ab43a29e8..999bd80845 100644 --- a/submodules/LegacyComponents/Sources/TGCameraController.m +++ b/submodules/LegacyComponents/Sources/TGCameraController.m @@ -2438,27 +2438,21 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus PGCameraMode newMode = PGCameraModeUndefined; if (gestureRecognizer == _photoSwipeGestureRecognizer) { - if (_camera.cameraMode == PGCameraModePhoto && _intent == TGCameraControllerGenericIntent) - newMode = PGCameraModePhotoScan; - else if (_camera.cameraMode != PGCameraModePhotoScan) - newMode = PGCameraModePhoto; + newMode = PGCameraModePhoto; } else if (gestureRecognizer == _videoSwipeGestureRecognizer) { - if (_camera.cameraMode == PGCameraModePhotoScan) { - if (_items.count == 0) - newMode = PGCameraModePhoto; + if (_intent == TGCameraControllerAvatarIntent) { + newMode = PGCameraModeSquareVideo; } else { - if (_intent == TGCameraControllerAvatarIntent) { - newMode = PGCameraModeSquareVideo; - } else { - newMode = PGCameraModeVideo; - } + newMode = PGCameraModeVideo; } } - if (newMode != PGCameraModeUndefined && _camera.cameraMode != newMode) { - [self _updateCameraMode:newMode updateInterface:true]; + if (newMode != PGCameraModeUndefined && _camera.cameraMode != newMode) + { + [_camera setCameraMode:newMode]; + [_interfaceView setCameraMode:newMode]; } } diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m index f5cd71d600..079ea3250d 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m @@ -245,19 +245,6 @@ if (_selectionContext.allowGrouping) { - /*_groupButton = [[TGMediaPickerGroupButton alloc] initWithFrame:CGRectMake(0, 0, 38.0f, 38.0f)]; - [_groupButton setHidden:true animated:false]; - _groupButton.selected = _selectionContext.grouping; - [_groupButton addTarget:self action:@selector(toggleGrouping) forControlEvents:UIControlEventTouchUpInside]; - [_wrapperView addSubview:_groupButton]; - - _groupingChangedDisposable = [[_selectionContext groupingChangedSignal] startWithNext:^(NSNumber *next) - { - __strong TGMediaPickerGalleryInterfaceView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf->_groupButton setSelected:next.boolValue]; - }];*/ - if (_editingContext != nil) { _timersChangedDisposable = [_editingContext.timersUpdatedSignal startWithNext:^(__unused NSNumber *next) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 014127d49a..cfda44c958 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -6603,10 +6603,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let _ = ApplicationSpecificNotice.incrementChatMessageOptionsTip(accountManager: strongSelf.context.sharedContext.accountManager, count: 4).start() - let controller = ChatSendMessageActionSheetController(context: strongSelf.context, controllerInteraction: strongSelf.controllerInteraction, interfaceState: strongSelf.presentationInterfaceState, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, completion: { [weak self] in + let controller = ChatSendMessageActionSheetController(context: strongSelf.context, interfaceState: strongSelf.presentationInterfaceState, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, completion: { [weak self] in if let strongSelf = self { strongSelf.supportedOrientations = previousSupportedOrientations } + }, sendMessage: { [weak self] silently in + if let strongSelf = self { + strongSelf.controllerInteraction?.sendCurrentMessage(silently) + } + }, schedule: { [weak self] in + if let strongSelf = self { + strongSelf.controllerInteraction?.scheduleCurrentMessage() + } }) strongSelf.sendMessageActionsController = controller if layout.isNonExclusive { @@ -10917,80 +10925,97 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } controller.present(textAlertController(context: context, title: nil, text: presentationData.strings.Forward_ErrorDisabledForChat, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } - controller.multiplePeersSelected = { [weak self, weak controller] peers, messageText in + controller.multiplePeersSelected = { [weak self, weak controller] peers, messageText, mode in guard let strongSelf = self, let strongController = controller else { return } strongController.dismiss() - for peer in peers { - var result: [EnqueueMessage] = [] - if messageText.string.count > 0 { - let inputText = convertMarkdownToAttributes(messageText) - for text in breakChatInputText(trimChatInputText(inputText)) { - if text.length != 0 { - var attributes: [MessageAttribute] = [] - let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) - if !entities.isEmpty { - attributes.append(TextEntitiesMessageAttribute(entities: entities)) - } - result.append(.message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) + var result: [EnqueueMessage] = [] + if messageText.string.count > 0 { + let inputText = convertMarkdownToAttributes(messageText) + for text in breakChatInputText(trimChatInputText(inputText)) { + if text.length != 0 { + var attributes: [MessageAttribute] = [] + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) } + result.append(.message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) } } - - result.append(contentsOf: messages.map { message -> EnqueueMessage in - return .forward(source: message.id, grouping: .auto, attributes: [], correlationId: nil) - }) - - let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: result) - |> deliverOnMainQueue).start(next: { messageIds in - if let strongSelf = self { - let signals: [Signal] = messageIds.compactMap({ id -> Signal? in - guard let id = id else { - return nil - } - return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id) - |> mapToSignal { status, _ -> Signal in - if status != nil { - return .never() - } else { - return .single(true) + } + + result.append(contentsOf: messages.map { message -> EnqueueMessage in + return .forward(source: message.id, grouping: .auto, attributes: [], correlationId: nil) + }) + + let commit: ([EnqueueMessage]) -> Void = { result in + for peer in peers { + let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: result) + |> deliverOnMainQueue).start(next: { messageIds in + if let strongSelf = self { + let signals: [Signal] = messageIds.compactMap({ id -> Signal? in + guard let id = id else { + return nil } + return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id) + |> mapToSignal { status, _ -> Signal in + if status != nil { + return .never() + } else { + return .single(true) + } + } + |> take(1) + }) + if strongSelf.shareStatusDisposable == nil { + strongSelf.shareStatusDisposable = MetaDisposable() } - |> take(1) - }) - if strongSelf.shareStatusDisposable == nil { - strongSelf.shareStatusDisposable = MetaDisposable() + strongSelf.shareStatusDisposable?.set((combineLatest(signals) + |> deliverOnMainQueue).start()) } - strongSelf.shareStatusDisposable?.set((combineLatest(signals) - |> deliverOnMainQueue).start()) - } - }) - - let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - let text: String - var savedMessages = false - if peers.count == 1, let peerId = peers.first?.id, peerId == strongSelf.context.account.peerId { - text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many - savedMessages = true - } else { - if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string - } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string - } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string + }) + + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + let text: String + var savedMessages = false + if peers.count == 1, let peerId = peers.first?.id, peerId == strongSelf.context.account.peerId { + text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many + savedMessages = true } else { - text = "" + if peers.count == 1, let peer = peers.first { + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string + } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string + } else if let peer = peers.first { + let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string + } else { + text = "" + } } + + strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) } - - strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) + } + + switch mode { + case .generic: + commit(result) + case .silent: + let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: true) + commit(transformedMessages) + case .schedule: + strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime in + if let strongSelf = self { + let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleTime) + commit(transformedMessages) + } + }) } } controller.peerSelected = { [weak self, weak controller] peer in diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 450b403d01..e28ddf8f18 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -36,6 +36,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD private var appliedHasAvatar = false private var appliedCurrentlyPlaying = false private var appliedAutomaticDownload = false + private var avatarOffset: CGFloat? private var animatingHeight: Bool { return self.apparentHeightTransition != nil @@ -78,7 +79,14 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD super.init(layerBacked: false) self.interactiveVideoNode.shouldOpen = { [weak self] in - return !(self?.animatingHeight ?? false) + if let strongSelf = self { + if let item = strongSelf.item, item.message.id.namespace == Namespaces.Message.Local { + return false + } + return !strongSelf.animatingHeight + } else { + return false + } } self.containerNode.shouldBegin = { [weak self] location in @@ -337,7 +345,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD } var isPlaying = false - var displaySize = layoutConstants.instantVideo.dimensions + let normalDisplaySize = layoutConstants.instantVideo.dimensions + var displaySize = normalDisplaySize let maximumDisplaySize = CGSize(width: min(404, params.width - 20.0), height: min(404, params.width - 20.0)) var effectiveAvatarInset = avatarInset if item.associatedData.currentlyPlayingMessageId == item.message.index { @@ -499,7 +508,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD forwardBackgroundImage = graphics.chatServiceBubbleFillImage } - var maxContentWidth = videoLayout.contentSize.width + var maxContentWidth = normalDisplaySize.width var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animated: Bool) -> ChatMessageActionButtonsNode))? if let replyMarkup = replyMarkup { let (minWidth, buttonsLayout) = actionButtonsLayout(item.context, item.presentationData.theme, item.presentationData.chatBubbleCorners, item.presentationData.strings, replyMarkup, item.message, maxContentWidth) @@ -536,6 +545,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD strongSelf.appliedHasAvatar = hasAvatar strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature) strongSelf.appliedCurrentlyPlaying = isPlaying + strongSelf.appliedAutomaticDownload = automaticDownload strongSelf.updateAccessibilityData(accessibilityData) @@ -552,171 +562,183 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD videoApply(videoLayoutData, transition) } + if currentPlaying != isPlaying { + if isPlaying { + strongSelf.avatarOffset = -100.0 + } else { + strongSelf.avatarOffset = nil + } + strongSelf.updateSelectionState(animated: true) + strongSelf.updateAttachedAvatarNodeOffset(offset: strongSelf.avatarOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + } + strongSelf.interactiveVideoNode.view.disablesInteractiveTransitionGestureRecognizer = isPlaying strongSelf.contextSourceNode.contentRect = videoFrame strongSelf.containerNode.targetNodeForActivationProgressContentRect = strongSelf.contextSourceNode.contentRect - if let updatedShareButtonNode = updatedShareButtonNode { - if updatedShareButtonNode !== strongSelf.shareButtonNode { - if let shareButtonNode = strongSelf.shareButtonNode { - shareButtonNode.removeFromSupernode() - } - strongSelf.shareButtonNode = updatedShareButtonNode - strongSelf.addSubnode(updatedShareButtonNode) - updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside) - } - let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account) - updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: videoFrame.maxX - 7.0, y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize) - } else if let shareButtonNode = strongSelf.shareButtonNode { - shareButtonNode.removeFromSupernode() - strongSelf.shareButtonNode = nil - } - - if let updatedReplyBackgroundNode = updatedReplyBackgroundNode { - if strongSelf.replyBackgroundNode == nil { - strongSelf.replyBackgroundNode = updatedReplyBackgroundNode - strongSelf.addSubnode(updatedReplyBackgroundNode) - updatedReplyBackgroundNode.image = replyBackgroundImage - } else { - strongSelf.replyBackgroundNode?.image = replyBackgroundImage - } - } else if let replyBackgroundNode = strongSelf.replyBackgroundNode { - replyBackgroundNode.removeFromSupernode() - strongSelf.replyBackgroundNode = nil - } - - if let (viaBotLayout, viaBotApply) = viaBotApply { - let viaBotNode = viaBotApply() - if strongSelf.viaBotNode == nil { - strongSelf.viaBotNode = viaBotNode - strongSelf.addSubnode(viaBotNode) - } - let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0), size: viaBotLayout.size) - viaBotNode.frame = viaBotFrame - strongSelf.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0)) - } else if let viaBotNode = strongSelf.viaBotNode { - viaBotNode.removeFromSupernode() - strongSelf.viaBotNode = nil - } - - if let (replyInfoSize, replyInfoApply) = replyInfoApply { - let replyInfoNode = replyInfoApply() - if strongSelf.replyInfoNode == nil { - strongSelf.replyInfoNode = replyInfoNode - strongSelf.addSubnode(replyInfoNode) - } - var viaBotSize = CGSize() - if let viaBotNode = strongSelf.viaBotNode { - viaBotSize = viaBotNode.frame.size - } - let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - max(replyInfoSize.width, viaBotSize.width) - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0 + viaBotSize.height), size: replyInfoSize) - if let viaBotNode = strongSelf.viaBotNode { - if replyInfoFrame.minX < viaBotNode.frame.minX { - viaBotNode.frame = viaBotNode.frame.offsetBy(dx: replyInfoFrame.minX - viaBotNode.frame.minX, dy: 0.0) - } - } - replyInfoNode.frame = replyInfoFrame - strongSelf.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0)) - } else if let replyInfoNode = strongSelf.replyInfoNode { - replyInfoNode.removeFromSupernode() - strongSelf.replyInfoNode = nil - } - - if isFailed { - let deliveryFailedNode: ChatMessageDeliveryFailedNode - var isAppearing = false - if let current = strongSelf.deliveryFailedNode { - deliveryFailedNode = current - } else { - isAppearing = true - deliveryFailedNode = ChatMessageDeliveryFailedNode(tapped: { - if let item = self?.item { - item.controllerInteraction.requestRedeliveryOfFailedMessages(item.content.firstMessage.id) + if !animating { + if let updatedShareButtonNode = updatedShareButtonNode { + if updatedShareButtonNode !== strongSelf.shareButtonNode { + if let shareButtonNode = strongSelf.shareButtonNode { + shareButtonNode.removeFromSupernode() } + strongSelf.shareButtonNode = updatedShareButtonNode + strongSelf.addSubnode(updatedShareButtonNode) + updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside) + } + let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account) + updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: min(params.width - buttonSize.width - 8.0, videoFrame.maxX - 7.0), y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize) + } else if let shareButtonNode = strongSelf.shareButtonNode { + shareButtonNode.removeFromSupernode() + strongSelf.shareButtonNode = nil + } + + if let updatedReplyBackgroundNode = updatedReplyBackgroundNode { + if strongSelf.replyBackgroundNode == nil { + strongSelf.replyBackgroundNode = updatedReplyBackgroundNode + strongSelf.addSubnode(updatedReplyBackgroundNode) + updatedReplyBackgroundNode.image = replyBackgroundImage + } else { + strongSelf.replyBackgroundNode?.image = replyBackgroundImage + } + } else if let replyBackgroundNode = strongSelf.replyBackgroundNode { + replyBackgroundNode.removeFromSupernode() + strongSelf.replyBackgroundNode = nil + } + + if let (viaBotLayout, viaBotApply) = viaBotApply { + let viaBotNode = viaBotApply() + if strongSelf.viaBotNode == nil { + strongSelf.viaBotNode = viaBotNode + strongSelf.addSubnode(viaBotNode) + } + let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - viaBotLayout.size.width - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0), size: viaBotLayout.size) + viaBotNode.frame = viaBotFrame + strongSelf.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: viaBotFrame.minX - 4.0, y: viaBotFrame.minY - 2.0), size: CGSize(width: viaBotFrame.size.width + 8.0, height: viaBotFrame.size.height + 5.0)) + } else if let viaBotNode = strongSelf.viaBotNode { + viaBotNode.removeFromSupernode() + strongSelf.viaBotNode = nil + } + + if let (replyInfoSize, replyInfoApply) = replyInfoApply { + let replyInfoNode = replyInfoApply() + if strongSelf.replyInfoNode == nil { + strongSelf.replyInfoNode = replyInfoNode + strongSelf.addSubnode(replyInfoNode) + } + var viaBotSize = CGSize() + if let viaBotNode = strongSelf.viaBotNode { + viaBotSize = viaBotNode.frame.size + } + let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 10.0) : (params.width - params.rightInset - max(replyInfoSize.width, viaBotSize.width) - layoutConstants.bubble.edgeInset - 10.0)), y: 8.0 + viaBotSize.height), size: replyInfoSize) + if let viaBotNode = strongSelf.viaBotNode { + if replyInfoFrame.minX < viaBotNode.frame.minX { + viaBotNode.frame = viaBotNode.frame.offsetBy(dx: replyInfoFrame.minX - viaBotNode.frame.minX, dy: 0.0) + } + } + replyInfoNode.frame = replyInfoFrame + strongSelf.replyBackgroundNode?.frame = CGRect(origin: CGPoint(x: replyInfoFrame.minX - 4.0, y: replyInfoFrame.minY - viaBotSize.height - 2.0), size: CGSize(width: max(replyInfoFrame.size.width, viaBotSize.width) + 8.0, height: replyInfoFrame.size.height + viaBotSize.height + 5.0)) + } else if let replyInfoNode = strongSelf.replyInfoNode { + replyInfoNode.removeFromSupernode() + strongSelf.replyInfoNode = nil + } + + if isFailed { + let deliveryFailedNode: ChatMessageDeliveryFailedNode + var isAppearing = false + if let current = strongSelf.deliveryFailedNode { + deliveryFailedNode = current + } else { + isAppearing = true + deliveryFailedNode = ChatMessageDeliveryFailedNode(tapped: { + if let item = self?.item { + item.controllerInteraction.requestRedeliveryOfFailedMessages(item.content.firstMessage.id) + } + }) + strongSelf.deliveryFailedNode = deliveryFailedNode + strongSelf.addSubnode(deliveryFailedNode) + } + let deliveryFailedSize = deliveryFailedNode.updateLayout(theme: item.presentationData.theme.theme) + let deliveryFailedFrame = CGRect(origin: CGPoint(x: videoFrame.maxX + deliveryFailedInset - deliveryFailedSize.width, y: videoFrame.maxY - deliveryFailedSize.height), size: deliveryFailedSize) + if isAppearing { + deliveryFailedNode.frame = deliveryFailedFrame + transition.animatePositionAdditive(node: deliveryFailedNode, offset: CGPoint(x: deliveryFailedInset, y: 0.0)) + } else { + transition.updateFrame(node: deliveryFailedNode, frame: deliveryFailedFrame) + } + } else if let deliveryFailedNode = strongSelf.deliveryFailedNode { + strongSelf.deliveryFailedNode = nil + transition.updateAlpha(node: deliveryFailedNode, alpha: 0.0) + transition.updateFrame(node: deliveryFailedNode, frame: deliveryFailedNode.frame.offsetBy(dx: 24.0, dy: 0.0), completion: { [weak deliveryFailedNode] _ in + deliveryFailedNode?.removeFromSupernode() }) - strongSelf.deliveryFailedNode = deliveryFailedNode - strongSelf.addSubnode(deliveryFailedNode) } - let deliveryFailedSize = deliveryFailedNode.updateLayout(theme: item.presentationData.theme.theme) - let deliveryFailedFrame = CGRect(origin: CGPoint(x: videoFrame.maxX + deliveryFailedInset - deliveryFailedSize.width, y: videoFrame.maxY - deliveryFailedSize.height), size: deliveryFailedSize) - if isAppearing { - deliveryFailedNode.frame = deliveryFailedFrame - transition.animatePositionAdditive(node: deliveryFailedNode, offset: CGPoint(x: deliveryFailedInset, y: 0.0)) - } else { - transition.updateFrame(node: deliveryFailedNode, frame: deliveryFailedFrame) - } - } else if let deliveryFailedNode = strongSelf.deliveryFailedNode { - strongSelf.deliveryFailedNode = nil - transition.updateAlpha(node: deliveryFailedNode, alpha: 0.0) - transition.updateFrame(node: deliveryFailedNode, frame: deliveryFailedNode.frame.offsetBy(dx: 24.0, dy: 0.0), completion: { [weak deliveryFailedNode] _ in - deliveryFailedNode?.removeFromSupernode() - }) - } - - if let updatedForwardBackgroundNode = updatedForwardBackgroundNode { - if strongSelf.forwardBackgroundNode == nil { - strongSelf.forwardBackgroundNode = updatedForwardBackgroundNode - strongSelf.addSubnode(updatedForwardBackgroundNode) - updatedForwardBackgroundNode.image = forwardBackgroundImage - } - } else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode { - forwardBackgroundNode.removeFromSupernode() - strongSelf.forwardBackgroundNode = nil - } - - if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply { - let forwardInfoNode = forwardInfoApply(forwardInfoSize.width) - if strongSelf.forwardInfoNode == nil { - strongSelf.forwardInfoNode = forwardInfoNode - strongSelf.addSubnode(forwardInfoNode) - forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in - guard let strongSelf = strongSelf, let item = strongSelf.item else { - return - } - item.controllerInteraction.displayPsa(type, sourceNode) + + if let updatedForwardBackgroundNode = updatedForwardBackgroundNode { + if strongSelf.forwardBackgroundNode == nil { + strongSelf.forwardBackgroundNode = updatedForwardBackgroundNode + strongSelf.addSubnode(updatedForwardBackgroundNode) + updatedForwardBackgroundNode.image = forwardBackgroundImage } + } else if let forwardBackgroundNode = strongSelf.forwardBackgroundNode { + forwardBackgroundNode.removeFromSupernode() + strongSelf.forwardBackgroundNode = nil } - let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize) - forwardInfoNode.frame = forwardInfoFrame - strongSelf.forwardBackgroundNode?.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0)) - } else if let forwardInfoNode = strongSelf.forwardInfoNode { - forwardInfoNode.removeFromSupernode() - strongSelf.forwardInfoNode = nil - } - - if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { - var animated = false - if let _ = strongSelf.actionButtonsNode { - if case .System = animation { - animated = true - } - } - let actionButtonsNode = actionButtonsSizeAndApply.1(animated) - let previousFrame = actionButtonsNode.frame - let actionButtonsFrame = CGRect(origin: CGPoint(x: videoFrame.minX, y: videoFrame.maxY), size: actionButtonsSizeAndApply.0) - actionButtonsNode.frame = actionButtonsFrame - if actionButtonsNode !== strongSelf.actionButtonsNode { - strongSelf.actionButtonsNode = actionButtonsNode - actionButtonsNode.buttonPressed = { button in - if let strongSelf = self { - strongSelf.performMessageButtonAction(button: button) + + if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply { + let forwardInfoNode = forwardInfoApply(forwardInfoSize.width) + if strongSelf.forwardInfoNode == nil { + strongSelf.forwardInfoNode = forwardInfoNode + strongSelf.addSubnode(forwardInfoNode) + forwardInfoNode.openPsa = { [weak strongSelf] type, sourceNode in + guard let strongSelf = strongSelf, let item = strongSelf.item else { + return + } + item.controllerInteraction.displayPsa(type, sourceNode) } } - actionButtonsNode.buttonLongTapped = { button in - if let strongSelf = self { - strongSelf.presentMessageButtonContextMenu(button: button) + let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + 12.0) : (params.width - params.rightInset - forwardInfoSize.width - layoutConstants.bubble.edgeInset - 12.0)), y: 8.0), size: forwardInfoSize) + forwardInfoNode.frame = forwardInfoFrame + strongSelf.forwardBackgroundNode?.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0)) + } else if let forwardInfoNode = strongSelf.forwardInfoNode { + forwardInfoNode.removeFromSupernode() + strongSelf.forwardInfoNode = nil + } + + if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { + var animated = false + if let _ = strongSelf.actionButtonsNode { + if case .System = animation { + animated = true } } - strongSelf.addSubnode(actionButtonsNode) - } else { - if case let .System(duration) = animation { - actionButtonsNode.layer.animateFrame(from: previousFrame, to: actionButtonsFrame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring) + let actionButtonsNode = actionButtonsSizeAndApply.1(animated) + let previousFrame = actionButtonsNode.frame + let actionButtonsFrame = CGRect(origin: CGPoint(x: videoFrame.minX, y: videoFrame.maxY), size: actionButtonsSizeAndApply.0) + actionButtonsNode.frame = actionButtonsFrame + if actionButtonsNode !== strongSelf.actionButtonsNode { + strongSelf.actionButtonsNode = actionButtonsNode + actionButtonsNode.buttonPressed = { button in + if let strongSelf = self { + strongSelf.performMessageButtonAction(button: button) + } + } + actionButtonsNode.buttonLongTapped = { button in + if let strongSelf = self { + strongSelf.presentMessageButtonContextMenu(button: button) + } + } + strongSelf.addSubnode(actionButtonsNode) + } else { + if case let .System(duration) = animation { + actionButtonsNode.layer.animateFrame(from: previousFrame, to: actionButtonsFrame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring) + } } + } else if let actionButtonsNode = strongSelf.actionButtonsNode { + actionButtonsNode.removeFromSupernode() + strongSelf.actionButtonsNode = nil } - } else if let actionButtonsNode = strongSelf.actionButtonsNode { - actionButtonsNode.removeFromSupernode() - strongSelf.actionButtonsNode = nil } } }) @@ -895,7 +917,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD bounds.origin.x = -translation.x self.bounds = bounds - self.updateAttachedAvatarNodeOffset(offset: translation.x, transition: .immediate) + self.updateAttachedAvatarNodeOffset(offset: self.avatarOffset ?? translation.x, transition: .immediate) if let swipeToReplyNode = self.swipeToReplyNode { swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0)) @@ -932,7 +954,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD self.bounds = bounds self.layer.animateBounds(from: previousBounds, to: bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring) - self.updateAttachedAvatarNodeOffset(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring)) + self.updateAttachedAvatarNodeOffset(offset: self.avatarOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .spring)) if let swipeToReplyNode = self.swipeToReplyNode { self.swipeToReplyNode = nil @@ -972,7 +994,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD selected = selectionState.selectedIds.contains(item.message.id) incoming = item.message.effectivelyIncoming(item.context.account.peerId) - let offset: CGFloat = incoming ? 42.0 : 0.0 + let offset: CGFloat = incoming || self.appliedCurrentlyPlaying ? 42.0 : 0.0 if let selectionNode = self.selectionNode { let selectionFrame = CGRect(origin: CGPoint(x: -offset, y: 0.0), size: CGSize(width: self.contentBounds.size.width, height: self.contentBounds.size.height)) @@ -1067,7 +1089,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD override func animateFrameTransition(_ progress: CGFloat, _ currentValue: CGFloat) { super.animateFrameTransition(progress, currentValue) - guard let item = self.appliedItem, let params = self.appliedParams, progress > 0.0, let (initialHeight, targetHeight) = self.apparentHeightTransition else { + guard let item = self.appliedItem, let params = self.appliedParams, progress > 0.0, let (initialHeight, targetHeight) = self.apparentHeightTransition, !targetHeight.isZero && !initialHeight.isZero else { return } @@ -1140,7 +1162,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if let shareButtonNode = self.shareButtonNode { let buttonSize = shareButtonNode.frame.size - shareButtonNode.frame = CGRect(origin: CGPoint(x: videoFrame.maxX - 7.0, y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize) + shareButtonNode.frame = CGRect(origin: CGPoint(x: min(params.width - buttonSize.width - 8.0, videoFrame.maxX - 7.0), y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize) } if let viaBotNode = self.viaBotNode { @@ -1178,5 +1200,11 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD forwardInfoNode.frame = forwardInfoFrame self.forwardBackgroundNode?.frame = CGRect(origin: CGPoint(x: forwardInfoFrame.minX - 6.0, y: forwardInfoFrame.minY - 2.0), size: CGSize(width: forwardInfoFrame.size.width + 10.0, height: forwardInfoFrame.size.height + 4.0)) } + + if let actionButtonsNode = self.actionButtonsNode { + let actionButtonsSize = actionButtonsNode.frame.size + let actionButtonsFrame = CGRect(origin: CGPoint(x: videoFrame.minX, y: videoFrame.maxY), size: actionButtonsSize) + actionButtonsNode.frame = actionButtonsFrame + } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index 3cd41bb1f8..f094ea2fc2 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -707,9 +707,6 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { if let playbackStatusNode = self.playbackStatusNode { self.playbackStatusNode = nil playbackStatusNode.removeFromSupernode() -// playbackStatusNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak playbackStatusNode] _ in -// playbackStatusNode?.removeFromSupernode() -// }) } self.durationNode?.status = .single(nil) diff --git a/submodules/TelegramUI/Sources/ChatSendMessageActionSheetController.swift b/submodules/TelegramUI/Sources/ChatSendMessageActionSheetController.swift index 5e8ae640c2..a90f364189 100644 --- a/submodules/TelegramUI/Sources/ChatSendMessageActionSheetController.swift +++ b/submodules/TelegramUI/Sources/ChatSendMessageActionSheetController.swift @@ -14,12 +14,13 @@ final class ChatSendMessageActionSheetController: ViewController { } private let context: AccountContext - private let controllerInteraction: ChatControllerInteraction? private let interfaceState: ChatPresentationInterfaceState private let gesture: ContextGesture private let sourceSendButton: ASDisplayNode private let textInputNode: EditableTextNode private let completion: () -> Void + private let sendMessage: (Bool) -> Void + private let schedule: () -> Void private var presentationDataDisposable: Disposable? @@ -29,15 +30,16 @@ final class ChatSendMessageActionSheetController: ViewController { private let hapticFeedback = HapticFeedback() - init(context: AccountContext, controllerInteraction: ChatControllerInteraction?, interfaceState: ChatPresentationInterfaceState, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, completion: @escaping () -> Void) { + init(context: AccountContext, interfaceState: ChatPresentationInterfaceState, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, completion: @escaping () -> Void, sendMessage: @escaping (Bool) -> Void, schedule: @escaping () -> Void) { self.context = context - self.controllerInteraction = controllerInteraction self.interfaceState = interfaceState self.gesture = gesture self.sourceSendButton = sourceSendButton self.textInputNode = textInputNode self.completion = completion - + self.sendMessage = sendMessage + self.schedule = schedule + super.init(navigationBarPresentationData: nil) self.blocksBackgroundWhenInOverlay = true @@ -77,13 +79,13 @@ final class ChatSendMessageActionSheetController: ViewController { } self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, forwardedCount: forwardedCount, send: { [weak self] in - self?.controllerInteraction?.sendCurrentMessage(false) + self?.sendMessage(false) self?.dismiss(cancel: false) }, sendSilently: { [weak self] in - self?.controllerInteraction?.sendCurrentMessage(true) + self?.sendMessage(true) self?.dismiss(cancel: false) }, schedule: !canSchedule ? nil : { [weak self] in - self?.controllerInteraction?.scheduleCurrentMessage() + self?.schedule() self?.dismiss(cancel: false) }, cancel: { [weak self] in self?.dismiss(cancel: true) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 07274a49d7..724a704546 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -5649,32 +5649,32 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD func forwardMessages(messageIds: Set?) { if let messageIds = messageIds ?? self.state.selectedMessageIds, !messageIds.isEmpty { let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled], multipleSelection: true)) - peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, messageText in + peerSelectionController.multiplePeersSelected = { [weak self, weak peerSelectionController] peers, messageText, mode in guard let strongSelf = self, let strongController = peerSelectionController else { return } strongController.dismiss() - - for peer in peers { - var result: [EnqueueMessage] = [] - if messageText.string.count > 0 { - let inputText = convertMarkdownToAttributes(messageText) - for text in breakChatInputText(trimChatInputText(inputText)) { - if text.length != 0 { - var attributes: [MessageAttribute] = [] - let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) - if !entities.isEmpty { - attributes.append(TextEntitiesMessageAttribute(entities: entities)) - } - result.append(.message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) + + var result: [EnqueueMessage] = [] + if messageText.string.count > 0 { + let inputText = convertMarkdownToAttributes(messageText) + for text in breakChatInputText(trimChatInputText(inputText)) { + if text.length != 0 { + var attributes: [MessageAttribute] = [] + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) } + result.append(.message(text: text.string, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) } } - - result.append(contentsOf: messageIds.map { messageId -> EnqueueMessage in - return .forward(source: messageId, grouping: .auto, attributes: [], correlationId: nil) - }) - + } + + result.append(contentsOf: messageIds.map { messageId -> EnqueueMessage in + return .forward(source: messageId, grouping: .auto, attributes: [], correlationId: nil) + }) + + for peer in peers { let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: result) |> deliverOnMainQueue).start(next: { messageIds in if let strongSelf = self { diff --git a/submodules/TelegramUI/Sources/PeerSelectionController.swift b/submodules/TelegramUI/Sources/PeerSelectionController.swift index 1a48ee0148..9e8240e79c 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionController.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionController.swift @@ -19,7 +19,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon private var customTitle: String? public var peerSelected: ((Peer) -> Void)? - public var multiplePeersSelected: (([Peer], NSAttributedString) -> Void)? + public var multiplePeersSelected: (([Peer], NSAttributedString, PeerSelectionControllerSendMode) -> Void)? private let filter: ChatListNodePeersFilter private let attemptSelection: ((Peer) -> Void)? @@ -150,14 +150,16 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon override public func loadDisplayNode() { self.displayNode = PeerSelectionControllerNode(context: self.context, filter: self.filter, hasChatListSelector: self.hasChatListSelector, hasContactSelector: self.hasContactSelector, hasGlobalSearch: self.hasGlobalSearch, createNewGroup: self.createNewGroup, present: { [weak self] c, a in self?.present(c, in: .window(.root), with: a) + }, presentInGlobalOverlay: { [weak self] c, a in + self?.presentInGlobalOverlay(c, with: a) }, dismiss: { [weak self] in self?.presentingViewController?.dismiss(animated: false, completion: nil) }) self.peerSelectionNode.navigationBar = self.navigationBar - self.peerSelectionNode.requestSend = { [weak self] peers, text in - self?.multiplePeersSelected?(peers, text) + self.peerSelectionNode.requestSend = { [weak self] peers, text, mode in + self?.multiplePeersSelected?(peers, text, mode) } self.peerSelectionNode.requestDeactivateSearch = { [weak self] in diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index 956727cba5..75dfeaf130 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -16,6 +16,7 @@ import SegmentedControlNode final class PeerSelectionControllerNode: ASDisplayNode { private let context: AccountContext private let present: (ViewController, Any?) -> Void + private let presentInGlobalOverlay: (ViewController, Any?) -> Void private let dismiss: () -> Void private let filter: ChatListNodePeersFilter private let hasGlobalSearch: Bool @@ -55,7 +56,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { var requestOpenDisabledPeer: ((Peer) -> Void)? var requestOpenPeerFromSearch: ((Peer) -> Void)? var requestOpenMessageFromSearch: ((Peer, MessageId) -> Void)? - var requestSend: (([Peer], NSAttributedString) -> Void)? + var requestSend: (([Peer], NSAttributedString, PeerSelectionControllerSendMode) -> Void)? private var presentationData: PresentationData private var presentationDataDisposable: Disposable? @@ -65,9 +66,10 @@ final class PeerSelectionControllerNode: ASDisplayNode { return self.readyValue.get() } - init(context: AccountContext, filter: ChatListNodePeersFilter, hasChatListSelector: Bool, hasContactSelector: Bool, hasGlobalSearch: Bool, createNewGroup: (() -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void) { + init(context: AccountContext, filter: ChatListNodePeersFilter, hasChatListSelector: Bool, hasContactSelector: Bool, hasGlobalSearch: Bool, createNewGroup: (() -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void) { self.context = context self.present = present + self.presentInGlobalOverlay = presentInGlobalOverlay self.dismiss = dismiss self.filter = filter self.hasGlobalSearch = hasGlobalSearch @@ -266,7 +268,32 @@ final class PeerSelectionControllerNode: ASDisplayNode { }, openLinkEditing: { }, reportPeerIrrelevantGeoLocation: { }, displaySlowmodeTooltip: { _, _ in - }, displaySendMessageOptions: { _, _ in + }, displaySendMessageOptions: { [weak self] node, gesture in + guard let strongSelf = self, let textInputPanelNode = strongSelf.textInputPanelNode else { + return + } + textInputPanelNode.loadTextInputNodeIfNeeded() + guard let textInputNode = textInputPanelNode.textInputNode else { + return + } +// let previousSupportedOrientations = strongSelf.supportedOrientations +// if layout.size.width > layout.size.height { +// strongSelf.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .landscape) +// } else { +// strongSelf.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) +// } + + let controller = ChatSendMessageActionSheetController(context: strongSelf.context, interfaceState: strongSelf.presentationInterfaceState, gesture: gesture, sourceSendButton: node, textInputNode: textInputNode, completion: { [weak self] in + if let strongSelf = self { +// strongSelf.supportedOrientations = previousSupportedOrientations + } + }, sendMessage: { [weak textInputPanelNode] silently in + textInputPanelNode?.sendMessage(silently ? .silent : .generic) + }, schedule: { [weak textInputPanelNode] in + textInputPanelNode?.sendMessage(.schedule) + }) +// strongSelf.sendMessageActionsController = controller + strongSelf.presentInGlobalOverlay(controller, nil) }, openScheduledMessages: { }, openPeersNearby: { }, displaySearchResultsTooltip: { _, _ in @@ -311,7 +338,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { } else { let textInputPanelNode = PeerSelectionTextInputPanelNode(presentationInterfaceState: self.presentationInterfaceState, presentController: { [weak self] c in self?.present(c, nil) }) textInputPanelNode.interfaceInteraction = self.interfaceInteraction - textInputPanelNode.sendMessage = { [weak self] in + textInputPanelNode.sendMessage = { [weak self] mode in guard let strongSelf = self else { return } @@ -327,7 +354,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { } } if !selectedPeers.isEmpty { - strongSelf.requestSend?(selectedPeers, effectiveInputText) + strongSelf.requestSend?(selectedPeers, effectiveInputText, mode) } } else { var selectedPeerIds: [PeerId] = [] @@ -345,7 +372,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { selectedPeers.append(peer) } } - strongSelf.requestSend?(selectedPeers, effectiveInputText) + strongSelf.requestSend?(selectedPeers, effectiveInputText, mode) } } } diff --git a/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift b/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift index aaec21232f..85638d8729 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift @@ -109,7 +109,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel private var validLayout: (CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, LayoutMetrics, Bool)? - var sendMessage: () -> Void = { } + var sendMessage: (PeerSelectionControllerSendMode) -> Void = { _ in } var updateHeight: (Bool) -> Void = { _ in } private var updatingInputState = false @@ -896,7 +896,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } } - self.sendMessage() + self.sendMessage(.generic) } @objc func textInputBackgroundViewTap(_ recognizer: UITapGestureRecognizer) {