diff --git a/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift b/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift index 8e3ab429af..c41ba0f8d1 100644 --- a/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift +++ b/submodules/ChatInterfaceState/Sources/ChatInterfaceState.swift @@ -47,12 +47,14 @@ public struct ChatEditMessageState: Codable, Equatable { public var inputState: ChatTextInputState public var disableUrlPreviews: [String] public var inputTextMaxLength: Int32? + public var mediaCaptionIsAbove: Bool? - public init(messageId: EngineMessage.Id, inputState: ChatTextInputState, disableUrlPreviews: [String], inputTextMaxLength: Int32?) { + public init(messageId: EngineMessage.Id, inputState: ChatTextInputState, disableUrlPreviews: [String], inputTextMaxLength: Int32?, mediaCaptionIsAbove: Bool?) { self.messageId = messageId self.inputState = inputState self.disableUrlPreviews = disableUrlPreviews self.inputTextMaxLength = inputTextMaxLength + self.mediaCaptionIsAbove = mediaCaptionIsAbove } public init(from decoder: Decoder) throws { @@ -80,6 +82,8 @@ public struct ChatEditMessageState: Codable, Equatable { } } self.inputTextMaxLength = try? container.decodeIfPresent(Int32.self, forKey: "tl") + + self.mediaCaptionIsAbove = try? container.decodeIfPresent(Bool.self, forKey: "mediaCaptionIsAbove") } @@ -94,18 +98,20 @@ public struct ChatEditMessageState: Codable, Equatable { try container.encode(self.disableUrlPreviews, forKey: "dupl") try container.encodeIfPresent(self.inputTextMaxLength, forKey: "tl") + + try container.encodeIfPresent(self.mediaCaptionIsAbove, forKey: "mediaCaptionIsAbove") } public static func ==(lhs: ChatEditMessageState, rhs: ChatEditMessageState) -> Bool { - return lhs.messageId == rhs.messageId && lhs.inputState == rhs.inputState && lhs.disableUrlPreviews == rhs.disableUrlPreviews && lhs.inputTextMaxLength == rhs.inputTextMaxLength + return lhs.messageId == rhs.messageId && lhs.inputState == rhs.inputState && lhs.disableUrlPreviews == rhs.disableUrlPreviews && lhs.inputTextMaxLength == rhs.inputTextMaxLength && lhs.mediaCaptionIsAbove == rhs.mediaCaptionIsAbove } public func withUpdatedInputState(_ inputState: ChatTextInputState) -> ChatEditMessageState { - return ChatEditMessageState(messageId: self.messageId, inputState: inputState, disableUrlPreviews: self.disableUrlPreviews, inputTextMaxLength: self.inputTextMaxLength) + return ChatEditMessageState(messageId: self.messageId, inputState: inputState, disableUrlPreviews: self.disableUrlPreviews, inputTextMaxLength: self.inputTextMaxLength, mediaCaptionIsAbove: self.mediaCaptionIsAbove) } public func withUpdatedDisableUrlPreviews(_ disableUrlPreviews: [String]) -> ChatEditMessageState { - return ChatEditMessageState(messageId: self.messageId, inputState: self.inputState, disableUrlPreviews: disableUrlPreviews, inputTextMaxLength: self.inputTextMaxLength) + return ChatEditMessageState(messageId: self.messageId, inputState: self.inputState, disableUrlPreviews: disableUrlPreviews, inputTextMaxLength: self.inputTextMaxLength, mediaCaptionIsAbove: self.mediaCaptionIsAbove) } } diff --git a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift index 68a87ead3b..45aeeef4e6 100644 --- a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift +++ b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetController.swift @@ -40,10 +40,12 @@ public enum SendMessageActionSheetControllerParams { public final class EditMessage { public let messages: [EngineMessage] public let mediaPreview: ChatSendMessageContextScreenMediaPreview? + public let mediaCaptionIsAbove: (Bool, (Bool) -> Void)? - public init(messages: [EngineMessage], mediaPreview: ChatSendMessageContextScreenMediaPreview?) { + public init(messages: [EngineMessage], mediaPreview: ChatSendMessageContextScreenMediaPreview?, mediaCaptionIsAbove: (Bool, (Bool) -> Void)?) { self.messages = messages self.mediaPreview = mediaPreview + self.mediaCaptionIsAbove = mediaCaptionIsAbove } } diff --git a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift index d2502c5ab8..31abcd2afe 100644 --- a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift +++ b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift @@ -320,9 +320,7 @@ final class ChatSendMessageContextScreenComponent: Component { case let .sendMessage(sendMessage): self.mediaCaptionIsAbove = sendMessage.mediaCaptionIsAbove?.0 ?? false case let .editMessage(editMessage): - self.mediaCaptionIsAbove = editMessage.messages.contains(where: { - return $0.attributes.contains(where: { $0 is InvertMediaMessageAttribute }) - }) + self.mediaCaptionIsAbove = editMessage.mediaCaptionIsAbove?.0 ?? false } component.gesture.externalUpdated = { [weak self] view, location in @@ -483,8 +481,8 @@ final class ChatSendMessageContextScreenComponent: Component { switch component.params { case let .sendMessage(sendMessage): sendMessage.mediaCaptionIsAbove?.1(self.mediaCaptionIsAbove) - case .editMessage: - break + case let .editMessage(editMessage): + editMessage.mediaCaptionIsAbove?.1(self.mediaCaptionIsAbove) } if !self.isUpdating { self.state?.updated(transition: .spring(duration: 0.35)) @@ -704,6 +702,11 @@ final class ChatSendMessageContextScreenComponent: Component { messageItemViewContainerSize = CGSize(width: availableSize.width - 16.0 - 40.0, height: availableSize.height) } + var isEditMessage = false + if case .editMessage = component.params { + isEditMessage = true + } + let messageItemSize = messageItemView.update( context: component.context, presentationData: presentationData, @@ -719,6 +722,7 @@ final class ChatSendMessageContextScreenComponent: Component { maxTextHeight: 20000.0, containerSize: messageItemViewContainerSize, effect: self.presentationAnimationState.key == .animatedIn ? self.selectedMessageEffect : nil, + isEditMessage: isEditMessage, transition: transition ) let sourceMessageItemFrame = CGRect(origin: CGPoint(x: localSourceTextInputViewFrame.minX - sourceMessageTextInsets.left, y: localSourceTextInputViewFrame.minY - 2.0), size: messageItemSize) @@ -1141,6 +1145,7 @@ final class ChatSendMessageContextScreenComponent: Component { messageItemView.animateIn( sourceTextInputView: component.textInputView as? ChatInputTextView, + isEditMessage: isEditMessage, transition: transition ) case .animatedOut: @@ -1150,6 +1155,7 @@ final class ChatSendMessageContextScreenComponent: Component { messageItemView.animateOut( sourceTextInputView: component.textInputView as? ChatInputTextView, toEmpty: self.animateOutToEmpty, + isEditMessage: isEditMessage, transition: transition ) } diff --git a/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift b/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift index 60b5fcade2..cf48ea62ba 100644 --- a/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift +++ b/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift @@ -245,23 +245,35 @@ final class MessageItemView: UIView { func animateIn( sourceTextInputView: ChatInputTextView?, + isEditMessage: Bool, transition: Transition ) { - if let mediaPreview = self.mediaPreview { - mediaPreview.animateIn(transition: transition) + if isEditMessage { + transition.animateScale(view: self, from: 0.001, to: 1.0) + transition.animateAlpha(view: self, from: 0.0, to: 1.0) + } else { + if let mediaPreview = self.mediaPreview { + mediaPreview.animateIn(transition: transition) + } } } func animateOut( sourceTextInputView: ChatInputTextView?, toEmpty: Bool, + isEditMessage: Bool, transition: Transition ) { - if let mediaPreview = self.mediaPreview { - if toEmpty { - mediaPreview.animateOutOnSend(transition: transition) - } else { - mediaPreview.animateOut(transition: transition) + if isEditMessage { + transition.setScale(view: self, scale: 0.001) + transition.setAlpha(view: self, alpha: 0.0) + } else { + if let mediaPreview = self.mediaPreview { + if toEmpty { + mediaPreview.animateOutOnSend(transition: transition) + } else { + mediaPreview.animateOut(transition: transition) + } } } } @@ -281,6 +293,7 @@ final class MessageItemView: UIView { maxTextHeight: CGFloat, containerSize: CGSize, effect: AvailableMessageEffects.MessageEffect?, + isEditMessage: Bool, transition: Transition ) -> CGSize { self.emojiViewProvider = emojiViewProvider @@ -387,6 +400,8 @@ final class MessageItemView: UIView { backgroundAlpha = 0.0 } + let backgroundScale: CGFloat = 1.0 + var backgroundFrame = mediaPreviewFrame.insetBy(dx: -2.0, dy: -2.0) backgroundFrame.size.width += 6.0 @@ -502,10 +517,14 @@ final class MessageItemView: UIView { transition.setFrame(view: sourceMediaPreview.view, frame: mediaPreviewFrame) - transition.setFrame(view: self.backgroundWallpaperNode.view, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size)) + transition.setPosition(view: self.backgroundWallpaperNode.view, position: CGRect(origin: CGPoint(), size: backgroundFrame.size).center) + transition.setBounds(view: self.backgroundWallpaperNode.view, bounds: CGRect(origin: CGPoint(), size: backgroundFrame.size)) alphaTransition.setAlpha(view: self.backgroundWallpaperNode.view, alpha: backgroundAlpha) + transition.setScale(view: self.backgroundWallpaperNode.view, scale: backgroundScale) self.backgroundWallpaperNode.updateFrame(backgroundFrame, transition: transition.containedViewLayoutTransition) - transition.setFrame(view: self.backgroundNode.view, frame: backgroundFrame) + transition.setPosition(view: self.backgroundNode.view, position: backgroundFrame.center) + transition.setBounds(view: self.backgroundNode.view, bounds: CGRect(origin: CGPoint(), size: backgroundFrame.size)) + transition.setScale(view: self.backgroundNode.view, scale: backgroundScale) alphaTransition.setAlpha(view: self.backgroundNode.view, alpha: backgroundAlpha) self.backgroundNode.updateLayout(size: backgroundFrame.size, transition: transition.containedViewLayoutTransition) diff --git a/submodules/TelegramCore/Sources/PendingMessages/ChatUpdatingMessageMedia.swift b/submodules/TelegramCore/Sources/PendingMessages/ChatUpdatingMessageMedia.swift index 55ead0e540..8c0399f82b 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/ChatUpdatingMessageMedia.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/ChatUpdatingMessageMedia.swift @@ -6,13 +6,15 @@ public final class ChatUpdatingMessageMedia: Equatable { public let entities: TextEntitiesMessageAttribute? public let disableUrlPreview: Bool public let media: RequestEditMessageMedia + public let invertMediaAttribute: InvertMediaMessageAttribute? public let progress: Float - init(text: String, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, media: RequestEditMessageMedia, progress: Float) { + init(text: String, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, media: RequestEditMessageMedia, invertMediaAttribute: InvertMediaMessageAttribute?, progress: Float) { self.text = text self.entities = entities self.disableUrlPreview = disableUrlPreview self.media = media + self.invertMediaAttribute = invertMediaAttribute self.progress = progress } @@ -29,6 +31,9 @@ public final class ChatUpdatingMessageMedia: Equatable { if lhs.media != rhs.media { return false } + if (lhs.invertMediaAttribute == nil) != (rhs.invertMediaAttribute == nil) { + return false + } if lhs.progress != rhs.progress { return false } @@ -36,6 +41,6 @@ public final class ChatUpdatingMessageMedia: Equatable { } func withProgress(_ progress: Float) -> ChatUpdatingMessageMedia { - return ChatUpdatingMessageMedia(text: self.text, entities: self.entities, disableUrlPreview: self.disableUrlPreview, media: self.media, progress: progress) + return ChatUpdatingMessageMedia(text: self.text, entities: self.entities, disableUrlPreview: self.disableUrlPreview, media: self.media, invertMediaAttribute: self.invertMediaAttribute, progress: progress) } } diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift index 81441e6a72..ba3623cb25 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift @@ -71,7 +71,7 @@ private final class PendingUpdateMessageManagerImpl { } let disposable = MetaDisposable() - let context = PendingUpdateMessageContext(value: ChatUpdatingMessageMedia(text: text, entities: entities, disableUrlPreview: disableUrlPreview, media: media, progress: 0.0), disposable: disposable) + let context = PendingUpdateMessageContext(value: ChatUpdatingMessageMedia(text: text, entities: entities, disableUrlPreview: disableUrlPreview, media: media, invertMediaAttribute: invertMediaAttribute, progress: 0.0), disposable: disposable) self.contexts[messageId] = context let queue = self.queue diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index db9deb4d03..0c49985624 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -250,7 +250,14 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ messageWithCaptionToAdd = (message, itemAttributes) skipText = true } else { - if let _ = message.attributes.first(where: { $0 is InvertMediaMessageAttribute }) { + var isMediaInverted = false + if let updatingMedia = itemAttributes.updatingMedia { + isMediaInverted = updatingMedia.invertMediaAttribute != nil + } else if let _ = message.attributes.first(where: { $0 is InvertMediaMessageAttribute }) { + isMediaInverted = true + } + + if isMediaInverted { result.insert((message, ChatMessageTextBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: isFile ? .condensed : .default)), at: 0) } else { result.append((message, ChatMessageTextBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: isFile ? .condensed : .default))) @@ -303,7 +310,14 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ } if let (messageWithCaptionToAdd, itemAttributes) = messageWithCaptionToAdd { - if let _ = messageWithCaptionToAdd.attributes.first(where: { $0 is InvertMediaMessageAttribute }) { + var isMediaInverted = false + if let updatingMedia = itemAttributes.updatingMedia { + isMediaInverted = updatingMedia.invertMediaAttribute != nil + } else if let _ = messageWithCaptionToAdd.attributes.first(where: { $0 is InvertMediaMessageAttribute }) { + isMediaInverted = true + } + + if isMediaInverted { if result.isEmpty { needReactions = false } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageMediaBubbleContentNode/Sources/ChatMessageMediaBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageMediaBubbleContentNode/Sources/ChatMessageMediaBubbleContentNode.swift index 011839327a..bedbbf5c46 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageMediaBubbleContentNode/Sources/ChatMessageMediaBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageMediaBubbleContentNode/Sources/ChatMessageMediaBubbleContentNode.swift @@ -300,6 +300,8 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? if case .customChatContents = item.associatedData.subject { statusType = nil + } else if item.message.timestamp == 0 { + statusType = nil } else { switch preparePosition { case .linear(_, .None), .linear(_, .Neighbour(true, _, _)): diff --git a/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/BUILD b/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/BUILD index 43b1d9a9b9..1434c81b04 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/BUILD @@ -23,6 +23,12 @@ swift_library( "//submodules/WallpaperBackgroundNode", "//submodules/AudioWaveform", "//submodules/TelegramUI/Components/Chat/ChatMessageItemView", + "//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode", + "//submodules/TelegramUI/Components/Chat/ChatMessageMediaBubbleContentNode", + "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", + "//submodules/TelegramUI/Components/Chat/ChatHistoryEntry", + "//submodules/TelegramUI/Components/ChatControllerInteraction", + "//submodules/TelegramUIPreferences", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift b/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift index 9cc921cdf2..01fedd35ff 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift @@ -13,6 +13,12 @@ import TelegramCore import WallpaperBackgroundNode import AudioWaveform import ChatMessageItemView +import ChatMessageItemCommon +import ChatMessageBubbleContentNode +import ChatMessageMediaBubbleContentNode +import ChatControllerInteraction +import TelegramUIPreferences +import ChatHistoryEntry public final class ChatSendContactMessageContextPreview: UIView, ChatSendMessageContextScreenMediaPreview { private let context: AccountContext @@ -318,3 +324,260 @@ public final class ChatSendAudioMessageContextPreview: UIView, ChatSendMessageCo return CGSize(width: contentFrame.width - 4.0, height: contentFrame.height + 2.0) } } + +public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMessageContextScreenMediaPreview { + private let context: AccountContext + private let presentationData: PresentationData + private let wallpaperBackgroundNode: WallpaperBackgroundNode? + private let messages: [Message] + + private var chatPresentationData: ChatPresentationData? + + private var messageNode: ChatMessageMediaBubbleContentNode? + private let messagesContainer: UIView + + public var isReady: Signal { + return .single(true) + } + + public var view: UIView { + return self + } + + public var globalClippingRect: CGRect? { + return nil + } + + public var layoutType: ChatSendMessageContextScreenMediaPreviewLayoutType { + return .media + } + + public init(context: AccountContext, presentationData: PresentationData, wallpaperBackgroundNode: WallpaperBackgroundNode?, messages: [EngineMessage]) { + self.context = context + self.presentationData = presentationData + self.wallpaperBackgroundNode = wallpaperBackgroundNode + self.messages = messages.map { message in + return message._asMessage().withUpdatedTimestamp(0) + } + + self.messagesContainer = UIView() + + super.init(frame: CGRect()) + + self.addSubview(self.messagesContainer) + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + } + + public func animateIn(transition: Transition) { + transition.animateAlpha(view: self.messagesContainer, from: 0.0, to: 1.0) + transition.animateScale(view: self.messagesContainer, from: 0.001, to: 1.0) + } + + public func animateOut(transition: Transition) { + transition.setAlpha(view: self.messagesContainer, alpha: 0.0) + transition.setScale(view: self.messagesContainer, scale: 0.001) + } + + public func animateOutOnSend(transition: Transition) { + transition.setAlpha(view: self.messagesContainer, alpha: 0.0) + } + + public func update(containerSize: CGSize, transition: Transition) -> CGSize { + let messageNode: ChatMessageMediaBubbleContentNode + if let current = self.messageNode { + messageNode = current + } else { + messageNode = ChatMessageMediaBubbleContentNode() + self.messageNode = messageNode + self.messagesContainer.addSubview(messageNode.view) + } + + let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } + + let chatPresentationData: ChatPresentationData + if let current = self.chatPresentationData { + chatPresentationData = current + } else { + chatPresentationData = ChatPresentationData( + theme: ChatPresentationThemeData( + theme: presentationData.theme, + wallpaper: presentationData.chatWallpaper + ), + fontSize: presentationData.chatFontSize, + strings: presentationData.strings, + dateTimeFormat: presentationData.dateTimeFormat, + nameDisplayOrder: presentationData.nameDisplayOrder, + disableAnimations: false, + largeEmoji: false, + chatBubbleCorners: presentationData.chatBubbleCorners + ) + self.chatPresentationData = chatPresentationData + } + + let controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in + return false }, openPeer: { _, _, _, _ in }, openPeerMention: { _, _ in }, openMessageContextMenu: { _, _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in + }, updateMessageReaction: { _, _, _, _ in }, activateMessagePinch: { _ in + }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _, _ in }, navigateToMessageStandalone: { _ in + }, navigateToThreadMessage: { _, _, _ in + }, tapMessage: { _ in + }, clickThroughMessage: { + }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _, _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _, _ in + return false + }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _, _ in }, openUrl: { _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in + }, presentController: { _, _ in + }, presentControllerInCurrent: { _, _ in + }, navigationController: { + return nil + }, chatControllerNode: { + return nil + }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in + }, canSetupReply: { _ in + return .none + }, canSendMessages: { + return false + }, navigateToFirstDateMessage: { _, _ in + }, requestRedeliveryOfFailedMessages: { _ in + }, addContact: { _ in + }, rateCall: { _, _, _ in + }, requestSelectMessagePollOptions: { _, _ in + }, requestOpenMessagePollResults: { _, _ in + }, openAppStorePage: { + }, displayMessageTooltip: { _, _, _, _, _ in + }, seekToTimecode: { _, _, _ in + }, scheduleCurrentMessage: { + }, sendScheduledMessagesNow: { _ in + }, editScheduledMessagesTime: { _ in + }, performTextSelectionAction: { _, _, _, _ in + }, displayImportedMessageTooltip: { _ in + }, displaySwipeToReplyHint: { + }, dismissReplyMarkupMessage: { _ in + }, openMessagePollResults: { _, _ in + }, openPollCreation: { _ in + }, displayPollSolution: { _, _ in + }, displayPsa: { _, _ in + }, displayDiceTooltip: { _ in + }, animateDiceSuccess: { _, _ in + }, displayPremiumStickerTooltip: { _, _ in + }, displayEmojiPackTooltip: { _, _ in + }, openPeerContextMenu: { _, _, _, _, _ in + }, openMessageReplies: { _, _, _ in + }, openReplyThreadOriginalMessage: { _ in + }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in + }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false + }, getMessageTransitionNode: { + return nil + }, updateChoosingSticker: { _ in + }, commitEmojiInteraction: { _, _, _, _ in + }, openLargeEmojiInfo: { _, _, _ in + }, openJoinLink: { _ in + }, openWebView: { _, _, _, _ in + }, activateAdAction: { _, _ in + }, openRequestedPeerSelection: { _, _, _, _ in + }, saveMediaToFiles: { _ in + }, openNoAdsDemo: { + }, openAdsInfo: { + }, displayGiveawayParticipationStatus: { _ in + }, openPremiumStatusInfo: { _, _, _, _ in + }, openRecommendedChannelContextMenu: { _, _, _ in + }, openGroupBoostInfo: { _, _ in + }, openStickerEditor: { + }, openPhoneContextMenu: { _ in + }, openAgeRestrictedMessageMedia: { _, _ in + }, playMessageEffect: { _ in + }, editMessageFactCheck: { _ in + }, requestMessageUpdate: { _, _ in + }, cancelInteractiveKeyboardGestures: { + }, dismissTextInput: { + }, scrollToMessageId: { _ in + }, navigateToStory: { _, _ in + }, attemptedNavigationToPrivateQuote: { _ in + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, + pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: self.context, backgroundNode: self.wallpaperBackgroundNode)) + + let associatedData = ChatMessageItemAssociatedData( + automaticDownloadPeerType: .channel, + automaticDownloadPeerId: nil, + automaticDownloadNetworkType: .cellular, + isRecentActions: false, + availableReactions: nil, + availableMessageEffects: nil, + savedMessageTags: nil, + defaultReaction: nil, + isPremium: false, + accountPeer: nil + ) + + let entryAttributes = ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil) + + let item = ChatMessageBubbleContentItem( + context: self.context, + controllerInteraction: controllerInteraction, + message: self.messages[0], + topMessage: self.messages[0], + read: true, + chatLocation: .peer(id: self.context.account.peerId), + presentationData: chatPresentationData, + associatedData: associatedData, + attributes: entryAttributes, + isItemPinned: false, + isItemEdited: false + ) + + let makeMessageLayout = messageNode.asyncLayoutContent() + let layoutConstants = chatMessageItemLayoutConstants( + (ChatMessageItemLayoutConstants.compact, ChatMessageItemLayoutConstants.regular), + params: ListViewItemLayoutParams( + width: containerSize.width, + leftInset: 0.0, + rightInset: 0.0, + availableHeight: 10000.0 + ), + presentationData: chatPresentationData + ) + + let (_, _, _, continueMessageLayout) = makeMessageLayout( + item, + layoutConstants, + ChatMessageBubblePreparePosition.linear( + top: ChatMessageBubbleRelativePosition.None(.None(.None)), + bottom: ChatMessageBubbleRelativePosition.None(.None(.None)) + ), + nil, + CGSize(width: containerSize.width, height: 10000.0), + 0.0 + ) + + let (finalizedWidth, finalizeMessageLayout) = continueMessageLayout( + CGSize(width: containerSize.width, height: 10000.0), + ChatMessageBubbleContentPosition.linear( + top: ChatMessageBubbleRelativePosition.None(.None(.None)), + bottom: ChatMessageBubbleRelativePosition.None(.None(.None)) + ) + ) + let _ = finalizedWidth + + let (finalizedSize, apply) = finalizeMessageLayout(finalizedWidth) + apply(.None, true, nil) + + let contentFrameInset = UIEdgeInsets(top: -2.0, left: -2.0, bottom: -2.0, right: -2.0) + + let contentFrame = CGRect(origin: CGPoint(x: contentFrameInset.left, y: contentFrameInset.top), size: finalizedSize) + messageNode.frame = contentFrame + + let messagesContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: contentFrame.width + contentFrameInset.left + contentFrameInset.right, height: contentFrame.height + contentFrameInset.top + contentFrameInset.bottom)) + + self.messagesContainer.frame = messagesContainerFrame + + return messagesContainerFrame.size + } +} diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index a90fef4c61..892682cd50 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -1824,7 +1824,7 @@ extension ChatControllerImpl { } var updated = state.updatedInterfaceState { interfaceState in - return interfaceState.withUpdatedEditMessage(ChatEditMessageState(messageId: messageId, inputState: ChatTextInputState(inputText: inputText), disableUrlPreviews: disableUrlPreviews, inputTextMaxLength: inputTextMaxLength)) + return interfaceState.withUpdatedEditMessage(ChatEditMessageState(messageId: messageId, inputState: ChatTextInputState(inputText: inputText), disableUrlPreviews: disableUrlPreviews, inputTextMaxLength: inputTextMaxLength, mediaCaptionIsAbove: nil)) } let (updatedState, updatedPreviewQueryState) = updatedChatEditInterfaceMessageState(context: strongSelf.context, state: updated, message: message) @@ -2169,6 +2169,14 @@ extension ChatControllerImpl { invertedMediaAttribute = attribute as? InvertMediaMessageAttribute } + if let mediaCaptionIsAbove = editMessage.mediaCaptionIsAbove { + if mediaCaptionIsAbove { + invertedMediaAttribute = InvertMediaMessageAttribute() + } else { + invertedMediaAttribute = nil + } + } + let text = trimChatInputText(convertMarkdownToAttributes(expandedInputStateAttributedString(editMessage.inputState.inputText))) let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) diff --git a/submodules/TelegramUI/Sources/Chat/ChatMessageDisplaySendMessageOptions.swift b/submodules/TelegramUI/Sources/Chat/ChatMessageDisplaySendMessageOptions.swift index c76786848a..a4b19fcdb3 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatMessageDisplaySendMessageOptions.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatMessageDisplaySendMessageOptions.swift @@ -58,15 +58,8 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no let editMessages: Signal<[EngineMessage], NoError> if let editMessage = selfController.presentationInterfaceState.interfaceState.editMessage { editMessages = selfController.context.engine.data.get( - TelegramEngine.EngineData.Item.Messages.Message(id: editMessage.messageId) + TelegramEngine.EngineData.Item.Messages.MessageGroup(id: editMessage.messageId) ) - |> map { message -> [EngineMessage] in - if let message { - return [message] - } else { - return [] - } - } } else { editMessages = .single([]) } @@ -83,17 +76,62 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no return } - if let _ = selfController.presentationInterfaceState.interfaceState.editMessage { + if let editMessage = selfController.presentationInterfaceState.interfaceState.editMessage { if editMessages.isEmpty { return } + + var mediaPreview: ChatSendMessageContextScreenMediaPreview? + if editMessages.contains(where: { message in + return message.media.contains(where: { media in + if media is TelegramMediaImage { + return true + } else if let file = media as? TelegramMediaFile, file.isVideo { + return true + } + return false + }) + }) { + mediaPreview = ChatSendGroupMediaMessageContextPreview( + context: selfController.context, + presentationData: selfController.presentationData, + wallpaperBackgroundNode: selfController.chatDisplayNode.backgroundNode, + messages: editMessages + ) + } + + let mediaCaptionIsAbove: Bool + if let value = editMessage.mediaCaptionIsAbove { + mediaCaptionIsAbove = value + } else { + mediaCaptionIsAbove = editMessages.contains(where: { + $0.attributes.contains(where: { + $0 is InvertMediaMessageAttribute + }) + }) + } + let controller = makeChatSendMessageActionSheetController( context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, peerId: selfController.presentationInterfaceState.chatLocation.peerId, params: .editMessage(SendMessageActionSheetControllerParams.EditMessage( messages: editMessages, - mediaPreview: nil + mediaPreview: mediaPreview, + mediaCaptionIsAbove: (mediaCaptionIsAbove, { [weak selfController] updatedMediaCaptionIsAbove in + guard let selfController else { + return + } + selfController.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in + return state.updatedInterfaceState { interfaceState in + guard var editMessage = interfaceState.editMessage else { + return interfaceState + } + editMessage.mediaCaptionIsAbove = updatedMediaCaptionIsAbove + return interfaceState.withUpdatedEditMessage(editMessage) + } + }) + }) )), hasEntityKeyboard: hasEntityKeyboard, gesture: gesture,