mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-17 11:00:07 +00:00
no message
This commit is contained in:
parent
a129ca9595
commit
efe13e4130
@ -8,6 +8,9 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D003702B1DA42586004308D3 /* PhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003702A1DA42586004308D3 /* PhoneNumber.swift */; };
|
||||
D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */; };
|
||||
D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */; };
|
||||
D01AC9231DD5E9A200E8160F /* ApplyUpdateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */; };
|
||||
D021E0DF1DB539FC00C6B04F /* StickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0DE1DB539FC00C6B04F /* StickerPack.swift */; };
|
||||
D021E0E21DB5401A00C6B04F /* StickerManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0E11DB5401A00C6B04F /* StickerManagement.swift */; };
|
||||
D03121021DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */; };
|
||||
@ -212,6 +215,10 @@
|
||||
D0DF0C911D81A857008AEB01 /* ImageRepresentationsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */; };
|
||||
D0DF0C931D81AD09008AEB01 /* MessageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */; };
|
||||
D0DF0CA81D82BF32008AEB01 /* PeerParticipants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0CA71D82BF32008AEB01 /* PeerParticipants.swift */; };
|
||||
D0F7AB2C1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */; };
|
||||
D0F7AB2D1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */; };
|
||||
D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */; };
|
||||
D0F7AB301DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -226,6 +233,9 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D003702A1DA42586004308D3 /* PhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumber.swift; sourceTree = "<group>"; };
|
||||
D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestMessageActionCallback.swift; sourceTree = "<group>"; };
|
||||
D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestEditMessage.swift; sourceTree = "<group>"; };
|
||||
D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplyUpdateMessage.swift; sourceTree = "<group>"; };
|
||||
D021E0DE1DB539FC00C6B04F /* StickerPack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerPack.swift; sourceTree = "<group>"; };
|
||||
D021E0E11DB5401A00C6B04F /* StickerManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerManagement.swift; sourceTree = "<group>"; };
|
||||
D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramPeerNotificationSettings.swift; sourceTree = "<group>"; };
|
||||
@ -358,6 +368,8 @@
|
||||
D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageRepresentationsUtils.swift; sourceTree = "<group>"; };
|
||||
D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageUtils.swift; sourceTree = "<group>"; };
|
||||
D0DF0CA71D82BF32008AEB01 /* PeerParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerParticipants.swift; sourceTree = "<group>"; };
|
||||
D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditedMessageAttribute.swift; sourceTree = "<group>"; };
|
||||
D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyMarkupMessageAttribute.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -517,6 +529,8 @@
|
||||
D03B0CE11D62249B00955575 /* InlineBotMessageAttribute.swift */,
|
||||
D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */,
|
||||
D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */,
|
||||
D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */,
|
||||
D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */,
|
||||
);
|
||||
name = Attributes;
|
||||
sourceTree = "<group>";
|
||||
@ -549,6 +563,7 @@
|
||||
D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */,
|
||||
D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */,
|
||||
D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */,
|
||||
D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */,
|
||||
);
|
||||
name = State;
|
||||
sourceTree = "<group>";
|
||||
@ -613,6 +628,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D03B0D711D631ABA00955575 /* SearchMessages.swift */,
|
||||
D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */,
|
||||
D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */,
|
||||
);
|
||||
name = Messages;
|
||||
sourceTree = "<group>";
|
||||
@ -902,6 +919,7 @@
|
||||
D0B843B91DA7FF30005F29E1 /* NBMetadataCoreTest.m in Sources */,
|
||||
D09A2FE61D7CD4940018FB72 /* TelegramChannel.swift in Sources */,
|
||||
D03B0D0E1D62255C00955575 /* UpdateGroup.swift in Sources */,
|
||||
D01AC9231DD5E9A200E8160F /* ApplyUpdateMessage.swift in Sources */,
|
||||
D03B0CF71D62250800955575 /* TelegramMediaImage.swift in Sources */,
|
||||
D073CE601DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift in Sources */,
|
||||
D03B0D6B1D631A9D00955575 /* Phonebook.swift in Sources */,
|
||||
@ -911,6 +929,8 @@
|
||||
D0DF0CA81D82BF32008AEB01 /* PeerParticipants.swift in Sources */,
|
||||
D03B0D5F1D631A6900955575 /* Serialization.swift in Sources */,
|
||||
D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */,
|
||||
D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */,
|
||||
D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */,
|
||||
D09BB6B61DB0428000A905C0 /* PendingMessageUploadedContent.swift in Sources */,
|
||||
D0B843B71DA7FF30005F29E1 /* NBMetadataCoreMapper.m in Sources */,
|
||||
D0AB0B921D65E9FA002C78E7 /* ManagedServiceViews.swift in Sources */,
|
||||
@ -936,6 +956,7 @@
|
||||
D03B0D671D631A8B00955575 /* AccountViewTracker.swift in Sources */,
|
||||
D0B843BB1DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m in Sources */,
|
||||
D03B0D101D62255C00955575 /* UpdatesApiUtils.swift in Sources */,
|
||||
D0F7AB2C1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */,
|
||||
D03B0CBF1D62234A00955575 /* Log.swift in Sources */,
|
||||
D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */,
|
||||
D03B0CD61D62245300955575 /* TelegramUser.swift in Sources */,
|
||||
@ -943,6 +964,7 @@
|
||||
D03B0CE41D62249F00955575 /* TextEntitiesMessageAttribute.swift in Sources */,
|
||||
D03B0CD31D62244300955575 /* Namespaces.swift in Sources */,
|
||||
D0DF0C8A1D819C7E008AEB01 /* JoinChannel.swift in Sources */,
|
||||
D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */,
|
||||
D0B843971DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift in Sources */,
|
||||
D09BB6B41DB02C2B00A905C0 /* PendingMessageManager.swift in Sources */,
|
||||
D0B843851DA6EDC4005F29E1 /* CachedChannelData.swift in Sources */,
|
||||
@ -1040,6 +1062,7 @@
|
||||
D0B418B91D7E05AD004562A4 /* SearchMessages.swift in Sources */,
|
||||
D0B8443F1DAB91EF005F29E1 /* UpdateGroup.swift in Sources */,
|
||||
D03C53731DAD5CA9004C17B3 /* CachedGroupData.swift in Sources */,
|
||||
D0F7AB2D1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */,
|
||||
D0B844121DAB91CD005F29E1 /* Log.swift in Sources */,
|
||||
D0B8444D1DAB9206005F29E1 /* JoinChannel.swift in Sources */,
|
||||
D03C53721DAD5CA9004C17B3 /* CachedUserData.swift in Sources */,
|
||||
@ -1047,6 +1070,7 @@
|
||||
D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */,
|
||||
D073CE6C1DCBCF17007511FD /* TextEntitiesMessageAttribute.swift in Sources */,
|
||||
D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */,
|
||||
D0F7AB301DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */,
|
||||
D073CE6D1DCBCF17007511FD /* InlineBotMessageAttribute.swift in Sources */,
|
||||
D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */,
|
||||
D03C536E1DAD5CA9004C17B3 /* PhoneNumber.swift in Sources */,
|
||||
@ -1175,7 +1199,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 3.0.1;
|
||||
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include";
|
||||
};
|
||||
name = Hockeyapp;
|
||||
@ -1318,7 +1342,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 3.0.1;
|
||||
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include";
|
||||
};
|
||||
name = Debug;
|
||||
@ -1352,7 +1376,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 3.0.1;
|
||||
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include";
|
||||
};
|
||||
name = Release;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "0820"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "0820"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -240,6 +240,8 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(LocalFileReferenceMediaResource.self, f: { LocalFileReferenceMediaResource(decoder: $0) })
|
||||
declareEncodable(OutgoingMessageInfoAttribute.self, f: { OutgoingMessageInfoAttribute(decoder: $0) })
|
||||
declareEncodable(ForwardSourceInfoAttribute.self, f: { ForwardSourceInfoAttribute(decoder: $0) })
|
||||
declareEncodable(EditedMessageAttribute.self, f: { EditedMessageAttribute(decoder: $0) })
|
||||
declareEncodable(ReplyMarkupMessageAttribute.self, f: { ReplyMarkupMessageAttribute(decoder: $0) })
|
||||
return
|
||||
}()
|
||||
|
||||
@ -359,7 +361,7 @@ public class Account {
|
||||
public let graphicsThreadPool = ThreadPool(threadCount: 3, threadPriority: 0.1)
|
||||
//let imageCache: ImageCache = ImageCache(maxResidentSize: 5 * 1024 * 1024)
|
||||
|
||||
public var applicationSpecificData: Any?
|
||||
public var applicationContext: Any?
|
||||
|
||||
public let settings: AccountSettings = defaultAccountSettings()
|
||||
|
||||
@ -518,4 +520,10 @@ public func setupAccount(_ account: Account, fetchCachedResourceRepresentation:
|
||||
|
||||
account.managedContactsDisposable.set(manageContacts(network: account.network, postbox: account.postbox).start())
|
||||
account.managedStickerPacksDisposable.set(manageStickerPacks(network: account.network, postbox: account.postbox).start())
|
||||
|
||||
/*account.network.request(Api.functions.help.getScheme(version: 0)).start(next: { result in
|
||||
if case let .scheme(text, _, _, _) = result {
|
||||
print("\(text)")
|
||||
}
|
||||
})*/
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
101
TelegramCore/ApplyUpdateMessage.swift
Normal file
101
TelegramCore/ApplyUpdateMessage.swift
Normal file
@ -0,0 +1,101 @@
|
||||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
import SwiftSignalKitMac
|
||||
#else
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
#endif
|
||||
|
||||
private func applyMediaResourceChanges(from: Media, to: Media, postbox: Postbox) {
|
||||
if let fromImage = from as? TelegramMediaImage, let toImage = to as? TelegramMediaImage {
|
||||
if let fromLargestRepresentation = largestImageRepresentation(fromImage.representations), let toLargestRepresentation = largestImageRepresentation(toImage.representations) {
|
||||
postbox.mediaBox.moveResourceData(from: fromLargestRepresentation.resource.id, to: toLargestRepresentation.resource.id)
|
||||
}
|
||||
} else if let fromFile = from as? TelegramMediaFile, let toFile = to as? TelegramMediaFile {
|
||||
postbox.mediaBox.moveResourceData(from: fromFile.resource.id, to: toFile.resource.id)
|
||||
}
|
||||
}
|
||||
|
||||
func applyUpdateMessage(postbox: Postbox, stateManager: StateManager, message: Message, result: Api.Updates) -> Signal<Void, NoError> {
|
||||
let messageId = result.rawMessageIds.first
|
||||
let apiMessage = result.messages.first
|
||||
|
||||
return postbox.modify { modifier -> Void in
|
||||
var updatedTimestamp: Int32?
|
||||
if let apiMessage = apiMessage {
|
||||
switch apiMessage {
|
||||
case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _):
|
||||
updatedTimestamp = date
|
||||
case .messageEmpty:
|
||||
break
|
||||
case let .messageService(_, _, _, _, _, date, _):
|
||||
updatedTimestamp = date
|
||||
}
|
||||
} else {
|
||||
switch result {
|
||||
case let .updateShortSentMessage(_, _, _, _, date, _, _):
|
||||
updatedTimestamp = date
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
modifier.updateMessage(message.id, update: { currentMessage in
|
||||
let updatedId: MessageId
|
||||
if let messageId = messageId {
|
||||
updatedId = MessageId(peerId: currentMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: messageId)
|
||||
} else {
|
||||
updatedId = currentMessage.id
|
||||
}
|
||||
|
||||
let media: [Media]
|
||||
let attributes: [MessageAttribute]
|
||||
let text: String
|
||||
if let apiMessage = apiMessage, let updatedMessage = StoreMessage(apiMessage: apiMessage) {
|
||||
media = updatedMessage.media
|
||||
attributes = updatedMessage.attributes
|
||||
text = updatedMessage.text
|
||||
} else if case let .updateShortSentMessage(_, _, _, _, _, apiMedia, entities) = result {
|
||||
let (_, mediaValue) = textAndMediaFromApiMedia(apiMedia)
|
||||
if let mediaValue = mediaValue {
|
||||
media = [mediaValue]
|
||||
} else {
|
||||
media = []
|
||||
}
|
||||
|
||||
var updatedAttributes: [MessageAttribute] = currentMessage.attributes
|
||||
if let entities = entities, !entities.isEmpty {
|
||||
for i in 0 ..< updatedAttributes.count {
|
||||
if updatedAttributes[i] is TextEntitiesMessageAttribute {
|
||||
updatedAttributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
updatedAttributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)))
|
||||
}
|
||||
attributes = updatedAttributes
|
||||
text = currentMessage.text
|
||||
} else {
|
||||
media = currentMessage.media
|
||||
attributes = currentMessage.attributes
|
||||
text = currentMessage.text
|
||||
}
|
||||
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date)
|
||||
}
|
||||
|
||||
if let fromMedia = currentMessage.media.first, let toMedia = media.first {
|
||||
applyMediaResourceChanges(from: fromMedia, to: toMedia, postbox: postbox)
|
||||
}
|
||||
|
||||
return StoreMessage(id: updatedId, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: currentMessage.tags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)
|
||||
})
|
||||
if let updatedTimestamp = updatedTimestamp {
|
||||
modifier.offsetPendingMessagesTimestamps(lowerBound: message.id, timestamp: updatedTimestamp)
|
||||
}
|
||||
stateManager.addUpdates(result)
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
extension CachedUserData {
|
||||
convenience init(apiUserFull: Api.UserFull) {
|
||||
switch apiUserFull {
|
||||
case let .userFull(_, _, about, _, _, _, apiBotInfo):
|
||||
case let .userFull(_, _, about, _, _, _, apiBotInfo, commonChatsCount):
|
||||
let botInfo: BotInfo?
|
||||
if let apiBotInfo = apiBotInfo {
|
||||
botInfo = BotInfo(apiBotInfo: apiBotInfo)
|
||||
|
@ -139,7 +139,7 @@ public class CloudDocumentMediaResource: TelegramCloudMediaResource {
|
||||
}
|
||||
|
||||
var apiInputLocation: Api.InputFileLocation {
|
||||
return Api.InputFileLocation.inputDocumentFileLocation(id: self.fileId, accessHash: self.accessHash)
|
||||
return Api.InputFileLocation.inputDocumentFileLocation(id: self.fileId, accessHash: self.accessHash, version: 0)
|
||||
}
|
||||
|
||||
public init(datacenterId: Int, fileId: Int64, accessHash: Int64, size: Int) {
|
||||
|
22
TelegramCore/EditedMessageAttribute.swift
Normal file
22
TelegramCore/EditedMessageAttribute.swift
Normal file
@ -0,0 +1,22 @@
|
||||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
#else
|
||||
import Postbox
|
||||
#endif
|
||||
|
||||
public class EditedMessageAttribute: MessageAttribute {
|
||||
public let date: Int32
|
||||
|
||||
init(date: Int32) {
|
||||
self.date = date
|
||||
}
|
||||
|
||||
required public init(decoder: Decoder) {
|
||||
self.date = decoder.decodeInt32ForKey("d")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: Encoder) {
|
||||
encoder.encodeInt32(self.date, forKey: "d")
|
||||
}
|
||||
}
|
@ -44,16 +44,6 @@ private final class PendingMessageRequestDependencyTag: NetworkRequestDependency
|
||||
}
|
||||
}
|
||||
|
||||
private func applyMediaResourceChanges(from: Media, to: Media, postbox: Postbox) {
|
||||
if let fromImage = from as? TelegramMediaImage, let toImage = to as? TelegramMediaImage {
|
||||
if let fromLargestRepresentation = largestImageRepresentation(fromImage.representations), let toLargestRepresentation = largestImageRepresentation(toImage.representations) {
|
||||
postbox.mediaBox.moveResourceData(from: fromLargestRepresentation.resource.id, to: toLargestRepresentation.resource.id)
|
||||
}
|
||||
} else if let fromFile = from as? TelegramMediaFile, let toFile = to as? TelegramMediaFile {
|
||||
postbox.mediaBox.moveResourceData(from: fromFile.resource.id, to: toFile.resource.id)
|
||||
}
|
||||
}
|
||||
|
||||
public final class PendingMessageManager {
|
||||
private let network: Network
|
||||
private let postbox: Postbox
|
||||
@ -259,7 +249,7 @@ public final class PendingMessageManager {
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: nil), tag: dependencyTag)
|
||||
|> mapError { _ -> NoError in
|
||||
return NoError()
|
||||
}
|
||||
}
|
||||
case let .media(inputMedia):
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: 0, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, randomId: uniqueId, replyMarkup: nil), tag: dependencyTag)
|
||||
|> mapError { _ -> NoError in
|
||||
@ -307,83 +297,7 @@ public final class PendingMessageManager {
|
||||
let messageId = result.rawMessageIds.first
|
||||
let apiMessage = result.messages.first
|
||||
|
||||
return postbox.modify { modifier -> Void in
|
||||
var updatedTimestamp: Int32?
|
||||
if let apiMessage = apiMessage {
|
||||
switch apiMessage {
|
||||
case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _):
|
||||
updatedTimestamp = date
|
||||
case .messageEmpty:
|
||||
break
|
||||
case let .messageService(_, _, _, _, _, date, _):
|
||||
updatedTimestamp = date
|
||||
}
|
||||
} else {
|
||||
switch result {
|
||||
case let .updateShortSentMessage(_, _, _, _, date, _, _):
|
||||
updatedTimestamp = date
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
modifier.updateMessage(message.id, update: { currentMessage in
|
||||
let updatedId: MessageId
|
||||
if let messageId = messageId {
|
||||
updatedId = MessageId(peerId: currentMessage.id.peerId, namespace: Namespaces.Message.Cloud, id: messageId)
|
||||
} else {
|
||||
updatedId = currentMessage.id
|
||||
}
|
||||
|
||||
let media: [Media]
|
||||
let attributes: [MessageAttribute]
|
||||
let text: String
|
||||
if let apiMessage = apiMessage, let updatedMessage = StoreMessage(apiMessage: apiMessage) {
|
||||
media = updatedMessage.media
|
||||
attributes = updatedMessage.attributes
|
||||
text = updatedMessage.text
|
||||
} else if case let .updateShortSentMessage(_, _, _, _, _, apiMedia, entities) = result {
|
||||
let (_, mediaValue) = textAndMediaFromApiMedia(apiMedia)
|
||||
if let mediaValue = mediaValue {
|
||||
media = [mediaValue]
|
||||
} else {
|
||||
media = []
|
||||
}
|
||||
|
||||
var updatedAttributes: [MessageAttribute] = currentMessage.attributes
|
||||
if let entities = entities, !entities.isEmpty {
|
||||
for i in 0 ..< updatedAttributes.count {
|
||||
if updatedAttributes[i] is TextEntitiesMessageAttribute {
|
||||
updatedAttributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
updatedAttributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)))
|
||||
}
|
||||
attributes = updatedAttributes
|
||||
text = currentMessage.text
|
||||
} else {
|
||||
media = currentMessage.media
|
||||
attributes = currentMessage.attributes
|
||||
text = currentMessage.text
|
||||
}
|
||||
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date)
|
||||
}
|
||||
|
||||
if let fromMedia = currentMessage.media.first, let toMedia = media.first {
|
||||
applyMediaResourceChanges(from: fromMedia, to: toMedia, postbox: postbox)
|
||||
}
|
||||
|
||||
return StoreMessage(id: updatedId, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: currentMessage.tags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)
|
||||
})
|
||||
if let updatedTimestamp = updatedTimestamp {
|
||||
modifier.offsetPendingMessagesTimestamps(lowerBound: message.id, timestamp: updatedTimestamp)
|
||||
}
|
||||
} |> afterDisposed { [weak self] in
|
||||
stateManager.addUpdates(result)
|
||||
return applyUpdateMessage(postbox: postbox, stateManager: stateManager, message: message, result: result) |> afterDisposed { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.queue.async {
|
||||
if let context = strongSelf.peerSummaryContexts[message.id.peerId] {
|
||||
|
@ -56,7 +56,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, image
|
||||
case let .progress(progress):
|
||||
return .progress(progress)
|
||||
case let .inputFile(file):
|
||||
return .content(message, .media(Api.InputMedia.inputMediaUploadedPhoto(file: file, caption: message.text)))
|
||||
return .content(message, .media(Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: file, caption: message.text, stickers: nil)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -75,7 +75,9 @@ private func inputDocumentAttributesFromFile(_ file: TelegramMediaFile) -> [Api.
|
||||
case let .ImageSize(size):
|
||||
attributes.append(.documentAttributeImageSize(w: Int32(size.width), h: Int32(size.height)))
|
||||
case let .Sticker(displayText):
|
||||
attributes.append(.documentAttributeSticker(alt: displayText, stickerset: .inputStickerSetEmpty))
|
||||
attributes.append(.documentAttributeSticker(flags: 0, alt: displayText, stickerset: .inputStickerSetEmpty, maskCoords: nil))
|
||||
case .HasLinkedStickers:
|
||||
attributes.append(.documentAttributeHasStickers)
|
||||
case let .Video(duration, size):
|
||||
attributes.append(.documentAttributeVideo(duration: Int32(duration), w: Int32(size.width), h: Int32(size.height)))
|
||||
case let .Audio(isVoice, duration, title, performer, waveform):
|
||||
@ -95,9 +97,6 @@ private func inputDocumentAttributesFromFile(_ file: TelegramMediaFile) -> [Api.
|
||||
waveformBuffer = Buffer(data: waveform.makeData())
|
||||
}
|
||||
attributes.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer))
|
||||
break
|
||||
case .Unknown:
|
||||
break
|
||||
}
|
||||
}
|
||||
return attributes
|
||||
@ -110,7 +109,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, file:
|
||||
case let .progress(progress):
|
||||
return .progress(progress)
|
||||
case let .inputFile(inputFile):
|
||||
return .content(message, .media(Api.InputMedia.inputMediaUploadedDocument(file: inputFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFile(file), caption: message.text)))
|
||||
return .content(message, .media(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFile(file), caption: message.text, stickers: nil)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
220
TelegramCore/ReplyMarkupMessageAttribute.swift
Normal file
220
TelegramCore/ReplyMarkupMessageAttribute.swift
Normal file
@ -0,0 +1,220 @@
|
||||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
#else
|
||||
import Postbox
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
keyboardButton#a2fa4880 text:string = KeyboardButton;
|
||||
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
|
||||
keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
|
||||
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
|
||||
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
|
||||
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
|
||||
keyboardButtonGame#50f41ccf text:string = KeyboardButton;
|
||||
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
|
||||
replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
|
||||
replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup;
|
||||
replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup;
|
||||
|
||||
*/
|
||||
|
||||
public enum ReplyMarkupButtonAction: Coding {
|
||||
case text
|
||||
case url(String)
|
||||
case callback(MemoryBuffer)
|
||||
case requestPhone
|
||||
case requestMap
|
||||
case switchInline(samePeer: Bool, query: String)
|
||||
case openWebApp
|
||||
|
||||
public init(decoder: Decoder) {
|
||||
switch decoder.decodeInt32ForKey("v") as Int32 {
|
||||
case 0:
|
||||
self = .text
|
||||
case 1:
|
||||
self = .url(decoder.decodeStringForKey("u"))
|
||||
case 2:
|
||||
self = .callback(decoder.decodeBytesForKey("d") ?? MemoryBuffer())
|
||||
case 3:
|
||||
self = .requestPhone
|
||||
case 4:
|
||||
self = .requestMap
|
||||
case 5:
|
||||
self = .switchInline(samePeer: decoder.decodeInt32ForKey("s") != 0, query: decoder.decodeStringForKey("q"))
|
||||
case 6:
|
||||
self = .openWebApp
|
||||
default:
|
||||
self = .text
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: Encoder) {
|
||||
switch self {
|
||||
case .text:
|
||||
encoder.encodeInt32(0, forKey: "v")
|
||||
case let .url(url):
|
||||
encoder.encodeInt32(1, forKey: "v")
|
||||
encoder.encodeString(url, forKey: "u")
|
||||
case let .callback(data):
|
||||
encoder.encodeInt32(2, forKey: "v")
|
||||
encoder.encodeBytes(data, forKey: "d")
|
||||
case .requestPhone:
|
||||
encoder.encodeInt32(3, forKey: "v")
|
||||
case .requestMap:
|
||||
encoder.encodeInt32(4, forKey: "v")
|
||||
case let .switchInline(samePeer, query):
|
||||
encoder.encodeInt32(5, forKey: "v")
|
||||
encoder.encodeInt32(samePeer ? 1 : 0, forKey: "s")
|
||||
case .openWebApp:
|
||||
encoder.encodeInt32(6, forKey: "v")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReplyMarkupButton: Coding {
|
||||
public let title: String
|
||||
public let action: ReplyMarkupButtonAction
|
||||
|
||||
init(title: String, action: ReplyMarkupButtonAction) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
}
|
||||
|
||||
public init(decoder: Decoder) {
|
||||
self.title = decoder.decodeStringForKey(".t")
|
||||
self.action = ReplyMarkupButtonAction(decoder: decoder)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: Encoder) {
|
||||
encoder.encodeString(self.title, forKey: ".t")
|
||||
self.action.encode(encoder)
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReplyMarkupRow: Coding {
|
||||
public let buttons: [ReplyMarkupButton]
|
||||
|
||||
init(buttons: [ReplyMarkupButton]) {
|
||||
self.buttons = buttons
|
||||
}
|
||||
|
||||
public init(decoder: Decoder) {
|
||||
self.buttons = decoder.decodeObjectArrayWithDecoderForKey("b")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: Encoder) {
|
||||
encoder.encodeObjectArray(self.buttons, forKey: "b")
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReplyMarkupMessageFlags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public init() {
|
||||
self.rawValue = 0
|
||||
}
|
||||
|
||||
public static let once = ReplyMarkupMessageFlags(rawValue: 1 << 0)
|
||||
public static let personal = ReplyMarkupMessageFlags(rawValue: 1 << 1)
|
||||
public static let setupReply = ReplyMarkupMessageFlags(rawValue: 1 << 2)
|
||||
public static let inline = ReplyMarkupMessageFlags(rawValue: 1 << 3)
|
||||
}
|
||||
|
||||
public class ReplyMarkupMessageAttribute: MessageAttribute {
|
||||
public let rows: [ReplyMarkupRow]
|
||||
public let flags: ReplyMarkupMessageFlags
|
||||
|
||||
init(rows: [ReplyMarkupRow], flags: ReplyMarkupMessageFlags) {
|
||||
self.rows = rows
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
public required init(decoder: Decoder) {
|
||||
self.rows = decoder.decodeObjectArrayWithDecoderForKey("r")
|
||||
self.flags = ReplyMarkupMessageFlags(rawValue: decoder.decodeInt32ForKey("f"))
|
||||
}
|
||||
|
||||
public func encode(_ encoder: Encoder) {
|
||||
encoder.encodeObjectArray(self.rows, forKey: "r")
|
||||
encoder.encodeInt32(self.flags.rawValue, forKey: "f")
|
||||
}
|
||||
}
|
||||
|
||||
extension ReplyMarkupButton {
|
||||
init(apiButton: Api.KeyboardButton) {
|
||||
switch apiButton {
|
||||
case let .keyboardButton(text):
|
||||
self.init(title: text, action: .text)
|
||||
case let .keyboardButtonCallback(text, data):
|
||||
let memory = malloc(data.size)!
|
||||
memcpy(memory, data.data, data.size)
|
||||
let dataBuffer = MemoryBuffer(memory: memory, capacity: data.size, length: data.size, freeWhenDone: true)
|
||||
self.init(title: text, action: .callback(dataBuffer))
|
||||
case let .keyboardButtonRequestGeoLocation(text):
|
||||
self.init(title: text, action: .requestMap)
|
||||
case let .keyboardButtonRequestPhone(text):
|
||||
self.init(title: text, action: .requestPhone)
|
||||
case let .keyboardButtonSwitchInline(flags, text, query):
|
||||
self.init(title: text, action: .switchInline(samePeer: (flags & (1 << 0)) != 0, query: query))
|
||||
case let .keyboardButtonUrl(text, url):
|
||||
self.init(title: text, action: .url(url))
|
||||
case let .keyboardButtonGame(text):
|
||||
self.init(title: text, action: .openWebApp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ReplyMarkupRow {
|
||||
init(apiRow: Api.KeyboardButtonRow) {
|
||||
switch apiRow {
|
||||
case let .keyboardButtonRow(buttons):
|
||||
self.init(buttons: buttons.map { ReplyMarkupButton(apiButton: $0) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ReplyMarkupMessageAttribute {
|
||||
convenience init(apiMarkup: Api.ReplyMarkup) {
|
||||
var rows: [ReplyMarkupRow] = []
|
||||
var flags = ReplyMarkupMessageFlags()
|
||||
switch apiMarkup {
|
||||
case let .replyKeyboardMarkup(markupFlags, apiRows):
|
||||
rows = apiRows.map { ReplyMarkupRow(apiRow: $0) }
|
||||
if (markupFlags & (1 << 1)) != 0 {
|
||||
flags.insert(.once)
|
||||
}
|
||||
if (markupFlags & (1 << 2)) != 0 {
|
||||
flags.insert(.personal)
|
||||
}
|
||||
case let .replyInlineMarkup(apiRows):
|
||||
rows = apiRows.map { ReplyMarkupRow(apiRow: $0) }
|
||||
flags.insert(.inline)
|
||||
case let .replyKeyboardForceReply(forceReplyFlags):
|
||||
if (forceReplyFlags & (1 << 1)) != 0 {
|
||||
flags.insert(.once)
|
||||
}
|
||||
if (forceReplyFlags & (1 << 2)) != 0 {
|
||||
flags.insert(.personal)
|
||||
}
|
||||
case let .replyKeyboardHide(hideFlags):
|
||||
if (hideFlags & (1 << 2)) != 0 {
|
||||
flags.insert(.personal)
|
||||
}
|
||||
}
|
||||
self.init(rows: rows, flags: flags)
|
||||
}
|
||||
}
|
43
TelegramCore/RequestEditMessage.swift
Normal file
43
TelegramCore/RequestEditMessage.swift
Normal file
@ -0,0 +1,43 @@
|
||||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
import SwiftSignalKitMac
|
||||
import MtProtoKitMac
|
||||
#else
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import MtProtoKitDynamic
|
||||
#endif
|
||||
|
||||
public func requestEditMessage(account: Account, messageId: MessageId, text: String) -> Signal<Bool, NoError> {
|
||||
return account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> mapToSignal { peer in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.editMessage(flags: (1 << 11), peer: inputPeer, id: messageId.id, message: text, replyMarkup: nil, entities: nil))
|
||||
|> map { result -> Api.Updates? in
|
||||
return result
|
||||
}
|
||||
|> `catch` { error -> Signal<Api.Updates?, MTRpcError> in
|
||||
if error.errorDescription == "MESSAGE_NOT_MODIFIED" {
|
||||
return .single(nil)
|
||||
} else {
|
||||
return .fail(error)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> NoError in
|
||||
return NoError()
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||
if let result = result {
|
||||
return .single(true)
|
||||
account.stateManager.addUpdates(result)
|
||||
} else {
|
||||
return .single(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(false)
|
||||
}
|
||||
}
|
||||
}
|
32
TelegramCore/RequestMessageActionCallback.swift
Normal file
32
TelegramCore/RequestMessageActionCallback.swift
Normal file
@ -0,0 +1,32 @@
|
||||
import Foundation
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
import SwiftSignalKitMac
|
||||
import MtProtoKitMac
|
||||
#else
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import MtProtoKitDynamic
|
||||
#endif
|
||||
|
||||
public func requestMessageActionCallback(account: Account, messageId: MessageId, data: MemoryBuffer?) -> Signal<Void, NoError> {
|
||||
return account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> mapToSignal { peer in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
var flags: Int32 = 0
|
||||
var dataBuffer: Buffer?
|
||||
if let data = data {
|
||||
flags != Int32(1 << 0)
|
||||
dataBuffer = Buffer(data: data.makeData())
|
||||
}
|
||||
return account.network.request(Api.functions.messages.getBotCallbackAnswer(flags: flags, peer: inputPeer, msgId: messageId.id, data: dataBuffer))
|
||||
|> retryRequest
|
||||
|> map { result in
|
||||
return Void()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ private func locallyRenderedMessage(message: StoreMessage, peers: [PeerId: Peer]
|
||||
messagePeers[peer.id] = peer
|
||||
}
|
||||
|
||||
return Message(stableId: 0, id: id, timestamp: message.timestamp, flags: MessageFlags(message.flags), tags: message.tags, forwardInfo: nil, author: author, text: message.text, attributes: message.attributes, media: message.media, peers: messagePeers, associatedMessages: SimpleDictionary())
|
||||
return Message(stableId: 0, stableVersion: 0, id: id, timestamp: message.timestamp, flags: MessageFlags(message.flags), tags: message.tags, forwardInfo: nil, author: author, text: message.text, attributes: message.attributes, media: message.media, peers: messagePeers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
}
|
||||
|
||||
public func searchMessages(account: Account, query: String) -> Signal<[Message], NoError> {
|
||||
|
@ -15,7 +15,7 @@ private func uploadedMessageMedia(network: Network, postbox: Postbox, media: Med
|
||||
|> mapToSignal { result -> Signal<Api.InputMedia?, NoError> in
|
||||
switch result {
|
||||
case let .inputFile(file):
|
||||
return .single(Api.InputMedia.inputMediaUploadedPhoto(file: file, caption: ""))
|
||||
return .single(Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: file, caption: "", stickers: nil))
|
||||
default:
|
||||
return .complete()
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 53
|
||||
return 60
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
@ -56,7 +56,8 @@ public class Serialization: NSObject, MTSerialization {
|
||||
return { response -> MTDatacenterAddressListData! in
|
||||
if let config = parse(Buffer(data: response)) {
|
||||
switch config {
|
||||
case let .config(_, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
//config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int phonecalls_enabled:flags.1?true disabled_features:Vector<DisabledFeature> = Config;
|
||||
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
var addressList = [MTDatacenterAddress]()
|
||||
for option in dcOptions {
|
||||
switch option {
|
||||
|
@ -37,6 +37,7 @@ private enum MutationOperation {
|
||||
case AddMessages([StoreMessage], AddMessagesLocation)
|
||||
case DeleteMessagesWithGlobalIds([Int32])
|
||||
case DeleteMessages([MessageId])
|
||||
case EditMessage(MessageId, StoreMessage)
|
||||
case UpdateMedia(MediaId, Media?)
|
||||
case ReadInbox(MessageId)
|
||||
case ReadOutbox(MessageId)
|
||||
@ -111,6 +112,10 @@ private struct MutableState {
|
||||
self.addOperation(.DeleteMessages(messageIds))
|
||||
}
|
||||
|
||||
mutating func editMessage(_ id: MessageId, message: StoreMessage) {
|
||||
self.addOperation(.EditMessage(id, message))
|
||||
}
|
||||
|
||||
mutating func updateMedia(_ id: MediaId, media: Media?) {
|
||||
self.addOperation(.UpdateMedia(id, media))
|
||||
}
|
||||
@ -177,7 +182,7 @@ private struct MutableState {
|
||||
|
||||
mutating func addOperation(_ operation: MutationOperation) {
|
||||
switch operation {
|
||||
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .UpdateMedia, .ReadInbox, .ReadOutbox, .ResetReadState, .MergePeerPresences:
|
||||
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadInbox, .ReadOutbox, .ResetReadState, .MergePeerPresences:
|
||||
break
|
||||
case let .AddMessages(messages, _):
|
||||
for message in messages {
|
||||
@ -297,6 +302,9 @@ private func peerIdsFromDifference(_ difference: Api.updates.Difference) -> Set<
|
||||
peerIds.insert(peerId)
|
||||
}
|
||||
}
|
||||
case let .differenceTooLong(pts):
|
||||
assertionFailure()
|
||||
break
|
||||
}
|
||||
|
||||
return peerIds
|
||||
@ -339,6 +347,8 @@ private func associatedMessageIdsFromDifference(_ difference: Api.updates.Differ
|
||||
}
|
||||
}
|
||||
}
|
||||
case .differenceTooLong:
|
||||
break
|
||||
}
|
||||
|
||||
return messageIds
|
||||
@ -373,6 +383,8 @@ private func peersWithNewMessagesFromDifference(_ difference: Api.updates.Differ
|
||||
peerIds.insert(messageId.peerId)
|
||||
}
|
||||
}
|
||||
case .differenceTooLong:
|
||||
break
|
||||
}
|
||||
|
||||
return peerIds
|
||||
@ -572,6 +584,9 @@ private func finalStateWithDifference(account: Account, state: MutableState, dif
|
||||
case let .state(pts, qts, date, seq, _):
|
||||
updatedState.updateState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq))
|
||||
}
|
||||
case .differenceTooLong:
|
||||
assertionFailure()
|
||||
break
|
||||
}
|
||||
|
||||
updatedState.mergeChats(chats)
|
||||
@ -693,8 +708,37 @@ private func finalStateWithUpdates(account: Account, state: MutableState, update
|
||||
channelsToPoll.insert(peerId)
|
||||
}
|
||||
}
|
||||
case let .updateEditChannelMessage(apiMessage, pts, ptsCount):
|
||||
if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id {
|
||||
let peerId = messageId.peerId
|
||||
if let previousState = updatedState.channelStates[peerId] {
|
||||
if previousState.pts >= pts {
|
||||
//trace("State", what: "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) skip old delete update")
|
||||
} else if previousState.pts + ptsCount == pts {
|
||||
updatedState.editMessage(messageId, message: message)
|
||||
updatedState.updateChannelState(peerId, state: previousState.setPts(pts))
|
||||
} else {
|
||||
if !channelsToPoll.contains(peerId) {
|
||||
trace("State", what: "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) delete pts hole")
|
||||
channelsToPoll.insert(peerId)
|
||||
//updatedMissingUpdates = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !channelsToPoll.contains(peerId) {
|
||||
//trace("State", what: "channel \(peerId) (\((updatedState.peers[peerId] as? TelegramChannel)?.title ?? "nil")) state unknown")
|
||||
channelsToPoll.insert(peerId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace("State", what: "Invalid updateEditChannelMessage")
|
||||
}
|
||||
case let .updateDeleteMessages(messages, _, _):
|
||||
updatedState.deleteMessagesWithGlobalIds(messages)
|
||||
case let .updateEditMessage(apiMessage, _, _):
|
||||
if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id {
|
||||
updatedState.editMessage(messageId, message: message)
|
||||
}
|
||||
case let .updateNewChannelMessage(message, pts, ptsCount):
|
||||
if let message = StoreMessage(apiMessage: message) {
|
||||
if let previousState = updatedState.channelStates[message.id.peerId] {
|
||||
@ -928,7 +972,7 @@ private func resolveMissingPeerNotificationSettings(account: Account, state: Mut
|
||||
|
||||
private func pollChannel(_ account: Account, peer: Peer, state: MutableState) -> Signal<MutableState, NoError> {
|
||||
if let inputChannel = apiInputChannel(peer) {
|
||||
return account.network.request(Api.functions.updates.getChannelDifference(channel: inputChannel, filter: .channelMessagesFilterEmpty, pts: state.channelStates[peer.id]?.pts ?? 1, limit: 20))
|
||||
return account.network.request(Api.functions.updates.getChannelDifference(flags: 0, channel: inputChannel, filter: .channelMessagesFilterEmpty, pts: state.channelStates[peer.id]?.pts ?? 1, limit: 20))
|
||||
|> retryRequest
|
||||
|> map { difference -> MutableState in
|
||||
var updatedState = state
|
||||
@ -1097,7 +1141,7 @@ private func optimizedOperations(_ operations: [MutationOperation]) -> [Mutation
|
||||
var currentAddMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ResetReadState, .UpdatePeerNotificationSettings:
|
||||
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ResetReadState, .UpdatePeerNotificationSettings:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@ -1147,6 +1191,8 @@ private func replayFinalState(_ modifier: Modifier, finalState: MutableState) ->
|
||||
modifier.deleteMessagesWithGlobalIds(ids)
|
||||
case let .DeleteMessages(ids):
|
||||
modifier.deleteMessages(ids)
|
||||
case let .EditMessage(id, message):
|
||||
modifier.updateMessage(id, update: { _ in message })
|
||||
case let .UpdateMedia(id, media):
|
||||
modifier.updateMedia(id, update: media)
|
||||
case let .ReadInbox(messageId):
|
||||
@ -1212,7 +1258,7 @@ private func pollDifference(_ account: Account) -> Signal<Void, NoError> {
|
||||
|> take(1)
|
||||
|> mapToSignal { state -> Signal<Void, NoError> in
|
||||
if let authorizedState = (state as! AuthorizedAccountState).state {
|
||||
let request = account.network.request(Api.functions.updates.getDifference(pts: authorizedState.pts, date: authorizedState.date, qts: authorizedState.qts))
|
||||
let request = account.network.request(Api.functions.updates.getDifference(flags: 0, pts: authorizedState.pts, ptsTotalLimit: nil, date: authorizedState.date, qts: authorizedState.qts))
|
||||
|> retryRequest
|
||||
return request |> mapToSignal { difference -> Signal<Void, NoError> in
|
||||
return initialStateWithDifference(account, difference: difference)
|
||||
|
@ -129,7 +129,7 @@ extension Api.Message {
|
||||
}
|
||||
|
||||
switch action {
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear:
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionHistoryClear, .messageActionGameScore:
|
||||
break
|
||||
case let .messageActionChannelMigrateFrom(_, chatId):
|
||||
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))
|
||||
@ -222,6 +222,8 @@ func textAndMediaFromApiMedia(_ media: Api.MessageMedia?) -> (String?, Media?) {
|
||||
break
|
||||
case .messageMediaEmpty:
|
||||
break
|
||||
case .messageMediaGame:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,10 +263,12 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
|
||||
return result
|
||||
}
|
||||
|
||||
//message#c09be45f flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int = Message;
|
||||
|
||||
extension StoreMessage {
|
||||
convenience init?(apiMessage: Api.Message) {
|
||||
switch apiMessage {
|
||||
case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, _, entities, views, _):
|
||||
case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, editDate):
|
||||
let peerId: PeerId
|
||||
var authorId: PeerId?
|
||||
switch toId {
|
||||
@ -345,14 +349,25 @@ extension StoreMessage {
|
||||
attributes.append(ViewCountMessageAttribute(count: Int(views)))
|
||||
}
|
||||
|
||||
if let editDate = editDate {
|
||||
attributes.append(EditedMessageAttribute(date: editDate))
|
||||
}
|
||||
|
||||
if let entities = entities, !entities.isEmpty {
|
||||
attributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)))
|
||||
}
|
||||
|
||||
if let replyMarkup = replyMarkup {
|
||||
attributes.append(ReplyMarkupMessageAttribute(apiMarkup: replyMarkup))
|
||||
}
|
||||
|
||||
var storeFlags = StoreMessageFlags()
|
||||
if (flags & 2) == 0 {
|
||||
if (flags & (1 << 1)) == 0 {
|
||||
let _ = storeFlags.insert(.Incoming)
|
||||
}
|
||||
if (flags & (1 << 4)) != 0 {
|
||||
let _ = storeFlags.insert(.Personal)
|
||||
}
|
||||
|
||||
self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), timestamp: date, flags: storeFlags, tags: tagsForStoreMessage(medias), forwardInfo: forwardInfo, authorId: authorId, text: messageText, attributes: attributes, media: medias)
|
||||
case .messageEmpty:
|
||||
|
@ -11,6 +11,7 @@ private let typeImageSize: Int32 = 2
|
||||
private let typeAnimated: Int32 = 3
|
||||
private let typeVideo: Int32 = 4
|
||||
private let typeAudio: Int32 = 5
|
||||
private let typeHasLinkedStickers: Int32 = 6
|
||||
|
||||
public enum TelegramMediaFileAttribute: Coding {
|
||||
case FileName(fileName: String)
|
||||
@ -19,7 +20,7 @@ public enum TelegramMediaFileAttribute: Coding {
|
||||
case Animated
|
||||
case Video(duration: Int, size: CGSize)
|
||||
case Audio(isVoice: Bool, duration: Int, title: String?, performer: String?, waveform: MemoryBuffer?)
|
||||
case Unknown
|
||||
case HasLinkedStickers
|
||||
|
||||
public init(decoder: Decoder) {
|
||||
let type: Int32 = decoder.decodeInt32ForKey("t")
|
||||
@ -41,8 +42,10 @@ public enum TelegramMediaFileAttribute: Coding {
|
||||
waveform = MemoryBuffer(copyOf: waveformBuffer)
|
||||
}
|
||||
self = .Audio(isVoice: decoder.decodeInt32ForKey("iv") != 0, duration: Int(decoder.decodeInt32ForKey("du")), title: decoder.decodeStringForKey("ti"), performer: decoder.decodeStringForKey("pe"), waveform: waveform)
|
||||
case typeHasLinkedStickers:
|
||||
self = .HasLinkedStickers
|
||||
default:
|
||||
self = .Unknown
|
||||
preconditionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,8 +81,8 @@ public enum TelegramMediaFileAttribute: Coding {
|
||||
if let waveform = waveform {
|
||||
encoder.encodeBytes(waveform, forKey: "wf")
|
||||
}
|
||||
case .Unknown:
|
||||
break
|
||||
case .HasLinkedStickers:
|
||||
encoder.encodeInt32(typeHasLinkedStickers, forKey: "t")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,8 +222,10 @@ public func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.Docu
|
||||
switch attribute {
|
||||
case let .documentAttributeFilename(fileName):
|
||||
result.append(.FileName(fileName: fileName))
|
||||
case let .documentAttributeSticker(alt, _):
|
||||
case let .documentAttributeSticker(flags, alt, stickerSet, maskCoords):
|
||||
result.append(.Sticker(displayText: alt))
|
||||
case .documentAttributeHasStickers:
|
||||
result.append(.HasLinkedStickers)
|
||||
case let .documentAttributeImageSize(w, h):
|
||||
result.append(.ImageSize(size: CGSize(width: CGFloat(w), height: CGFloat(h))))
|
||||
case .documentAttributeAnimated:
|
||||
@ -243,7 +248,7 @@ public func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.Docu
|
||||
|
||||
public func telegramMediaFileFromApiDocument(_ document: Api.Document) -> TelegramMediaFile? {
|
||||
switch document {
|
||||
case let .document(id, accessHash, _, mimeType, size, thumb, dcId, attributes):
|
||||
case let .document(id, accessHash, _, mimeType, size, thumb, dcId, _, attributes):
|
||||
return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: id), resource: CloudDocumentMediaResource(datacenterId: Int(dcId), fileId: id, accessHash: accessHash, size: Int(size)), previewRepresentations: telegramMediaImageRepresentationsFromApiSizes([thumb]), mimeType: mimeType, size: Int(size), attributes: telegramMediaFileAttributesFromApiAttributes(attributes))
|
||||
case .documentEmpty:
|
||||
return nil
|
||||
|
@ -136,7 +136,7 @@ public func telegramMediaImageRepresentationsFromApiSizes(_ sizes: [Api.PhotoSiz
|
||||
|
||||
public func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? {
|
||||
switch photo {
|
||||
case let .photo(id, accessHash, _, sizes):
|
||||
case let .photo(flags, id, accessHash, date, sizes):
|
||||
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: telegramMediaImageRepresentationsFromApiSizes(sizes))
|
||||
case .photoEmpty:
|
||||
return nil
|
||||
|
@ -214,9 +214,11 @@ public final class TelegramMediaWebpage: Media {
|
||||
|
||||
func telegramMediaWebpageFromApiWebpage(_ webpage: Api.WebPage) -> TelegramMediaWebpage? {
|
||||
switch webpage {
|
||||
case .webPageNotModified:
|
||||
return nil
|
||||
case let .webPagePending(id, date):
|
||||
return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Pending(date))
|
||||
case let .webPage(_, id, url, displayUrl, type, siteName, title, description, photo, embedUrl, embedType, embedWidth, embedHeight, duration, author, document):
|
||||
case let .webPage(_, id, url, displayUrl, hash, type, siteName, title, description, photo, embedUrl, embedType, embedWidth, embedHeight, duration, author, document, cachedPage):
|
||||
var embedSize: CGSize?
|
||||
if let embedWidth = embedWidth, let embedHeight = embedHeight {
|
||||
embedSize = CGSize(width: CGFloat(embedWidth), height: CGFloat(embedHeight))
|
||||
|
@ -16,7 +16,8 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.modify { modifier -> Void in
|
||||
switch result {
|
||||
case let .userFull(_, _, _, _, _, notifySettings, _):
|
||||
|
||||
case let .userFull(_, _, _, _, _, notifySettings, _, commonChatCount):
|
||||
modifier.updatePeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
|
||||
}
|
||||
modifier.updatePeerCachedData(peerIds: [peerId], update: { peerId, _ in
|
||||
|
@ -129,6 +129,8 @@ extension Api.Update {
|
||||
return (pts, ptsCount)
|
||||
case let .updateReadMessages(_, pts, ptsCount):
|
||||
return (pts, ptsCount)
|
||||
case let .updateEditMessage(_, pts, ptsCount):
|
||||
return (pts, ptsCount)
|
||||
case let .updateReadMessagesContents(_, pts, ptsCount):
|
||||
return (pts, ptsCount)
|
||||
case let .updateRestoreMessages(_, pts):
|
||||
|
@ -140,6 +140,10 @@ extension Api.Update {
|
||||
return message
|
||||
case let .updateNewChannelMessage(message, _, _):
|
||||
return message
|
||||
case let .updateEditMessage(message, _, _):
|
||||
return message
|
||||
case let .updateEditChannelMessage(message, _, _):
|
||||
return message
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@ -174,6 +178,10 @@ extension Api.Update {
|
||||
return message.peerIds
|
||||
case let .updateNewMessage(message, _, _):
|
||||
return message.peerIds
|
||||
case let .updateEditMessage(message, _, _):
|
||||
return message.peerIds
|
||||
case let .updateEditChannelMessage(message, _, _):
|
||||
return message.peerIds
|
||||
//case let .updateReadChannelInbox(channelId, _):
|
||||
// return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)]
|
||||
case let .updateUserName(userId, _, _, _):
|
||||
|
@ -6,7 +6,7 @@ import Foundation
|
||||
#endif
|
||||
|
||||
public class ViewCountMessageAttribute: MessageAttribute {
|
||||
let count: Int
|
||||
public let count: Int
|
||||
|
||||
public var associatedMessageIds: [MessageId] = []
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user