diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index a90d00bcfd..153c54732b 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -191,6 +191,7 @@ private var declaredEncodables: Void = { declareEncodable(NonPremiumMessageAttribute.self, f: { NonPremiumMessageAttribute(decoder: $0) }) declareEncodable(TelegramExtendedMedia.self, f: { TelegramExtendedMedia(decoder: $0) }) declareEncodable(TelegramPeerUsername.self, f: { TelegramPeerUsername(decoder: $0) }) + declareEncodable(MediaSpoilerMessageAttribute.self, f: { MediaSpoilerMessageAttribute(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 817c746084..b5b061b10a 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -266,48 +266,48 @@ func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: Refere return nil } -func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerId: PeerId) -> (Media?, Int32?, Bool?) { +func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerId: PeerId) -> (Media?, Int32?, Bool?, Bool?) { if let media = media { switch media { - case let .messageMediaPhoto(_, photo, ttlSeconds): + case let .messageMediaPhoto(flags, photo, ttlSeconds): if let photo = photo { if let mediaImage = telegramMediaImageFromApiPhoto(photo) { - return (mediaImage, ttlSeconds, nil) + return (mediaImage, ttlSeconds, nil, (flags & (1 << 3)) != 0) } } else { - return (TelegramMediaExpiredContent(data: .image), nil, nil) + return (TelegramMediaExpiredContent(data: .image), nil, nil, nil) } case let .messageMediaContact(phoneNumber, firstName, lastName, vcard, userId): let contactPeerId: PeerId? = userId == 0 ? nil : PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) let mediaContact = TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: contactPeerId, vCardData: vcard.isEmpty ? nil : vcard) - return (mediaContact, nil, nil) + return (mediaContact, nil, nil, nil) case let .messageMediaGeo(geo): let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil, heading: nil) - return (mediaMap, nil, nil) + return (mediaMap, nil, nil, nil) case let .messageMediaVenue(geo, title, address, provider, venueId, venueType): let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId, venueType: venueType, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil, heading: nil) - return (mediaMap, nil, nil) + return (mediaMap, nil, nil, nil) case let .messageMediaGeoLive(_, geo, heading, period, proximityNotificationRadius): let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period, liveProximityNotificationRadius: proximityNotificationRadius, heading: heading) - return (mediaMap, nil, nil) + return (mediaMap, nil, nil, nil) case let .messageMediaDocument(flags, document, ttlSeconds): if let document = document { if let mediaFile = telegramMediaFileFromApiDocument(document) { - return (mediaFile, ttlSeconds, (flags & (1 << 3)) != 0) + return (mediaFile, ttlSeconds, (flags & (1 << 3)) != 0, (flags & (1 << 4)) != 0) } } else { - return (TelegramMediaExpiredContent(data: .file), nil, nil) + return (TelegramMediaExpiredContent(data: .file), nil, nil, nil) } case let .messageMediaWebPage(webpage): if let mediaWebpage = telegramMediaWebpageFromApiWebpage(webpage, url: nil) { - return (mediaWebpage, nil, nil) + return (mediaWebpage, nil, nil, nil) } case .messageMediaUnsupported: - return (TelegramMediaUnsupported(), nil, nil) + return (TelegramMediaUnsupported(), nil, nil, nil) case .messageMediaEmpty: break case let .messageMediaGame(game): - return (TelegramMediaGame(apiGame: game), nil, nil) + return (TelegramMediaGame(apiGame: game), nil, nil, nil) case let .messageMediaInvoice(flags, title, description, photo, receiptMsgId, currency, totalAmount, startParam, apiExtendedMedia): var parsedFlags = TelegramMediaInvoiceFlags() if (flags & (1 << 3)) != 0 { @@ -331,7 +331,7 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI } extendedMedia = .preview(dimensions: dimensions, immediateThumbnailData: immediateThumbnailData, videoDuration: videoDuration) case let .messageExtendedMedia(apiMedia): - let (media, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, peerId) + let (media, _, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, peerId) if let media = media { extendedMedia = .full(media: media) } else { @@ -342,7 +342,7 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI extendedMedia = nil } - return (TelegramMediaInvoice(title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), receiptMessageId: receiptMsgId.flatMap { MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }, currency: currency, totalAmount: totalAmount, startParam: startParam, extendedMedia: extendedMedia, flags: parsedFlags, version: TelegramMediaInvoice.lastVersion), nil, nil) + return (TelegramMediaInvoice(title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), receiptMessageId: receiptMsgId.flatMap { MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }, currency: currency, totalAmount: totalAmount, startParam: startParam, extendedMedia: extendedMedia, flags: parsedFlags, version: TelegramMediaInvoice.lastVersion), nil, nil, nil) case let .messageMediaPoll(poll, results): switch poll { case let .poll(id, flags, question, answers, closePeriod, _): @@ -358,14 +358,14 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI } else { kind = .poll(multipleAnswers: (flags & (1 << 2)) != 0) } - return (TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), publicity: publicity, kind: kind, text: question, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod), nil, nil) + return (TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), publicity: publicity, kind: kind, text: question, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod), nil, nil, nil) } case let .messageMediaDice(value, emoticon): - return (TelegramMediaDice(emoji: emoticon, value: value), nil, nil) + return (TelegramMediaDice(emoji: emoticon, value: value), nil, nil, nil) } } - return (nil, nil, nil) + return (nil, nil, nil, nil) } func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [MessageTextEntity] { @@ -534,19 +534,22 @@ extension StoreMessage { var consumableContent: (Bool, Bool)? = nil if let media = media { - let (mediaValue, expirationTimer, nonPremium) = textMediaAndExpirationTimerFromApiMedia(media, peerId) + let (mediaValue, expirationTimer, nonPremium, hasSpoiler) = textMediaAndExpirationTimerFromApiMedia(media, peerId) if let mediaValue = mediaValue { medias.append(mediaValue) if let expirationTimer = expirationTimer, expirationTimer > 0 { attributes.append(AutoclearTimeoutMessageAttribute(timeout: expirationTimer, countdownBeginTime: nil)) - consumableContent = (true, false) } if let nonPremium = nonPremium, nonPremium { attributes.append(NonPremiumMessageAttribute()) } + + if let hasSpoiler = hasSpoiler, hasSpoiler { + attributes.append(MediaSpoilerMessageAttribute()) + } } } diff --git a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift index 359f920826..7b9daf339a 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift @@ -134,6 +134,8 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt return true case _ as SendAsMessageAttribute: return true + case _ as MediaSpoilerMessageAttribute: + return true default: return false } @@ -155,6 +157,8 @@ private func filterMessageAttributesForForwardedMessage(_ attributes: [MessageAt return true case _ as SendAsMessageAttribute: return true + case _ as MediaSpoilerMessageAttribute: + return true case let attribute as ReplyMessageAttribute: if let forwardedMessageIds = forwardedMessageIds { return forwardedMessageIds.contains(attribute.messageId) diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift index 4fcbd889b7..bbf912d96b 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift @@ -435,7 +435,8 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans stickers = stickersValue flags |= 1 << 0 } - break + } else if let _ = attribute as? MediaSpoilerMessageAttribute { + flags |= 1 << 2 } } return postbox.transaction { transaction -> Api.InputPeer? in @@ -740,6 +741,8 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili if let attribute = attribute as? AutoclearTimeoutMessageAttribute { flags |= 1 << 1 ttlSeconds = attribute.timeout + } else if let _ = attribute as? MediaSpoilerMessageAttribute { + flags |= 1 << 5 } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 94c9d73ccc..ba04e25306 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1103,7 +1103,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: let messageText = text var medias: [Media] = [] - let (mediaValue, expirationTimer, nonPremium) = textMediaAndExpirationTimerFromApiMedia(media, peerId) + let (mediaValue, expirationTimer, nonPremium, hasSpoiler) = textMediaAndExpirationTimerFromApiMedia(media, peerId) if let mediaValue = mediaValue { medias.append(mediaValue) } @@ -1115,6 +1115,10 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: attributes.append(NonPremiumMessageAttribute()) } + if let hasSpoiler = hasSpoiler, hasSpoiler { + attributes.append(MediaSpoilerMessageAttribute()) + } + if type.hasPrefix("auth") { updatedState.authorizationListUpdated = true } @@ -4250,7 +4254,7 @@ func replayFinalState( } updatedExtendedMedia = .preview(dimensions: dimensions, immediateThumbnailData: immediateThumbnailData, videoDuration: videoDuration) case let .messageExtendedMedia(apiMedia): - let (media, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId) + let (media, _, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId) if let media = media { updatedExtendedMedia = .full(media: media) } else { diff --git a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift index 3b406e9fd5..2fcbf53e45 100644 --- a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift @@ -148,7 +148,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes text = updatedMessage.text forwardInfo = updatedMessage.forwardInfo } else if case let .updateShortSentMessage(_, _, _, _, _, apiMedia, entities, ttlPeriod) = result { - let (mediaValue, _, nonPremium) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId) + let (mediaValue, _, nonPremium, hasSpoiler) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId) if let mediaValue = mediaValue { media = [mediaValue] } else { @@ -176,6 +176,10 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes updatedAttributes.append(NonPremiumMessageAttribute()) } + if let hasSpoiler = hasSpoiler, hasSpoiler { + updatedAttributes.append(MediaSpoilerMessageAttribute()) + } + if Namespaces.Message.allScheduled.contains(message.id.namespace) && updatedId.namespace == Namespaces.Message.Cloud { for i in 0 ..< updatedAttributes.count { if updatedAttributes[i] is OutgoingScheduleInfoMessageAttribute { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaSpoilerMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaSpoilerMessageAttribute.swift new file mode 100644 index 0000000000..c01d689fda --- /dev/null +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaSpoilerMessageAttribute.swift @@ -0,0 +1,16 @@ +import Foundation +import Postbox + +public class MediaSpoilerMessageAttribute: MessageAttribute { + public var associatedMessageIds: [MessageId] = [] + + public init() { + + } + + required public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } +}