This commit is contained in:
Isaac 2026-03-09 20:23:48 +01:00
commit 68e26d20aa
23 changed files with 113 additions and 81 deletions

View file

@ -15973,3 +15973,6 @@ Error: %8$@";
"Month.NomOctober" = "October";
"Month.NomNovember" = "November";
"Month.NomDecember" = "December";
"ChannelMessages.LinkTitle" = "LINK TO DIRECT MESSAGES";
"Chat.ContactChannel" = "CONTACT CHANNEL";

View file

@ -195,9 +195,14 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
break
}
}
case _ as TelegramMediaImage:
case let imageMedia as TelegramMediaImage:
if message.text.isEmpty {
messageText = strings.Message_Photo
if imageMedia.flags.contains(.isLivePhoto) {
//TODO:localize
messageText = "Live Photo"
} else {
messageText = strings.Message_Photo
}
} else if enableMediaEmoji {
messageText = "🖼 \(messageText)"
}
@ -255,21 +260,12 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
break inner
} else {
if message.text.isEmpty {
if flags.contains(.isLivePhoto) {
//TODO:localize
messageText = "Live Photo"
} else {
messageText = strings.Message_Video
}
messageText = strings.Message_Video
processed = true
} else {
if enableMediaEmoji {
if !fileMedia.isAnimated {
if flags.contains(.isLivePhoto) {
messageText = "🖼 \(messageText)"
} else {
messageText = "📹 \(messageText)"
}
messageText = "📹 \(messageText)"
}
}
processed = true

View file

@ -897,10 +897,7 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
fileAttributes.append(.Animated)
}
if !asFile {
var flags: TelegramMediaVideoFlags = [.supportsStreaming]
if isLivePhoto {
flags.insert(.isLivePhoto)
}
let flags: TelegramMediaVideoFlags = [.supportsStreaming]
fileAttributes.append(.Video(duration: finalDuration, size: PixelDimensions(finalDimensions), flags: flags, preloadSize: nil, coverTime: nil, videoCodec: nil))
if let adjustments = adjustments {
if adjustments.sendAsGif {

View file

@ -108,7 +108,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
case groupPrivacy(PresentationTheme, String, String)
case groupPrivacyFooter
case voiceMessagePrivacy(PresentationTheme, String, String, Bool)
case messagePrivacy(PresentationTheme, GlobalPrivacySettings.NonContactChatsPrivacy, Bool)
case messagePrivacy(PresentationTheme, String, Bool)
case bioPrivacy(PresentationTheme, String, String)
case birthdayPrivacy(PresentationTheme, String, String)
case savedMusicPrivacy(PresentationTheme, String, String)
@ -454,20 +454,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
arguments.openVoiceMessagePrivacy()
})
case let .messagePrivacy(theme, value, hasPremium):
let label: String
var effectiveValue = value
if !hasPremium {
effectiveValue = .everybody
}
switch effectiveValue {
case .everybody:
label = presentationData.strings.Settings_Privacy_Messages_ValueEveryone
case .requirePremium:
label = presentationData.strings.Settings_Privacy_Messages_ValueContactsAndPremium
case .paidMessages:
label = presentationData.strings.Settings_Privacy_Messages_ValuePaid
}
return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, title: presentationData.strings.Settings_Privacy_Messages, titleIcon: hasPremium ? PresentationResourcesItemList.premiumIcon(theme) : nil, label: label, sectionId: self.section, style: .blocks, action: {
return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, title: presentationData.strings.Settings_Privacy_Messages, titleIcon: hasPremium ? PresentationResourcesItemList.premiumIcon(theme) : nil, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openMessagePrivacy()
})
case let .bioPrivacy(_, text, value):
@ -639,7 +626,8 @@ private func privacyAndSecurityControllerEntries(
isPremiumDisabled: Bool,
isPremium: Bool,
loginEmail: String?,
accountPeer: EnginePeer?
accountPeer: EnginePeer?,
appConfiguration: AppConfiguration
) -> [PrivacyAndSecurityEntry] {
var entries: [PrivacyAndSecurityEntry] = []
@ -729,7 +717,21 @@ private func privacyAndSecurityControllerEntries(
entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceCalls)))
if !isPremiumDisabled || isPremium {
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, stringForSelectiveSettings(strings: presentationData.strings, settings: isPremium ? privacySettings.voiceMessages : .enableEveryone(disableFor: [:])), isPremium))
entries.append(.messagePrivacy(presentationData.theme, privacySettings.globalSettings.nonContactChatsPrivacy, isPremium))
var effectiveValue = privacySettings.globalSettings.nonContactChatsPrivacy
if let data = appConfiguration.data, let setting = data["new_noncontact_peers_require_premium_without_ownpremium"] as? Bool, setting {
} else if !isPremium {
effectiveValue = .everybody
}
let label: String
switch effectiveValue {
case .everybody:
label = presentationData.strings.Settings_Privacy_Messages_ValueEveryone
case .requirePremium:
label = presentationData.strings.Settings_Privacy_Messages_ValueContactsAndPremium
case .paidMessages:
label = presentationData.strings.Settings_Privacy_Messages_ValuePaid
}
entries.append(.messagePrivacy(presentationData.theme, label, isPremium))
}
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_InviteItem, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.groupInvitations)))
entries.append(.groupPrivacyFooter)
@ -745,6 +747,7 @@ private func privacyAndSecurityControllerEntries(
entries.append(.voiceCallPrivacy(presentationData.theme, presentationData.strings.Privacy_Calls, presentationData.strings.Channel_NotificationLoading))
if !isPremiumDisabled || isPremium {
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, presentationData.strings.Channel_NotificationLoading, isPremium))
entries.append(.messagePrivacy(presentationData.theme, presentationData.strings.Channel_NotificationLoading, isPremium))
}
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.Privacy_GroupsAndChannels, presentationData.strings.Channel_NotificationLoading))
entries.append(.groupPrivacyFooter)
@ -1553,7 +1556,7 @@ public func privacyAndSecurityController(
let isPremium = accountPeer?.isPremium ?? false
let isPremiumDisabled = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }).isPremiumDisabled
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: privacyAndSecurityControllerEntries(presentationData: presentationData, state: state, privacySettings: privacySettings, accessChallengeData: accessChallengeData.data, blockedPeerCount: blockedPeersState.totalCount, activeWebsitesCount: activeWebsitesState.sessions.count, hasTwoStepAuth: twoStepAuth.0, twoStepAuthData: twoStepAuth.1, hasPasskeys: passkeys.0, displayPasskeys: displayPasskeys, canAutoarchive: canAutoarchive, isPremiumDisabled: isPremiumDisabled, isPremium: isPremium, loginEmail: loginEmail, accountPeer: accountPeer), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: privacyAndSecurityControllerEntries(presentationData: presentationData, state: state, privacySettings: privacySettings, accessChallengeData: accessChallengeData.data, blockedPeerCount: blockedPeersState.totalCount, activeWebsitesCount: activeWebsitesState.sessions.count, hasTwoStepAuth: twoStepAuth.0, twoStepAuthData: twoStepAuth.1, hasPasskeys: passkeys.0, displayPasskeys: displayPasskeys, canAutoarchive: canAutoarchive, isPremiumDisabled: isPremiumDisabled, isPremium: isPremium, loginEmail: loginEmail, accountPeer: accountPeer, appConfiguration: appConfiguration), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
return (controllerState, (listState, arguments))
}

View file

@ -2,6 +2,7 @@ include "MediaId.fbs";
include "TelegramMediaImageRepresentation.fbs";
include "StickerPackReference.fbs";
include "PartialMediaReference.fbs";
include "TelegramMediaFile.fbs";
namespace TelegramCore;
@ -46,6 +47,7 @@ table TelegramMediaImage {
reference:TelegramMediaImageReference (id: 5);
partialReference:PartialMediaReference (id: 6);
flags:int32 (id: 7);
video:TelegramMediaFile (id: 8);
}
root_type TelegramMediaImage;

View file

@ -50,7 +50,7 @@ extension BotInfo {
switch apiBotInfo {
case let .botInfo(botInfoData):
let (_, _, description, descriptionPhoto, descriptionDocument, apiCommands, apiMenuButton, privacyPolicyUrl, appSettings, verifierSettings) = (botInfoData.flags, botInfoData.userId, botInfoData.description, botInfoData.descriptionPhoto, botInfoData.descriptionDocument, botInfoData.commands, botInfoData.menuButton, botInfoData.privacyPolicyUrl, botInfoData.appSettings, botInfoData.verifierSettings)
let photo: TelegramMediaImage? = descriptionPhoto.flatMap(telegramMediaImageFromApiPhoto)
let photo: TelegramMediaImage? = descriptionPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
let video: TelegramMediaFile? = descriptionDocument.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
var commands: [BotCommand] = []
if let apiCommands = apiCommands {

View file

@ -372,7 +372,7 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
case let .messageMediaPhoto(messageMediaPhotoData):
let (flags, photo, ttlSeconds) = (messageMediaPhotoData.flags, messageMediaPhotoData.photo, messageMediaPhotoData.ttlSeconds)
if let photo = photo {
if let mediaImage = telegramMediaImageFromApiPhoto(photo) {
if let mediaImage = telegramMediaImageFromApiPhoto(photo, video: messageMediaPhotoData.video) {
return (mediaImage, ttlSeconds, nil, (flags & (1 << 3)) != 0, nil, nil)
}
} else {
@ -398,7 +398,7 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
case let .messageMediaDocument(messageMediaDocumentData):
let (flags, document, altDocuments, coverPhoto, videoTimestamp, ttlSeconds) = (messageMediaDocumentData.flags, messageMediaDocumentData.document, messageMediaDocumentData.altDocuments, messageMediaDocumentData.videoCover, messageMediaDocumentData.videoTimestamp, messageMediaDocumentData.ttlSeconds)
if let document = document {
if let mediaFile = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments, videoCover: coverPhoto, isLivePhoto: (flags & (1 << 11)) != 0) {
if let mediaFile = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments, videoCover: coverPhoto) {
return (mediaFile, ttlSeconds, (flags & (1 << 3)) != 0, (flags & (1 << 4)) != 0, nil, videoTimestamp)
}
} else {

View file

@ -108,7 +108,7 @@ extension StickerMaskCoords {
}
}
func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAttribute], isLivePhoto: Bool = false) -> [TelegramMediaFileAttribute] {
func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAttribute]) -> [TelegramMediaFileAttribute] {
var result: [TelegramMediaFileAttribute] = []
for attribute in attributes {
switch attribute {
@ -137,9 +137,6 @@ func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAtt
if (flags & (1 << 3)) != 0 {
videoFlags.insert(.isSilent)
}
if isLivePhoto {
videoFlags.insert(.isLivePhoto)
}
result.append(.Video(duration: Double(duration), size: PixelDimensions(width: w, height: h), flags: videoFlags, preloadSize: preloadSize, coverTime: videoStart, videoCodec: videoCodec))
case let .documentAttributeAudio(documentAttributeAudioData):
let (flags, duration, title, performer, waveform) = (documentAttributeAudioData.flags, documentAttributeAudioData.duration, documentAttributeAudioData.title, documentAttributeAudioData.performer, documentAttributeAudioData.waveform)
@ -195,11 +192,11 @@ func telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: Int32,
return (immediateThumbnailData, representations)
}
func telegramMediaFileFromApiDocument(_ document: Api.Document, altDocuments: [Api.Document]?, videoCover: Api.Photo? = nil, isLivePhoto: Bool = false) -> TelegramMediaFile? {
func telegramMediaFileFromApiDocument(_ document: Api.Document, altDocuments: [Api.Document]?, videoCover: Api.Photo? = nil) -> TelegramMediaFile? {
switch document {
case let .document(documentData):
let (id, accessHash, fileReference, mimeType, size, thumbs, videoThumbs, dcId, attributes) = (documentData.id, documentData.accessHash, documentData.fileReference, documentData.mimeType, documentData.size, documentData.thumbs, documentData.videoThumbs, documentData.dcId, documentData.attributes)
var parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes, isLivePhoto: isLivePhoto)
var parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes)
var isSticker = false
var isAnimated = false
for attribute in parsedAttributes {
@ -241,7 +238,7 @@ func telegramMediaFileFromApiDocument(_ document: Api.Document, altDocuments: [A
alternativeRepresentations = altDocuments.compactMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
}
return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: id), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(dcId), fileId: id, accessHash: accessHash, size: size, fileReference: fileReference.makeData(), fileName: fileNameFromFileAttributes(parsedAttributes)), previewRepresentations: previewRepresentations, videoThumbnails: videoThumbnails, videoCover: videoCover.flatMap(telegramMediaImageFromApiPhoto), immediateThumbnailData: immediateThumbnail, mimeType: mimeType, size: size, attributes: parsedAttributes, alternativeRepresentations: alternativeRepresentations)
return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: id), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(dcId), fileId: id, accessHash: accessHash, size: size, fileReference: fileReference.makeData(), fileName: fileNameFromFileAttributes(parsedAttributes)), previewRepresentations: previewRepresentations, videoThumbnails: videoThumbnails, videoCover: videoCover.flatMap({ telegramMediaImageFromApiPhoto($0) }), immediateThumbnailData: immediateThumbnail, mimeType: mimeType, size: size, attributes: parsedAttributes, alternativeRepresentations: alternativeRepresentations)
case .documentEmpty:
return nil
}

View file

@ -34,7 +34,7 @@ func telegramMediaImageRepresentationsFromApiSizes(datacenterId: Int32, photoId:
return (immediateThumbnailData, representations)
}
func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? {
func telegramMediaImageFromApiPhoto(_ photo: Api.Photo, video: Api.Document? = nil) -> TelegramMediaImage? {
switch photo {
case let .photo(photoData):
let (flags, id, accessHash, fileReference, sizes, videoSizes, dcId) = (photoData.flags, photoData.id, photoData.accessHash, photoData.fileReference, photoData.sizes, photoData.videoSizes, photoData.dcId)
@ -67,8 +67,7 @@ func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? {
}
}
}
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: representations, videoRepresentations: videoRepresentations, immediateThumbnailData: immediateThumbnailData, emojiMarkup: emojiMarkup, reference: .cloud(imageId: id, accessHash: accessHash, fileReference: fileReference.makeData()), partialReference: nil, flags: imageFlags)
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: representations, videoRepresentations: videoRepresentations, immediateThumbnailData: immediateThumbnailData, emojiMarkup: emojiMarkup, reference: .cloud(imageId: id, accessHash: accessHash, fileReference: fileReference.makeData()), partialReference: nil, flags: imageFlags, video: video.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: nil) })
case .photoEmpty:
return nil
}

View file

@ -683,10 +683,10 @@ if "".isEmpty {
|> mapToSignal { inputPeer -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
if let inputPeer = inputPeer {
if autoclearMessageAttribute != nil {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: nil)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
}
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds))))
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: nil))))
|> mapError { _ -> PendingMessageUploadError in return .generic }
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
switch result {
@ -857,7 +857,7 @@ private func uploadedVideoCover(network: Network, postbox: Postbox, resourceRefe
case .progress:
return .complete()
case let .inputFile(file):
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: 0, file: file, stickers: [], ttlSeconds: nil))))
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: 0, file: file, stickers: [], ttlSeconds: nil, video: nil))))
|> mapError { _ -> PendingMessageUploadError in return .generic }
|> map { uploadResult in
switch uploadResult {
@ -1219,11 +1219,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
if videoTimestamp != nil {
flags |= 1 << 7
}
if file.isLivePhoto {
flags |= 1 << 8
}
if ttlSeconds != nil {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedDocument(.init(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, videoCover: videoCoverPhoto, videoTimestamp: videoTimestamp, ttlSeconds: ttlSeconds)), text), reuploadInfo: nil, cacheReferenceKey: referenceKey)))
}

View file

@ -767,7 +767,7 @@ private func uploadedImage(account: Account, data: Data) -> Signal<UploadMediaEv
switch next {
case let .inputFile(inputFileData):
let inputFile = inputFileData
return .result(Api.InputMedia.inputMediaUploadedPhoto(.init(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil)))
return .result(Api.InputMedia.inputMediaUploadedPhoto(.init(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil, video: nil)))
case .inputSecretFile:
preconditionFailure()
case let .progress(progress):

View file

@ -64,7 +64,7 @@ public func standaloneUploadedImage(postbox: Postbox, network: Network, peerId:
|> mapError { _ -> StandaloneUploadMediaError in }
|> mapToSignal { inputPeer -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
if let inputPeer = inputPeer {
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil))))
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil, video: nil))))
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch media {

View file

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 223
return 224
}
public func parseMessage(_ data: Data!) -> Any! {

View file

@ -750,7 +750,7 @@ extension Api.InputMedia {
if let _ = stickers {
flags |= (1 << 0)
}
return .inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds))
return .inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: nil))
default:
return self
}

View file

@ -311,7 +311,6 @@ public struct TelegramMediaVideoFlags: OptionSet {
public static let instantRoundVideo = TelegramMediaVideoFlags(rawValue: 1 << 0)
public static let supportsStreaming = TelegramMediaVideoFlags(rawValue: 1 << 1)
public static let isSilent = TelegramMediaVideoFlags(rawValue: 1 << 3)
public static let isLivePhoto = TelegramMediaVideoFlags(rawValue: 1 << 4)
}
public struct StickerMaskCoords: PostboxCoding, Equatable {
@ -1062,11 +1061,6 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
}
public var isLivePhoto: Bool {
for attribute in self.attributes {
if case .Video(_, _, let flags, _, _, _) = attribute {
return flags.contains(.isLivePhoto)
}
}
return false
}

View file

@ -101,6 +101,7 @@ public struct TelegramMediaImageFlags: OptionSet {
}
public static let hasStickers = TelegramMediaImageFlags(rawValue: 1 << 0)
public static let isLivePhoto = TelegramMediaImageFlags(rawValue: 1 << 1)
}
public enum TelegramMediaImageDecodingError: Error {
@ -282,12 +283,13 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
public let partialReference: PartialMediaReference?
public let peerIds: [PeerId] = []
public let flags: TelegramMediaImageFlags
public let video: TelegramMediaFile?
public var id: MediaId? {
return self.imageId
}
public init(imageId: MediaId, representations: [TelegramMediaImageRepresentation], videoRepresentations: [TelegramMediaImage.VideoRepresentation] = [], immediateThumbnailData: Data?, emojiMarkup: TelegramMediaImage.EmojiMarkup? = nil, reference: TelegramMediaImageReference?, partialReference: PartialMediaReference?, flags: TelegramMediaImageFlags) {
public init(imageId: MediaId, representations: [TelegramMediaImageRepresentation], videoRepresentations: [TelegramMediaImage.VideoRepresentation] = [], immediateThumbnailData: Data?, emojiMarkup: TelegramMediaImage.EmojiMarkup? = nil, reference: TelegramMediaImageReference?, partialReference: PartialMediaReference?, flags: TelegramMediaImageFlags, video: TelegramMediaFile? = nil) {
self.imageId = imageId
self.representations = representations
self.videoRepresentations = videoRepresentations
@ -296,6 +298,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
self.reference = reference
self.partialReference = partialReference
self.flags = flags
self.video = video
}
public init(decoder: PostboxDecoder) {
@ -307,6 +310,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
self.reference = decoder.decodeObjectForKey("rf", decoder: { TelegramMediaImageReference(decoder: $0) }) as? TelegramMediaImageReference
self.partialReference = decoder.decodeAnyObjectForKey("prf", decoder: { PartialMediaReference(decoder: $0) }) as? PartialMediaReference
self.flags = TelegramMediaImageFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0))
self.video = decoder.decodeObjectForKey("vid", decoder: { TelegramMediaFile(decoder: $0) }) as? TelegramMediaFile
}
public func encode(_ encoder: PostboxEncoder) {
@ -336,6 +340,11 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
encoder.encodeNil(forKey: "prf")
}
encoder.encodeInt32(self.flags.rawValue, forKey: "fl")
if let video = self.video {
encoder.encodeObject(video, forKey: "vid")
} else {
encoder.encodeNil(forKey: "vid")
}
}
public required init(from decoder: Decoder) throws {
@ -353,6 +362,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
self.reference = object.reference
self.partialReference = object.partialReference
self.flags = object.flags
self.video = object.video
}
public func encode(to encoder: Encoder) throws {
@ -376,6 +386,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
self.reference = try flatBuffersObject.reference.flatMap { try TelegramMediaImageReference(flatBuffersObject: $0) }
self.partialReference = try flatBuffersObject.partialReference.flatMap { try PartialMediaReference(flatBuffersObject: $0) }
self.flags = TelegramMediaImageFlags(rawValue: flatBuffersObject.flags)
self.video = try flatBuffersObject.video.flatMap { try TelegramMediaFile(flatBuffersObject: $0) }
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
@ -393,6 +404,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
let emojiMarkupOffset = self.emojiMarkup.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let referenceOffset = self.reference.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let partialReferenceOffset = self.partialReference.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let videoOffset = self.video.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let start = TelegramCore_TelegramMediaImage.startTelegramMediaImage(&builder)
@ -412,6 +424,9 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
TelegramCore_TelegramMediaImage.add(partialReference: partialReferenceOffset, &builder)
}
TelegramCore_TelegramMediaImage.add(flags: self.flags.rawValue, &builder)
if let videoOffset {
TelegramCore_TelegramMediaImage.add(video: videoOffset, &builder)
}
return TelegramCore_TelegramMediaImage.endTelegramMediaImage(&builder, start: start)
}
@ -466,6 +481,9 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
if other.flags != self.flags {
return false
}
if other.video != self.video {
return false
}
return true
}
return false
@ -494,6 +512,9 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
if self.flags != other.flags {
return false
}
if self.video != other.video {
return false
}
return true
}
return false
@ -504,7 +525,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
}
public func withUpdatedPartialReference(_ partialReference: PartialMediaReference?) -> TelegramMediaImage {
return TelegramMediaImage(imageId: self.imageId, representations: self.representations, videoRepresentations: self.videoRepresentations, immediateThumbnailData: self.immediateThumbnailData, reference: self.reference, partialReference: partialReference, flags: self.flags)
return TelegramMediaImage(imageId: self.imageId, representations: self.representations, videoRepresentations: self.videoRepresentations, immediateThumbnailData: self.immediateThumbnailData, reference: self.reference, partialReference: partialReference, flags: self.flags, video: self.video)
}
}

View file

@ -140,7 +140,7 @@ public extension TelegramEngine {
case let .inputFile(inputFile):
switch type {
case .photo:
inputMedia = .inputMediaUploadedPhoto(.init(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil))
inputMedia = .inputMediaUploadedPhoto(.init(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil, video: nil))
case .file, .video, .sticker, .voice:
var attributes: [Api.DocumentAttribute] = []
attributes.append(.documentAttributeFilename(.init(fileName: fileName)))

View file

@ -599,12 +599,12 @@ public extension TelegramEngine {
return EngineMessageReactionListContext(account: self.account, message: message, readStats: readStats, reaction: reaction)
}
public func translate(text: String, toLang: String, entities: [MessageTextEntity] = []) -> Signal<(String, [MessageTextEntity])?, TranslationError> {
return _internal_translate(network: self.account.network, text: text, toLang: toLang, entities: entities)
public func translate(text: String, toLang: String, entities: [MessageTextEntity] = [], tone: TranslationTone = .neutral) -> Signal<(String, [MessageTextEntity])?, TranslationError> {
return _internal_translate(network: self.account.network, text: text, toLang: toLang, entities: entities, tone: tone)
}
public func translate(texts: [(String, [MessageTextEntity])], toLang: String) -> Signal<[(String, [MessageTextEntity])], TranslationError> {
return _internal_translateTexts(network: self.account.network, texts: texts, toLang: toLang)
public func translate(texts: [(String, [MessageTextEntity])], toLang: String, tone: TranslationTone = .neutral) -> Signal<[(String, [MessageTextEntity])], TranslationError> {
return _internal_translateTexts(network: self.account.network, texts: texts, toLang: toLang, tone: tone)
}
public func translateMessages(messageIds: [EngineMessage.Id], fromLang: String?, toLang: String, enableLocalIfPossible: Bool) -> Signal<Never, TranslationError> {

View file

@ -14,11 +14,21 @@ public enum TranslationError {
case tryAlternative
}
func _internal_translate(network: Network, text: String, toLang: String, entities: [MessageTextEntity] = []) -> Signal<(String, [MessageTextEntity])?, TranslationError> {
public enum TranslationTone: String {
case neutral
case casual
case formal
}
func _internal_translate(network: Network, text: String, toLang: String, entities: [MessageTextEntity] = [], tone: TranslationTone = .neutral) -> Signal<(String, [MessageTextEntity])?, TranslationError> {
var flags: Int32 = 0
flags |= (1 << 1)
if tone != .neutral {
flags |= (1 << 2)
}
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: [.textWithEntities(.init(text: text, entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())))], toLang: toLang))
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: [.textWithEntities(.init(text: text, entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())))], toLang: toLang, tone: tone.rawValue))
|> mapError { error -> TranslationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
@ -50,16 +60,20 @@ func _internal_translate(network: Network, text: String, toLang: String, entitie
}
}
func _internal_translateTexts(network: Network, texts: [(String, [MessageTextEntity])], toLang: String) -> Signal<[(String, [MessageTextEntity])], TranslationError> {
func _internal_translateTexts(network: Network, texts: [(String, [MessageTextEntity])], toLang: String, tone: TranslationTone = .neutral) -> Signal<[(String, [MessageTextEntity])], TranslationError> {
var flags: Int32 = 0
flags |= (1 << 1)
if tone != .neutral {
flags |= (1 << 2)
}
var apiTexts: [Api.TextWithEntities] = []
for text in texts {
apiTexts.append(.textWithEntities(.init(text: text.0, entities: apiEntitiesFromMessageTextEntities(text.1, associatedPeers: SimpleDictionary()))))
}
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: apiTexts, toLang: toLang))
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: apiTexts, toLang: toLang, tone: tone.rawValue))
|> mapError { error -> TranslationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
@ -191,7 +205,7 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin
}
}
} else {
msgs = account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang))
msgs = account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang, tone: nil))
|> map(Optional.init)
|> mapError { error -> TranslationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {

View file

@ -189,7 +189,7 @@ func _internal_updateChannelAdminRights(account: Account, peerId: PeerId, adminI
if let _ = rank {
flags = (1 << 0)
}
return account.network.request(Api.functions.channels.editAdmin(flags: flags, channel: inputChannel, userId: inputUser, adminRights: rights?.apiAdminRights ?? .chatAdminRights(Api.ChatAdminRights.Cons_chatAdminRights(flags: 0)), rank: rank ?? ""))
return account.network.request(Api.functions.channels.editAdmin(flags: flags, channel: inputChannel, userId: inputUser, adminRights: rights?.apiAdminRights ?? .chatAdminRights(Api.ChatAdminRights.Cons_chatAdminRights(flags: 0)), rank: rank))
|> map { [$0] }
|> `catch` { error -> Signal<[Api.Updates], UpdateChannelAdminRightsError> in
if error.errorDescription == "USER_NOT_PARTICIPANT" {

View file

@ -548,7 +548,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
}
}
let photo: TelegramMediaImage? = chatFullChatPhoto.flatMap(telegramMediaImageFromApiPhoto)
let photo: TelegramMediaImage? = chatFullChatPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
let exportedInvitation = chatFullExportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) }
let pinnedMessageId = chatFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })

View file

@ -513,6 +513,8 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
actionTitle = hasEnded ? item.presentationData.strings.Chat_Auction_ViewResults : item.presentationData.strings.Chat_Auction_Join
actionIcon = !hasEnded ? .bid : nil
}
case "telegram_channel_direct":
actionTitle = item.presentationData.strings.Chat_ContactChannel
default:
break
}

View file

@ -539,12 +539,20 @@ final class PostSuggestionsSettingsScreenComponent: Component {
}
)
)))
let linkSectionSize = self.linkSection.update(
transition: transition,
component: AnyComponent(ListSectionComponent(
theme: environment.theme,
style: .glass,
header: nil,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: environment.strings.ChannelMessages_LinkTitle.uppercased(),
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor
)),
maximumNumberOfLines: 0
)),
footer: nil,
items: linkSectionItems
)),