mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Edit message media preview
This commit is contained in:
parent
2456eba1b4
commit
d6ebf1b4ff
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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, _, _)):
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user