Edit message media preview

This commit is contained in:
Isaac 2024-05-26 20:42:43 +04:00
parent 2456eba1b4
commit d6ebf1b4ff
12 changed files with 404 additions and 35 deletions

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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
)
}

View File

@ -245,18 +245,29 @@ final class MessageItemView: UIView {
func animateIn(
sourceTextInputView: ChatInputTextView?,
isEditMessage: Bool,
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 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)
@ -265,6 +276,7 @@ final class MessageItemView: UIView {
}
}
}
}
func update(
context: AccountContext,
@ -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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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, _, _)):

View File

@ -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",

View File

@ -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<Bool, NoError> {
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
}
}

View File

@ -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))

View File

@ -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,