mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-25 01:22:41 +00:00
Merge commit '50c01586839b0113730b0aaa9a4011b954868da2'
This commit is contained in:
commit
3024d9c43a
@ -151,7 +151,6 @@
|
||||
D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB51E61F3F900644997 /* BlockedPeers.swift */; };
|
||||
D033FEB71E61F3F900644997 /* BlockedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB51E61F3F900644997 /* BlockedPeers.swift */; };
|
||||
D03B0CB91D62233400955575 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CB81D62233400955575 /* Either.swift */; };
|
||||
D03B0CBB1D62233C00955575 /* MergeLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBA1D62233C00955575 /* MergeLists.swift */; };
|
||||
D03B0CBD1D62234300955575 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBC1D62234300955575 /* Regex.swift */; };
|
||||
D03B0CBF1D62234A00955575 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBE1D62234A00955575 /* Log.swift */; };
|
||||
D03B0CC11D62235000955575 /* StringFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CC01D62235000955575 /* StringFormat.swift */; };
|
||||
@ -454,7 +453,6 @@
|
||||
D0B8440D1DAB91CD005F29E1 /* ImageRepresentationsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */; };
|
||||
D0B8440E1DAB91CD005F29E1 /* MessageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */; };
|
||||
D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CB81D62233400955575 /* Either.swift */; };
|
||||
D0B844101DAB91CD005F29E1 /* MergeLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBA1D62233C00955575 /* MergeLists.swift */; };
|
||||
D0B844111DAB91CD005F29E1 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBC1D62234300955575 /* Regex.swift */; };
|
||||
D0B844121DAB91CD005F29E1 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBE1D62234A00955575 /* Log.swift */; };
|
||||
D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CC01D62235000955575 /* StringFormat.swift */; };
|
||||
@ -556,6 +554,8 @@
|
||||
D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */; };
|
||||
D0E6521F1E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; };
|
||||
D0E652201E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; };
|
||||
D0E817492010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */; };
|
||||
D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */; };
|
||||
D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; };
|
||||
D0F02CE61E9926C50065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; };
|
||||
D0F3A89F1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */; };
|
||||
@ -694,7 +694,6 @@
|
||||
D033FEB21E61F3C000644997 /* ReportPeer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportPeer.swift; sourceTree = "<group>"; };
|
||||
D033FEB51E61F3F900644997 /* BlockedPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockedPeers.swift; sourceTree = "<group>"; };
|
||||
D03B0CB81D62233400955575 /* Either.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = "<group>"; };
|
||||
D03B0CBA1D62233C00955575 /* MergeLists.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MergeLists.swift; sourceTree = "<group>"; };
|
||||
D03B0CBC1D62234300955575 /* Regex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = "<group>"; };
|
||||
D03B0CBE1D62234A00955575 /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
|
||||
D03B0CC01D62235000955575 /* StringFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringFormat.swift; sourceTree = "<group>"; };
|
||||
@ -930,6 +929,7 @@
|
||||
D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingMessageWithChatContextResult.swift; sourceTree = "<group>"; };
|
||||
D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingChatContextResultMessageAttribute.swift; sourceTree = "<group>"; };
|
||||
D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateAccountPeerName.swift; sourceTree = "<group>"; };
|
||||
D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelAdminEventLogContext.swift; sourceTree = "<group>"; };
|
||||
D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedConfigurationUpdates.swift; sourceTree = "<group>"; };
|
||||
D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeChatInputStateOperation.swift; sourceTree = "<group>"; };
|
||||
D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeChatInputStateOperations.swift; sourceTree = "<group>"; };
|
||||
@ -1090,7 +1090,6 @@
|
||||
D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */,
|
||||
D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */,
|
||||
D03B0CB81D62233400955575 /* Either.swift */,
|
||||
D03B0CBA1D62233C00955575 /* MergeLists.swift */,
|
||||
D03B0CBC1D62234300955575 /* Regex.swift */,
|
||||
D03B0CBE1D62234A00955575 /* Log.swift */,
|
||||
D03B0CC01D62235000955575 /* StringFormat.swift */,
|
||||
@ -1575,6 +1574,7 @@
|
||||
C23BC3861E9BE3CA00D79F92 /* ImportContact.swift */,
|
||||
C205FEA71EB3B75900455808 /* ExportMessageLink.swift */,
|
||||
C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */,
|
||||
D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */,
|
||||
D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */,
|
||||
D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */,
|
||||
D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */,
|
||||
@ -1950,6 +1950,7 @@
|
||||
D0561DE31E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */,
|
||||
D0DF0C8A1D819C7E008AEB01 /* JoinChannel.swift in Sources */,
|
||||
D04CAA5A1E83310D0047E51F /* MD5.swift in Sources */,
|
||||
D0E817492010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */,
|
||||
D05452071E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */,
|
||||
D01C7F041EFC1C49008305F1 /* DeviceContact.swift in Sources */,
|
||||
D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */,
|
||||
@ -2040,7 +2041,6 @@
|
||||
D0528E651E65C82400E2FEF5 /* UpdateContactName.swift in Sources */,
|
||||
D03121021DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift in Sources */,
|
||||
D0C48F391E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */,
|
||||
D03B0CBB1D62233C00955575 /* MergeLists.swift in Sources */,
|
||||
C239BE971E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift in Sources */,
|
||||
D03B0CC11D62235000955575 /* StringFormat.swift in Sources */,
|
||||
D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */,
|
||||
@ -2289,6 +2289,7 @@
|
||||
D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */,
|
||||
D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */,
|
||||
D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */,
|
||||
D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */,
|
||||
D0561DEB1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */,
|
||||
D0AD02E41FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */,
|
||||
D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */,
|
||||
@ -2324,7 +2325,6 @@
|
||||
D033FEB41E61F3C000644997 /* ReportPeer.swift in Sources */,
|
||||
D0FA8BAE1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */,
|
||||
D0FA8BB41E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */,
|
||||
D0B844101DAB91CD005F29E1 /* MergeLists.swift in Sources */,
|
||||
D0F3A8A31E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */,
|
||||
D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */,
|
||||
D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */,
|
||||
|
||||
@ -802,13 +802,10 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
|
||||
if !entities.isEmpty {
|
||||
attributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)))
|
||||
}
|
||||
var messageText = text
|
||||
let messageText = text
|
||||
var medias: [Media] = []
|
||||
|
||||
let (mediaText, mediaValue, expirationTimer) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let mediaText = mediaText {
|
||||
messageText = mediaText
|
||||
}
|
||||
let (mediaValue, expirationTimer) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let mediaValue = mediaValue {
|
||||
medias.append(mediaValue)
|
||||
}
|
||||
@ -829,7 +826,7 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
|
||||
updatedState.readInbox(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: maxId))
|
||||
case let .updateReadHistoryOutbox(peer, maxId, _, _):
|
||||
updatedState.readOutbox(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: maxId))
|
||||
case let .updateReadFeed(feedId, maxPosition):
|
||||
case let .updateReadFeed(_, feedId, maxPosition, unreadCount, unreadMutedCount):
|
||||
switch maxPosition {
|
||||
case let .feedPosition(date, peer, id):
|
||||
let index = MessageIndex(id: MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: id), timestamp: date)
|
||||
@ -1157,6 +1154,8 @@ private func resolveAssociatedMessages(account: Account, state: AccountMutableSt
|
||||
return (messages, chats, users)
|
||||
case let .channelMessages(_, _, _, messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case .messagesNotModified:
|
||||
return ([], [], [])
|
||||
}
|
||||
} |> `catch` { _ in
|
||||
return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], []))
|
||||
@ -1318,7 +1317,14 @@ private func resetChannels(_ account: Account, peers: [Peer], state: AccountMuta
|
||||
}
|
||||
}
|
||||
return account.network.request(Api.functions.messages.getPeerDialogs(peers: inputPeers))
|
||||
|> retryRequest
|
||||
|> map(Optional.init)
|
||||
|> `catch` { error -> Signal<Api.messages.PeerDialogs?, Void> in
|
||||
if error.errorDescription == "CHANNEL_PRIVATE" && inputPeers.count == 1 {
|
||||
return .single(nil)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|> map { result -> AccountMutableState in
|
||||
var updatedState = state
|
||||
|
||||
@ -1331,74 +1337,76 @@ private func resetChannels(_ account: Account, peers: [Peer], state: AccountMuta
|
||||
var channelStates: [PeerId: ChannelState] = [:]
|
||||
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
|
||||
|
||||
switch result {
|
||||
case let .peerDialogs(dialogs, messages, chats, users, _):
|
||||
dialogsChats.append(contentsOf: chats)
|
||||
dialogsUsers.append(contentsOf: users)
|
||||
|
||||
loop: for dialog in dialogs {
|
||||
let apiPeer: Api.Peer
|
||||
let apiReadInboxMaxId: Int32
|
||||
let apiReadOutboxMaxId: Int32
|
||||
let apiTopMessage: Int32
|
||||
let apiUnreadCount: Int32
|
||||
let apiUnreadMentionsCount: Int32
|
||||
var apiChannelPts: Int32?
|
||||
let apiNotificationSettings: Api.PeerNotifySettings
|
||||
switch dialog {
|
||||
case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _):
|
||||
apiPeer = peer
|
||||
apiTopMessage = topMessage
|
||||
apiReadInboxMaxId = readInboxMaxId
|
||||
apiReadOutboxMaxId = readOutboxMaxId
|
||||
apiUnreadCount = unreadCount
|
||||
apiUnreadMentionsCount = unreadMentionsCount
|
||||
apiNotificationSettings = peerNotificationSettings
|
||||
apiChannelPts = pts
|
||||
case .dialogFeed:
|
||||
assertionFailure()
|
||||
continue loop
|
||||
}
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .peerDialogs(dialogs, messages, chats, users, _):
|
||||
dialogsChats.append(contentsOf: chats)
|
||||
dialogsUsers.append(contentsOf: users)
|
||||
|
||||
let peerId: PeerId
|
||||
switch apiPeer {
|
||||
case let .peerUser(userId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||
case let .peerChat(chatId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
|
||||
case let .peerChannel(channelId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
|
||||
}
|
||||
|
||||
if readStates[peerId] == nil {
|
||||
readStates[peerId] = [:]
|
||||
}
|
||||
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount)
|
||||
|
||||
if apiTopMessage != 0 {
|
||||
mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage))
|
||||
}
|
||||
|
||||
if let apiChannelPts = apiChannelPts {
|
||||
channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts)
|
||||
}
|
||||
|
||||
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
|
||||
}
|
||||
|
||||
for message in messages {
|
||||
if let storeMessage = StoreMessage(apiMessage: message) {
|
||||
var updatedStoreMessage = storeMessage
|
||||
if case let .Id(id) = storeMessage.id {
|
||||
if let channelState = channelStates[id.peerId] {
|
||||
var updatedAttributes = storeMessage.attributes
|
||||
updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts))
|
||||
updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes)
|
||||
}
|
||||
loop: for dialog in dialogs {
|
||||
let apiPeer: Api.Peer
|
||||
let apiReadInboxMaxId: Int32
|
||||
let apiReadOutboxMaxId: Int32
|
||||
let apiTopMessage: Int32
|
||||
let apiUnreadCount: Int32
|
||||
let apiUnreadMentionsCount: Int32
|
||||
var apiChannelPts: Int32?
|
||||
let apiNotificationSettings: Api.PeerNotifySettings
|
||||
switch dialog {
|
||||
case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _):
|
||||
apiPeer = peer
|
||||
apiTopMessage = topMessage
|
||||
apiReadInboxMaxId = readInboxMaxId
|
||||
apiReadOutboxMaxId = readOutboxMaxId
|
||||
apiUnreadCount = unreadCount
|
||||
apiUnreadMentionsCount = unreadMentionsCount
|
||||
apiNotificationSettings = peerNotificationSettings
|
||||
apiChannelPts = pts
|
||||
case .dialogFeed:
|
||||
assertionFailure()
|
||||
continue loop
|
||||
}
|
||||
storeMessages.append(updatedStoreMessage)
|
||||
|
||||
let peerId: PeerId
|
||||
switch apiPeer {
|
||||
case let .peerUser(userId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||
case let .peerChat(chatId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
|
||||
case let .peerChannel(channelId):
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
|
||||
}
|
||||
|
||||
if readStates[peerId] == nil {
|
||||
readStates[peerId] = [:]
|
||||
}
|
||||
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount)
|
||||
|
||||
if apiTopMessage != 0 {
|
||||
mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage))
|
||||
}
|
||||
|
||||
if let apiChannelPts = apiChannelPts {
|
||||
channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts)
|
||||
}
|
||||
|
||||
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
|
||||
}
|
||||
}
|
||||
|
||||
for message in messages {
|
||||
if let storeMessage = StoreMessage(apiMessage: message) {
|
||||
var updatedStoreMessage = storeMessage
|
||||
if case let .Id(id) = storeMessage.id {
|
||||
if let channelState = channelStates[id.peerId] {
|
||||
var updatedAttributes = storeMessage.attributes
|
||||
updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts))
|
||||
updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes)
|
||||
}
|
||||
}
|
||||
storeMessages.append(updatedStoreMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updatedState.mergeChats(dialogsChats)
|
||||
@ -1774,10 +1782,16 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, modifier: Modif
|
||||
modifier.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id)
|
||||
case let .EditMessage(id, message):
|
||||
modifier.updateMessage(id, update: { previousMessage in
|
||||
var updatedFlags = message.flags
|
||||
var updatedLocalTags = message.localTags
|
||||
if previousMessage.localTags.contains(.OutgoingLiveLocation) {
|
||||
updatedLocalTags.insert(.OutgoingLiveLocation)
|
||||
}
|
||||
if message.flags.contains(.Incoming) {
|
||||
updatedFlags.insert(.Incoming)
|
||||
} else {
|
||||
updatedFlags.remove(.Incoming)
|
||||
}
|
||||
return .update(message.withUpdatedLocalTags(updatedLocalTags))
|
||||
})
|
||||
case let .UpdateMedia(id, media):
|
||||
|
||||
@ -75,8 +75,8 @@ public final class AccountStateManager {
|
||||
return self.isUpdatingValue.get()
|
||||
}
|
||||
|
||||
private let notificationMessagesPipe = ValuePipe<[Message]>()
|
||||
public var notificationMessages: Signal<[Message], NoError> {
|
||||
private let notificationMessagesPipe = ValuePipe<[(Message, PeerGroupId?)]>()
|
||||
public var notificationMessages: Signal<[(Message, PeerGroupId?)], NoError> {
|
||||
return self.notificationMessagesPipe.signal()
|
||||
}
|
||||
|
||||
@ -460,12 +460,12 @@ public final class AccountStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
let signal = self.account.postbox.modify { modifier -> [Message] in
|
||||
var messages: [Message] = []
|
||||
let signal = self.account.postbox.modify { modifier -> [(Message, PeerGroupId?)] in
|
||||
var messages: [(Message, PeerGroupId?)] = []
|
||||
for id in events.addedIncomingMessageIds {
|
||||
let (message, notify, _, _) = messageForNotification(modifier: modifier, id: id, alwaysReturnMessage: false)
|
||||
if let message = message, notify {
|
||||
messages.append(message)
|
||||
messages.append((message, modifier.getPeerGroupId(message.id.peerId)))
|
||||
}
|
||||
}
|
||||
return messages
|
||||
@ -473,7 +473,7 @@ public final class AccountStateManager {
|
||||
|
||||
let _ = (signal |> deliverOn(self.queue)).start(next: { [weak self] messages in
|
||||
if let strongSelf = self {
|
||||
for message in messages {
|
||||
for (message, _) in messages {
|
||||
Logger.shared.log("State" , "notify: \(String(describing: messageMainPeer(message)?.displayTitle)): \(message.id)")
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,10 @@ private func fetchWebpage(account: Account, messageId: MessageId) -> Signal<Void
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
chats = []
|
||||
users = []
|
||||
}
|
||||
|
||||
return account.postbox.modify { modifier -> Void in
|
||||
|
||||
@ -108,7 +108,7 @@ func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? {
|
||||
case .chat, .chatEmpty, .chatForbidden, .channelForbidden:
|
||||
return parseTelegramGroupOrChannel(chat: rhs)
|
||||
case let .channel(flags, _, accessHash, title, username, photo, date, version, restrictionReason, adminRights, bannedRights, _, feedId):
|
||||
if let _ = accessHash {
|
||||
if accessHash != nil && (flags & (1 << 12)) == 0 {
|
||||
return parseTelegramGroupOrChannel(chat: rhs)
|
||||
} else if let lhs = lhs as? TelegramChannel {
|
||||
var channelFlags = lhs.flags
|
||||
@ -128,7 +128,7 @@ func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? {
|
||||
}
|
||||
info = .group(TelegramChannelGroupInfo(flags: infoFlags))
|
||||
}
|
||||
return TelegramChannel(id: lhs.id, accessHash: lhs.accessHash, title: title, username: username, photo: imageRepresentationsForApiChatPhoto(photo), creationDate: lhs.creationDate, version: lhs.version, participationStatus: lhs.participationStatus, info: info, flags: channelFlags, restrictionInfo: lhs.restrictionInfo, adminRights: lhs.adminRights, bannedRights: lhs.bannedRights, peerGroupId: feedId.flatMap { PeerGroupId(rawValue: $0) })
|
||||
return TelegramChannel(id: lhs.id, accessHash: lhs.accessHash, title: title, username: username, photo: imageRepresentationsForApiChatPhoto(photo), creationDate: lhs.creationDate, version: lhs.version, participationStatus: lhs.participationStatus, info: info, flags: channelFlags, restrictionInfo: lhs.restrictionInfo, adminRights: lhs.adminRights, bannedRights: lhs.bannedRights, peerGroupId: lhs.peerGroupId)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -50,6 +50,8 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
}
|
||||
}
|
||||
|
||||
let channelPts = result.channelPts
|
||||
|
||||
var sentStickers: [TelegramMediaFile] = []
|
||||
var sentGifs: [TelegramMediaFile] = []
|
||||
|
||||
@ -62,14 +64,14 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
}
|
||||
|
||||
let media: [Media]
|
||||
let attributes: [MessageAttribute]
|
||||
var 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, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId)
|
||||
let (mediaValue, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId)
|
||||
if let mediaValue = mediaValue {
|
||||
media = [mediaValue]
|
||||
} else {
|
||||
@ -95,6 +97,16 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
text = currentMessage.text
|
||||
}
|
||||
|
||||
if let channelPts = channelPts {
|
||||
for i in 0 ..< attributes.count {
|
||||
if let _ = attributes[i] as? ChannelMessageStateVersionAttribute {
|
||||
attributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
|
||||
}
|
||||
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature)
|
||||
|
||||
124
TelegramCore/ChannelAdminEventLogContext.swift
Normal file
124
TelegramCore/ChannelAdminEventLogContext.swift
Normal file
@ -0,0 +1,124 @@
|
||||
#if os(macOS)
|
||||
import PostboxMac
|
||||
import SwiftSignalKitMac
|
||||
#else
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
#endif
|
||||
|
||||
public struct ChannelAdminEventLogEntry: Comparable {
|
||||
public let event: AdminLogEvent
|
||||
public let peers: [PeerId: Peer]
|
||||
|
||||
public static func ==(lhs: ChannelAdminEventLogEntry, rhs: ChannelAdminEventLogEntry) -> Bool {
|
||||
return lhs.event == rhs.event
|
||||
}
|
||||
|
||||
public static func <(lhs: ChannelAdminEventLogEntry, rhs: ChannelAdminEventLogEntry) -> Bool {
|
||||
return lhs.event < rhs.event
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChannelAdminEventLogUpdateType {
|
||||
case initial
|
||||
case generic
|
||||
case load
|
||||
}
|
||||
|
||||
public final class ChannelAdminEventLogContext {
|
||||
private let queue: Queue = Queue.mainQueue()
|
||||
|
||||
private let postbox: Postbox
|
||||
private let network: Network
|
||||
private let peerId: PeerId
|
||||
|
||||
private var entries: [ChannelAdminEventLogEntry] = []
|
||||
private var hasEarlier: Bool = true
|
||||
private var loadingMoreEarlier: Bool = false
|
||||
|
||||
private var subscribers = Bag<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType) -> Void>()
|
||||
|
||||
private let loadMoreDisposable = MetaDisposable()
|
||||
|
||||
public init(postbox: Postbox, network: Network, peerId: PeerId) {
|
||||
self.postbox = postbox
|
||||
self.network = network
|
||||
self.peerId = peerId
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.loadMoreDisposable.dispose()
|
||||
}
|
||||
|
||||
public func get() -> Signal<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType), NoError> {
|
||||
let queue = self.queue
|
||||
return Signal { [weak self] subscriber in
|
||||
if let strongSelf = self {
|
||||
subscriber.putNext((strongSelf.entries, strongSelf.hasEarlier, .initial))
|
||||
|
||||
let index = strongSelf.subscribers.add({ entries, hasEarlier, type in
|
||||
subscriber.putNext((strongSelf.entries, strongSelf.hasEarlier, type))
|
||||
})
|
||||
|
||||
return ActionDisposable {
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.subscribers.remove(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return EmptyDisposable
|
||||
}
|
||||
} |> runOn(queue)
|
||||
}
|
||||
|
||||
public func loadMoreEntries() {
|
||||
assert(self.queue.isCurrent())
|
||||
|
||||
if self.loadingMoreEarlier {
|
||||
return
|
||||
}
|
||||
|
||||
let maxId: AdminLogEventId
|
||||
if let last = self.entries.last {
|
||||
maxId = last.event.id
|
||||
} else {
|
||||
maxId = AdminLogEventId.max
|
||||
}
|
||||
|
||||
self.loadingMoreEarlier = true
|
||||
self.loadMoreDisposable.set((channelAdminLogEvents(postbox: self.postbox, network: self.network, peerId: self.peerId, maxId: maxId, minId: AdminLogEventId.min, limit: 10, query: nil, filter: nil, admins: nil)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
var events = result.events.sorted()
|
||||
if let first = strongSelf.entries.first {
|
||||
var clipIndex = events.count
|
||||
for i in (0 ..< events.count).reversed() {
|
||||
if events[i] >= first.event {
|
||||
clipIndex = i - 1
|
||||
}
|
||||
}
|
||||
if clipIndex < events.count {
|
||||
events.removeSubrange(clipIndex ..< events.count)
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.hasEarlier = !events.isEmpty
|
||||
|
||||
var entries: [ChannelAdminEventLogEntry] = events.map { event in
|
||||
return ChannelAdminEventLogEntry(event: event, peers: result.peers)
|
||||
|
||||
}
|
||||
entries.append(contentsOf: strongSelf.entries)
|
||||
strongSelf.entries = entries
|
||||
|
||||
strongSelf.loadingMoreEarlier = false
|
||||
|
||||
for subscriber in strongSelf.subscribers.copyItems() {
|
||||
subscriber(strongSelf.entries, strongSelf.hasEarlier, .load)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -8,17 +8,29 @@
|
||||
|
||||
public typealias AdminLogEventId = Int64
|
||||
|
||||
public struct AdminLogEvent {
|
||||
public struct AdminLogEvent: Comparable {
|
||||
public let id: AdminLogEventId
|
||||
public let peerId:PeerId
|
||||
public let date:Int32
|
||||
public let peerId: PeerId
|
||||
public let date: Int32
|
||||
public let action: AdminLogEventAction
|
||||
|
||||
public static func ==(lhs: AdminLogEvent, rhs: AdminLogEvent) -> Bool {
|
||||
return lhs.id == rhs.id
|
||||
}
|
||||
|
||||
public static func <(lhs: AdminLogEvent, rhs: AdminLogEvent) -> Bool {
|
||||
if lhs.date != rhs.date {
|
||||
return lhs.date < rhs.date
|
||||
} else {
|
||||
return lhs.id < rhs.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct AdminLogEventsResult {
|
||||
public let peerId: PeerId
|
||||
public let peers:[PeerId: Peer]
|
||||
public let events:[AdminLogEvent]
|
||||
public let peers: [PeerId: Peer]
|
||||
public let events: [AdminLogEvent]
|
||||
}
|
||||
|
||||
public enum AdminLogEventAction {
|
||||
@ -29,7 +41,7 @@ public enum AdminLogEventAction {
|
||||
case toggleInvites(Bool)
|
||||
case toggleSignatures(Bool)
|
||||
case updatePinned(Message?)
|
||||
case editMessage(prev: Message, new:Message)
|
||||
case editMessage(prev: Message, new: Message)
|
||||
case deleteMessage(Message)
|
||||
case participantJoin
|
||||
case participantLeave
|
||||
@ -69,129 +81,129 @@ public struct AdminLogEventsFlags : OptionSet {
|
||||
public static let editMessages = AdminLogEventsFlags(rawValue: 1 << 12)
|
||||
public static let deleteMessages = AdminLogEventsFlags(rawValue: 1 << 13)
|
||||
|
||||
public static var all:[AdminLogEventsFlags] {
|
||||
public static var all: [AdminLogEventsFlags] {
|
||||
return [.join, .leave, .invite, .ban, .unban, .kick, .unkick, .promote, .demote, .info, .settings, .pinnedMessages, .editMessages, .deleteMessages]
|
||||
}
|
||||
public static var flags:AdminLogEventsFlags {
|
||||
public static var flags: AdminLogEventsFlags {
|
||||
return [.join, .leave, .invite, .ban, .unban, .kick, .unkick, .promote, .demote, .info, .settings, .pinnedMessages, .editMessages, .deleteMessages]
|
||||
}
|
||||
}
|
||||
|
||||
private func boolFromApiValue(_ value: Api.Bool) -> Bool {
|
||||
switch value {
|
||||
case .boolFalse:
|
||||
return false
|
||||
case .boolTrue:
|
||||
return true
|
||||
case .boolFalse:
|
||||
return false
|
||||
case .boolTrue:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public func channelAdminLogEvents(_ account:Account, peerId:PeerId, maxId:AdminLogEventId, minId:AdminLogEventId, limit:Int32 = 100, query:String? = nil, filter:AdminLogEventsFlags? = nil, admins:[PeerId]? = nil) -> Signal<AdminLogEventsResult, ChannelAdminLogEventError> {
|
||||
|
||||
return account.postbox.modify { modifier -> (Peer?, [Peer]?) in
|
||||
return (modifier.getPeer(peerId), admins?.flatMap {modifier.getPeer($0)})
|
||||
} |> mapError {return .generic} |> mapToSignal { (peer, admins) -> Signal<AdminLogEventsResult, ChannelAdminLogEventError> in
|
||||
public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, maxId: AdminLogEventId, minId: AdminLogEventId, limit: Int32 = 100, query: String? = nil, filter: AdminLogEventsFlags? = nil, admins: [PeerId]? = nil) -> Signal<AdminLogEventsResult, ChannelAdminLogEventError> {
|
||||
return postbox.modify { modifier -> (Peer?, [Peer]?) in
|
||||
return (modifier.getPeer(peerId), admins?.flatMap { modifier.getPeer($0) })
|
||||
}
|
||||
|> mapError { return .generic }
|
||||
|> mapToSignal { (peer, admins) -> Signal<AdminLogEventsResult, ChannelAdminLogEventError> in
|
||||
if let peer = peer, let inputChannel = apiInputChannel(peer) {
|
||||
let inputAdmins = admins?.flatMap {apiInputUser($0)}
|
||||
|
||||
if let peer = peer, let inputChannel = apiInputChannel(peer) {
|
||||
let inputAdmins = admins?.flatMap {apiInputUser($0)}
|
||||
|
||||
var flags:Int32 = 0
|
||||
var eventsFilter:Api.ChannelAdminLogEventsFilter? = nil
|
||||
if let filter = filter {
|
||||
flags += Int32(1 << 0)
|
||||
eventsFilter = Api.ChannelAdminLogEventsFilter.channelAdminLogEventsFilter(flags: Int32(filter.rawValue))
|
||||
}
|
||||
if let _ = inputAdmins {
|
||||
flags += Int32(1 << 1)
|
||||
}
|
||||
return account.network.request(Api.functions.channels.getAdminLog(flags: flags, channel: inputChannel, q: query ?? "", eventsFilter: eventsFilter, admins: inputAdmins, maxId: maxId, minId: minId, limit: limit)) |> map { result in
|
||||
|
||||
switch result {
|
||||
case let .adminLogResults(apiEvents, apiChats, apiUsers):
|
||||
let peers = (apiChats.flatMap {parseTelegramGroupOrChannel(chat: $0)} + apiUsers.flatMap { TelegramUser(user: $0) } + Array(arrayLiteral: peer)).reduce([:], { current, peer -> [PeerId : Peer] in
|
||||
var current = current
|
||||
current[peer.id] = peer
|
||||
return current
|
||||
})
|
||||
|
||||
var events: [AdminLogEvent] = []
|
||||
|
||||
for event in apiEvents {
|
||||
switch event {
|
||||
case let .channelAdminLogEvent(id, date, userId, apiAction):
|
||||
var action: AdminLogEventAction?
|
||||
switch apiAction {
|
||||
case let .channelAdminLogEventActionChangeTitle(prev, new):
|
||||
action = .changeTitle(prev: prev, new: new)
|
||||
case let .channelAdminLogEventActionChangeAbout(prev, new):
|
||||
action = .changeAbout(prev: prev, new: new)
|
||||
case let .channelAdminLogEventActionChangeUsername(prev, new):
|
||||
action = .changeUsername(prev: prev, new: new)
|
||||
case let .channelAdminLogEventActionChangePhoto(prev, new):
|
||||
action = .changePhoto(prev: imageRepresentationsForApiChatPhoto(prev), new: imageRepresentationsForApiChatPhoto(new))
|
||||
case let .channelAdminLogEventActionToggleInvites(new):
|
||||
action = .toggleInvites(boolFromApiValue(new))
|
||||
case let .channelAdminLogEventActionToggleSignatures(new):
|
||||
action = .toggleSignatures(boolFromApiValue(new))
|
||||
case let .channelAdminLogEventActionUpdatePinned(new):
|
||||
switch new {
|
||||
case .messageEmpty:
|
||||
action = .updatePinned(nil)
|
||||
default:
|
||||
if let message = StoreMessage(apiMessage: new), let rendered = locallyRenderedMessage(message: message, peers: peers) {
|
||||
action = .updatePinned(rendered)
|
||||
}
|
||||
}
|
||||
|
||||
case let .channelAdminLogEventActionEditMessage(prev, new):
|
||||
if let prev = StoreMessage(apiMessage: prev), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new), let newRendered = locallyRenderedMessage(message: new, peers: peers) {
|
||||
action = .editMessage(prev: prevRendered, new: newRendered)
|
||||
}
|
||||
case let .channelAdminLogEventActionDeleteMessage(message):
|
||||
if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) {
|
||||
action = .deleteMessage(rendered)
|
||||
}
|
||||
case .channelAdminLogEventActionParticipantJoin:
|
||||
action = .participantJoin
|
||||
case .channelAdminLogEventActionParticipantLeave:
|
||||
action = .participantLeave
|
||||
case let .channelAdminLogEventActionParticipantInvite(participant):
|
||||
let participant = ChannelParticipant(apiParticipant: participant)
|
||||
|
||||
if let peer = peers[participant.peerId] {
|
||||
action = .participantInvite(RenderedChannelParticipant(participant: participant, peer: peer))
|
||||
}
|
||||
case let .channelAdminLogEventActionParticipantToggleBan(prev, new):
|
||||
let prevParticipant = ChannelParticipant(apiParticipant: prev)
|
||||
let newParticipant = ChannelParticipant(apiParticipant: new)
|
||||
|
||||
if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] {
|
||||
action = .participantToggleBan(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer))
|
||||
}
|
||||
case let .channelAdminLogEventActionParticipantToggleAdmin(prev, new):
|
||||
let prevParticipant = ChannelParticipant(apiParticipant: prev)
|
||||
let newParticipant = ChannelParticipant(apiParticipant: new)
|
||||
|
||||
if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] {
|
||||
action = .participantToggleAdmin(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer))
|
||||
}
|
||||
case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset):
|
||||
action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset))
|
||||
case let .channelAdminLogEventActionTogglePreHistoryHidden(value):
|
||||
action = .togglePreHistoryHidden(value == .boolTrue)
|
||||
}
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||
if let action = action {
|
||||
events.append(AdminLogEvent(id: id, peerId: peerId, date: date, action: action))
|
||||
}
|
||||
}
|
||||
}
|
||||
return AdminLogEventsResult(peerId: peerId, peers: peers, events: events)
|
||||
}
|
||||
|
||||
} |> mapError {_ in return .generic}
|
||||
var flags: Int32 = 0
|
||||
var eventsFilter: Api.ChannelAdminLogEventsFilter? = nil
|
||||
if let filter = filter {
|
||||
flags += Int32(1 << 0)
|
||||
eventsFilter = Api.ChannelAdminLogEventsFilter.channelAdminLogEventsFilter(flags: Int32(filter.rawValue))
|
||||
}
|
||||
|
||||
return .complete()
|
||||
if let _ = inputAdmins {
|
||||
flags += Int32(1 << 1)
|
||||
}
|
||||
return network.request(Api.functions.channels.getAdminLog(flags: flags, channel: inputChannel, q: query ?? "", eventsFilter: eventsFilter, admins: inputAdmins, maxId: maxId, minId: minId, limit: limit)) |> map { result in
|
||||
|
||||
switch result {
|
||||
case let .adminLogResults(apiEvents, apiChats, apiUsers):
|
||||
let peers = (apiChats.flatMap {parseTelegramGroupOrChannel(chat: $0)} + apiUsers.flatMap { TelegramUser(user: $0) } + Array(arrayLiteral: peer)).reduce([:], { current, peer -> [PeerId : Peer] in
|
||||
var current = current
|
||||
current[peer.id] = peer
|
||||
return current
|
||||
})
|
||||
|
||||
var events: [AdminLogEvent] = []
|
||||
|
||||
for event in apiEvents {
|
||||
switch event {
|
||||
case let .channelAdminLogEvent(id, date, userId, apiAction):
|
||||
var action: AdminLogEventAction?
|
||||
switch apiAction {
|
||||
case let .channelAdminLogEventActionChangeTitle(prev, new):
|
||||
action = .changeTitle(prev: prev, new: new)
|
||||
case let .channelAdminLogEventActionChangeAbout(prev, new):
|
||||
action = .changeAbout(prev: prev, new: new)
|
||||
case let .channelAdminLogEventActionChangeUsername(prev, new):
|
||||
action = .changeUsername(prev: prev, new: new)
|
||||
case let .channelAdminLogEventActionChangePhoto(prev, new):
|
||||
action = .changePhoto(prev: imageRepresentationsForApiChatPhoto(prev), new: imageRepresentationsForApiChatPhoto(new))
|
||||
case let .channelAdminLogEventActionToggleInvites(new):
|
||||
action = .toggleInvites(boolFromApiValue(new))
|
||||
case let .channelAdminLogEventActionToggleSignatures(new):
|
||||
action = .toggleSignatures(boolFromApiValue(new))
|
||||
case let .channelAdminLogEventActionUpdatePinned(new):
|
||||
switch new {
|
||||
case .messageEmpty:
|
||||
action = .updatePinned(nil)
|
||||
default:
|
||||
if let message = StoreMessage(apiMessage: new), let rendered = locallyRenderedMessage(message: message, peers: peers) {
|
||||
action = .updatePinned(rendered)
|
||||
}
|
||||
}
|
||||
|
||||
case let .channelAdminLogEventActionEditMessage(prev, new):
|
||||
if let prev = StoreMessage(apiMessage: prev), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new), let newRendered = locallyRenderedMessage(message: new, peers: peers) {
|
||||
action = .editMessage(prev: prevRendered, new: newRendered)
|
||||
}
|
||||
case let .channelAdminLogEventActionDeleteMessage(message):
|
||||
if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) {
|
||||
action = .deleteMessage(rendered)
|
||||
}
|
||||
case .channelAdminLogEventActionParticipantJoin:
|
||||
action = .participantJoin
|
||||
case .channelAdminLogEventActionParticipantLeave:
|
||||
action = .participantLeave
|
||||
case let .channelAdminLogEventActionParticipantInvite(participant):
|
||||
let participant = ChannelParticipant(apiParticipant: participant)
|
||||
|
||||
if let peer = peers[participant.peerId] {
|
||||
action = .participantInvite(RenderedChannelParticipant(participant: participant, peer: peer))
|
||||
}
|
||||
case let .channelAdminLogEventActionParticipantToggleBan(prev, new):
|
||||
let prevParticipant = ChannelParticipant(apiParticipant: prev)
|
||||
let newParticipant = ChannelParticipant(apiParticipant: new)
|
||||
|
||||
if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] {
|
||||
action = .participantToggleBan(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer))
|
||||
}
|
||||
case let .channelAdminLogEventActionParticipantToggleAdmin(prev, new):
|
||||
let prevParticipant = ChannelParticipant(apiParticipant: prev)
|
||||
let newParticipant = ChannelParticipant(apiParticipant: new)
|
||||
|
||||
if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] {
|
||||
action = .participantToggleAdmin(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer))
|
||||
}
|
||||
case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset):
|
||||
action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset))
|
||||
case let .channelAdminLogEventActionTogglePreHistoryHidden(value):
|
||||
action = .togglePreHistoryHidden(value == .boolTrue)
|
||||
}
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||
if let action = action {
|
||||
events.append(AdminLogEvent(id: id, peerId: peerId, date: date, action: action))
|
||||
}
|
||||
}
|
||||
}
|
||||
return AdminLogEventsResult(peerId: peerId, peers: peers, events: events)
|
||||
}
|
||||
|
||||
} |> mapError {_ in return .generic}
|
||||
}
|
||||
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import Foundation
|
||||
#endif
|
||||
|
||||
public enum ChatContextResultMessage: PostboxCoding, Equatable {
|
||||
case auto(caption: String, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case auto(caption: String, entities: TextEntitiesMessageAttribute?, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case text(text: String, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case mapLocation(media: TelegramMediaMap, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case contact(media: TelegramMediaContact, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
@ -18,7 +18,7 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable {
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_v", orElse: 0) {
|
||||
case 0:
|
||||
self = .auto(caption: decoder.decodeStringForKey("c", orElse: ""), replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
self = .auto(caption: decoder.decodeStringForKey("c", orElse: ""), entities: decoder.decodeObjectForKey("e") as? TextEntitiesMessageAttribute, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
case 1:
|
||||
self = .text(text: decoder.decodeStringForKey("t", orElse: ""), entities: decoder.decodeObjectForKey("e") as? TextEntitiesMessageAttribute, disableUrlPreview: decoder.decodeInt32ForKey("du", orElse: 0) != 0, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
case 2:
|
||||
@ -26,15 +26,20 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable {
|
||||
case 3:
|
||||
self = .contact(media: decoder.decodeObjectForKey("c") as! TelegramMediaContact, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
default:
|
||||
self = .auto(caption: "", replyMarkup: nil)
|
||||
self = .auto(caption: "", entities: nil, replyMarkup: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
switch self {
|
||||
case let .auto(caption, replyMarkup):
|
||||
case let .auto(caption, entities, replyMarkup):
|
||||
encoder.encodeInt32(0, forKey: "_v")
|
||||
encoder.encodeString(caption, forKey: "c")
|
||||
if let entities = entities {
|
||||
encoder.encodeObject(entities, forKey: "e")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "e")
|
||||
}
|
||||
if let replyMarkup = replyMarkup {
|
||||
encoder.encodeObject(replyMarkup, forKey: "m")
|
||||
} else {
|
||||
@ -75,11 +80,14 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable {
|
||||
|
||||
public static func ==(lhs: ChatContextResultMessage, rhs: ChatContextResultMessage) -> Bool {
|
||||
switch lhs {
|
||||
case let .auto(lhsCaption, lhsReplyMarkup):
|
||||
if case let .auto(rhsCaption, rhsReplyMarkup) = rhs {
|
||||
case let .auto(lhsCaption, lhsEntities, lhsReplyMarkup):
|
||||
if case let .auto(rhsCaption, rhsEntities, rhsReplyMarkup) = rhs {
|
||||
if lhsCaption != rhsCaption {
|
||||
return false
|
||||
}
|
||||
if lhsEntities != rhsEntities {
|
||||
return false
|
||||
}
|
||||
if lhsReplyMarkup != rhsReplyMarkup {
|
||||
return false
|
||||
}
|
||||
@ -324,12 +332,16 @@ public final class ChatContextResultCollection: Equatable {
|
||||
extension ChatContextResultMessage {
|
||||
init(apiMessage: Api.BotInlineMessage) {
|
||||
switch apiMessage {
|
||||
case let .botInlineMessageMediaAuto(_, caption, replyMarkup):
|
||||
case let .botInlineMessageMediaAuto(_, message, entities, replyMarkup):
|
||||
var parsedEntities: TextEntitiesMessageAttribute?
|
||||
if let entities = entities, !entities.isEmpty {
|
||||
parsedEntities = TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities))
|
||||
}
|
||||
var parsedReplyMarkup: ReplyMarkupMessageAttribute?
|
||||
if let replyMarkup = replyMarkup {
|
||||
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
|
||||
}
|
||||
self = .auto(caption: caption, replyMarkup: parsedReplyMarkup)
|
||||
self = .auto(caption: message, entities: parsedEntities, replyMarkup: parsedReplyMarkup)
|
||||
case let .botInlineMessageText(flags, message, entities, replyMarkup):
|
||||
var parsedEntities: TextEntitiesMessageAttribute?
|
||||
if let entities = entities, !entities.isEmpty {
|
||||
|
||||
@ -61,7 +61,7 @@ final class HistoryViewChannelStateValidationContexts {
|
||||
if ranges.isEmpty {
|
||||
ranges = [[id]]
|
||||
} else {
|
||||
ranges[rangesToInvalidate.count - 1].append(id)
|
||||
ranges[ranges.count - 1].append(id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,6 +122,8 @@ final class HistoryViewChannelStateValidationContexts {
|
||||
var addedRanges: [[MessageId]] = []
|
||||
for messages in rangesToInvalidate {
|
||||
for id in messages {
|
||||
invalidatedMessageIds.insert(id)
|
||||
|
||||
if context.batchReferences[id] != nil {
|
||||
addRangeBreak(&addedRanges)
|
||||
} else {
|
||||
@ -130,7 +132,7 @@ final class HistoryViewChannelStateValidationContexts {
|
||||
}
|
||||
}
|
||||
|
||||
if !addedRanges.isEmpty && addedRanges[rangesToInvalidate.count - 1].isEmpty {
|
||||
if !addedRanges.isEmpty && addedRanges[addedRanges.count - 1].isEmpty {
|
||||
addedRanges.removeLast()
|
||||
}
|
||||
|
||||
@ -141,7 +143,7 @@ final class HistoryViewChannelStateValidationContexts {
|
||||
context.batchReferences[messageId] = batch
|
||||
}
|
||||
|
||||
disposable.set((validateBatch(postbox: self.postbox, network: self.network, messageIds: messages)
|
||||
disposable.set((validateBatch(postbox: self.postbox, network: self.network, messageIds: messages, validatePts: invalidatedPts)
|
||||
|> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in
|
||||
if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch {
|
||||
var completedMessageIds: [MessageId] = []
|
||||
@ -215,8 +217,10 @@ final class HistoryViewChannelStateValidationContexts {
|
||||
private func hashForMessages(_ messages: [Message]) -> Int32 {
|
||||
var acc: UInt32 = 0
|
||||
|
||||
for message in messages {
|
||||
acc = (acc &* 20261) &+ message.id.id
|
||||
let sorted = messages.sorted(by: { $0.id > $1.id })
|
||||
|
||||
for message in sorted {
|
||||
acc = (acc &* 20261) &+ UInt32(message.id.id)
|
||||
var timestamp = message.timestamp
|
||||
inner: for attribute in message.attributes {
|
||||
if let attribute = attribute as? EditedMessageAttribute {
|
||||
@ -224,25 +228,173 @@ private func hashForMessages(_ messages: [Message]) -> Int32 {
|
||||
break inner
|
||||
}
|
||||
}
|
||||
acc = (acc &* 20261) &+ timestamp
|
||||
acc = (acc &* 20261) &+ UInt32(timestamp)
|
||||
}
|
||||
return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))
|
||||
}
|
||||
|
||||
private func validateBatch(postbox: Postbox, network: Network, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
||||
private func hashForMessages(_ messages: [StoreMessage]) -> Int32 {
|
||||
var acc: UInt32 = 0
|
||||
|
||||
for message in messages {
|
||||
if case let .Id(id) = message.id {
|
||||
acc = (acc &* 20261) &+ UInt32(id.id)
|
||||
var timestamp = message.timestamp
|
||||
inner: for attribute in message.attributes {
|
||||
if let attribute = attribute as? EditedMessageAttribute {
|
||||
timestamp = attribute.date
|
||||
break inner
|
||||
}
|
||||
}
|
||||
acc = (acc &* 20261) &+ UInt32(timestamp)
|
||||
}
|
||||
}
|
||||
return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))
|
||||
}
|
||||
|
||||
private func validateBatch(postbox: Postbox, network: Network, messageIds: [MessageId], validatePts: Int32) -> Signal<Void, NoError> {
|
||||
guard let peerId = messageIds.first?.peerId else {
|
||||
return .never()
|
||||
}
|
||||
return postbox.modify { modifier -> Signal<Void, NoError> in
|
||||
if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
var messages: [Message] = []
|
||||
var previous: [MessageId: Message] = [:]
|
||||
for messageId in messageIds {
|
||||
if let message = modifier.getMessage(messageId) {
|
||||
messages.append(message)
|
||||
previous[message.id] = message
|
||||
}
|
||||
}
|
||||
let hash = hashForMessages(messages)
|
||||
return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: messageIds[messageIds.count - 1].id, offsetDate: 0, addOffset: 0, limit: 100, maxId: messageIds[messageIds.cout - 1].id, minId: messageIds[0].id))
|
||||
return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: messageIds[messageIds.count - 1].id + 1, offsetDate: 0, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.modify { modifier -> Void in
|
||||
if let result = result {
|
||||
let messages: [Api.Message]
|
||||
let chats: [Api.Chat]
|
||||
let users: [Api.User]
|
||||
var channelPts: Int32?
|
||||
|
||||
switch result {
|
||||
case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .channelMessages(_, pts, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
channelPts = pts
|
||||
case .messagesNotModified:
|
||||
for id in previous.keys {
|
||||
modifier.updateMessage(id, update: { currentMessage in
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature)
|
||||
}
|
||||
var attributes = currentMessage.attributes
|
||||
/*if let channelPts = channelPts {
|
||||
for i in 0 ..< attributes.count {
|
||||
if let _ = attributes[i] as? ChannelMessageStateVersionAttribute {
|
||||
attributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
|
||||
}*/
|
||||
for i in 0 ..< attributes.count {
|
||||
if let _ = attributes[i] as? ChannelMessageStateVersionAttribute {
|
||||
attributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
attributes.append(ChannelMessageStateVersionAttribute(pts: validatePts))
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var storeMessages: [StoreMessage] = []
|
||||
|
||||
for message in messages {
|
||||
if let storeMessage = StoreMessage(apiMessage: message) {
|
||||
if let channelPts = channelPts {
|
||||
var attributes = storeMessage.attributes
|
||||
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
|
||||
storeMessages.append(storeMessage.withUpdatedAttributes(attributes))
|
||||
} else {
|
||||
storeMessages.append(storeMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//let updatedHash = hashForMessages(storeMessages)
|
||||
|
||||
var validMessageIds = Set<MessageId>()
|
||||
for message in storeMessages {
|
||||
if case let .Id(id) = message.id {
|
||||
validMessageIds.insert(id)
|
||||
|
||||
if let previousMessage = previous[id] {
|
||||
var updatedTimestamp = message.timestamp
|
||||
inner: for attribute in message.attributes {
|
||||
if let attribute = attribute as? EditedMessageAttribute {
|
||||
updatedTimestamp = attribute.date
|
||||
break inner
|
||||
}
|
||||
}
|
||||
|
||||
var timestamp = previousMessage.timestamp
|
||||
inner: for attribute in previousMessage.attributes {
|
||||
if let attribute = attribute as? EditedMessageAttribute {
|
||||
timestamp = attribute.date
|
||||
break inner
|
||||
}
|
||||
}
|
||||
|
||||
modifier.updateMessage(id, update: { currentMessage in
|
||||
if updatedTimestamp != timestamp {
|
||||
return .update(message)
|
||||
} else {
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature)
|
||||
}
|
||||
var attributes = currentMessage.attributes
|
||||
if let channelPts = channelPts {
|
||||
for i in 0 ..< attributes.count {
|
||||
if let _ = attributes[i] as? ChannelMessageStateVersionAttribute {
|
||||
attributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
|
||||
}
|
||||
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for id in previous.keys {
|
||||
if !validMessageIds.contains(id) {
|
||||
modifier.deleteMessages([id])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .never()
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos
|
||||
default:
|
||||
assertionFailure()
|
||||
}
|
||||
request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit)))
|
||||
request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0))
|
||||
} else if let filter = messageFilterForTagMask(tagMask) {
|
||||
let offsetId: Int32
|
||||
let addOffset: Int32
|
||||
@ -119,7 +119,7 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos
|
||||
minId = 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: hole.maxIndex.timestamp, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: hole.maxIndex.timestamp, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
} else {
|
||||
assertionFailure()
|
||||
request = .never()
|
||||
@ -145,7 +145,7 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos
|
||||
if hole.maxIndex.timestamp == Int32.max {
|
||||
let innerOffsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1)
|
||||
let innerMaxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1)
|
||||
maxIndexRequest = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: innerOffsetId, offsetDate: hole.maxIndex.timestamp, addOffset: 0, limit: 1, maxId: innerMaxId, minId: 1))
|
||||
maxIndexRequest = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: innerOffsetId, offsetDate: hole.maxIndex.timestamp, addOffset: 0, limit: 1, maxId: innerMaxId, minId: 1, hash: 0))
|
||||
|> map(Optional.init)
|
||||
}
|
||||
case let .AroundId(id):
|
||||
@ -160,7 +160,7 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos
|
||||
minId = 1
|
||||
}
|
||||
|
||||
request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: hole.maxIndex.timestamp, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId))
|
||||
request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: hole.maxIndex.timestamp, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
|
||||
}
|
||||
|
||||
return combineLatest(request |> retryRequest, maxIndexRequest |> retryRequest)
|
||||
@ -183,6 +183,10 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
channelPts = pts
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
chats = []
|
||||
users = []
|
||||
}
|
||||
var updatedMaxIndex: MessageIndex?
|
||||
if let maxIndexResult = maxIndexResult {
|
||||
@ -194,6 +198,8 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos
|
||||
maxIndexMessages = apiMessages
|
||||
case let .channelMessages(_, _, _, apiMessages, _, _):
|
||||
maxIndexMessages = apiMessages
|
||||
case .messagesNotModified:
|
||||
maxIndexMessages = []
|
||||
}
|
||||
if !maxIndexMessages.isEmpty {
|
||||
assert(maxIndexMessages.count == 1)
|
||||
@ -501,7 +507,7 @@ func fetchCallListHole(network: Network, postbox: Postbox, holeIndex: MessageInd
|
||||
offset = single((holeIndex.timestamp, min(holeIndex.id.id, Int32.max - 1) + 1, Api.InputPeer.inputPeerEmpty), NoError.self)
|
||||
return offset
|
||||
|> mapToSignal { (timestamp, id, peer) -> Signal<Void, NoError> in
|
||||
let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0))
|
||||
let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0, hash: 0))
|
||||
|> retryRequest
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
let messages: [Api.Message]
|
||||
@ -520,6 +526,10 @@ func fetchCallListHole(network: Network, postbox: Postbox, holeIndex: MessageInd
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
chats = []
|
||||
users = []
|
||||
}
|
||||
return postbox.modify { modifier -> Void in
|
||||
var storeMessages: [StoreMessage] = []
|
||||
|
||||
@ -60,12 +60,14 @@ public func getMessagesLoadIfNecessary(_ messageIds:[MessageId], postbox:Postbox
|
||||
if let signal = signal {
|
||||
signals.append(signal |> map { result in
|
||||
switch result {
|
||||
case let .messages(messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case let .messagesSlice(_, messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case let .channelMessages(_, _, _, messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case let .messages(messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case let .messagesSlice(_, messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case let .channelMessages(_, _, _, messages, chats, users):
|
||||
return (messages, chats, users)
|
||||
case .messagesNotModified:
|
||||
return ([], [], [])
|
||||
}
|
||||
} |> `catch` { _ in
|
||||
return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], []))
|
||||
|
||||
@ -43,6 +43,8 @@ public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: M
|
||||
apiUsers = users
|
||||
case let .channelMessages(_, _, _, _, _, users):
|
||||
apiUsers = users
|
||||
case .messagesNotModified:
|
||||
apiUsers = []
|
||||
}
|
||||
|
||||
for user in apiUsers {
|
||||
|
||||
@ -119,8 +119,8 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
|
||||
switch item {
|
||||
case let .peer(peerId):
|
||||
return peerId.namespace != Namespaces.Peer.SecretChat
|
||||
case .group:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
let localItemIds = modifier.getPinnedItemIds()
|
||||
@ -128,17 +128,14 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
|
||||
switch item {
|
||||
case let .peer(peerId):
|
||||
return peerId.namespace != Namespaces.Peer.SecretChat
|
||||
case .group:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.getPinnedDialogs())
|
||||
|> retryRequest
|
||||
|> mapToSignal { dialogs -> Signal<Void, NoError> in
|
||||
let dialogsChats: [Api.Chat]
|
||||
let dialogsUsers: [Api.User]
|
||||
|
||||
var storeMessages: [StoreMessage] = []
|
||||
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
|
||||
var chatStates: [PeerId: PeerChatState] = [:]
|
||||
@ -146,10 +143,27 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
|
||||
|
||||
var remoteItemIds: [PinnedItemId] = []
|
||||
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||
|
||||
switch dialogs {
|
||||
case let .peerDialogs(dialogs, messages, chats, users, _):
|
||||
dialogsChats = chats
|
||||
dialogsUsers = users
|
||||
var channelGroupIds: [PeerId: PeerGroupId] = [:]
|
||||
for chat in chats {
|
||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||
peers.append(groupOrChannel)
|
||||
if let channel = groupOrChannel as? TelegramChannel, let peerGroupId = channel.peerGroupId {
|
||||
channelGroupIds[channel.id] = peerGroupId
|
||||
}
|
||||
}
|
||||
}
|
||||
for user in users {
|
||||
let telegramUser = TelegramUser(user: user)
|
||||
peers.append(telegramUser)
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
peerPresences[telegramUser.id] = presence
|
||||
}
|
||||
}
|
||||
|
||||
loop: for dialog in dialogs {
|
||||
let apiPeer: Api.Peer
|
||||
@ -161,6 +175,9 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
|
||||
let apiNotificationSettings: Api.PeerNotifySettings
|
||||
switch dialog {
|
||||
case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _):
|
||||
if channelGroupIds[peer.peerId] != nil {
|
||||
continue loop
|
||||
}
|
||||
apiPeer = peer
|
||||
apiTopMessage = topMessage
|
||||
apiReadInboxMaxId = readInboxMaxId
|
||||
@ -204,21 +221,6 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
|
||||
}
|
||||
}
|
||||
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||
for chat in dialogsChats {
|
||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||
peers.append(groupOrChannel)
|
||||
}
|
||||
}
|
||||
for user in dialogsUsers {
|
||||
let telegramUser = TelegramUser(user: user)
|
||||
peers.append(telegramUser)
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
peerPresences[telegramUser.id] = presence
|
||||
}
|
||||
}
|
||||
|
||||
let locallyRemovedFromRemoteItemIds = Set(initialRemoteItemIdsWithoutSecretChats).subtracting(Set(localItemIdsWithoutSecretChats))
|
||||
let remotelyRemovedItemIds = Set(initialRemoteItemIdsWithoutSecretChats).subtracting(Set(remoteItemIds))
|
||||
|
||||
|
||||
@ -1,413 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
public protocol Identifiable {
|
||||
associatedtype T: Hashable
|
||||
var stableId: T { get }
|
||||
}
|
||||
|
||||
public func mergeListsStable<T>(leftList: [T], rightList: [T]) -> ([Int], [(Int, T, Int?)]) where T: Comparable, T: Identifiable {
|
||||
var removeIndices: [Int] = []
|
||||
var insertItems: [(Int, T, Int?)] = []
|
||||
|
||||
var currentList = leftList
|
||||
|
||||
var i = 0
|
||||
var j = 0
|
||||
while true {
|
||||
let left: T? = i < currentList.count ? currentList[i] : nil
|
||||
let right: T? = j < rightList.count ? rightList[j] : nil
|
||||
|
||||
if let left = left, let right = right {
|
||||
if left == right {
|
||||
i += 1
|
||||
j += 1
|
||||
} else if left < right {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else {
|
||||
j += 1
|
||||
}
|
||||
} else if let _ = left {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else if let _ = right {
|
||||
j += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for index in removeIndices.reversed() {
|
||||
currentList.remove(at: index)
|
||||
}
|
||||
|
||||
var previousIndices: [T.T: Int] = [:]
|
||||
i = 0
|
||||
for left in leftList {
|
||||
previousIndices[left.stableId] = i
|
||||
i += 1
|
||||
}
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
while true {
|
||||
let left: T? = i < currentList.count ? currentList[i] : nil
|
||||
let right: T? = j < rightList.count ? rightList[j] : nil
|
||||
|
||||
if let left = left, let right = right {
|
||||
if left == right {
|
||||
i += 1
|
||||
j += 1
|
||||
} else if left > right {
|
||||
let previousIndex = previousIndices[right.stableId]
|
||||
insertItems.append((i, right, previousIndex))
|
||||
currentList.insert(right, at: i)
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
i += 1
|
||||
}
|
||||
} else if let _ = left {
|
||||
i += 1
|
||||
} else if let right = right {
|
||||
let previousIndex = previousIndices[right.stableId]
|
||||
insertItems.append((i, right, previousIndex))
|
||||
currentList.insert(right, at: i)
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert(currentList == rightList, "currentList == rightList")
|
||||
|
||||
return (removeIndices, insertItems)
|
||||
}
|
||||
|
||||
public func mergeListsStableWithUpdates<T>(leftList: [T], rightList: [T]) -> ([Int], [(Int, T, Int?)], [(Int, T, Int)]) where T: Comparable, T: Identifiable {
|
||||
var removeIndices: [Int] = []
|
||||
var insertItems: [(Int, T, Int?)] = []
|
||||
var updatedIndices: [(Int, T, Int)] = []
|
||||
|
||||
#if (arch(i386) || arch(x86_64)) && os(iOS)
|
||||
var existingStableIds: [T.T: T] = [:]
|
||||
for item in leftList {
|
||||
if let _ = existingStableIds[item.stableId] {
|
||||
assertionFailure()
|
||||
} else {
|
||||
existingStableIds[item.stableId] = item
|
||||
}
|
||||
}
|
||||
existingStableIds.removeAll()
|
||||
for item in rightList {
|
||||
if let other = existingStableIds[item.stableId] {
|
||||
print("\(other) has the same stableId as \(item): \(item.stableId)")
|
||||
assertionFailure()
|
||||
} else {
|
||||
existingStableIds[item.stableId] = item
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
var currentList = leftList
|
||||
|
||||
var i = 0
|
||||
var previousIndices: [T.T: Int] = [:]
|
||||
for left in leftList {
|
||||
previousIndices[left.stableId] = i
|
||||
i += 1
|
||||
}
|
||||
|
||||
i = 0
|
||||
var j = 0
|
||||
while true {
|
||||
let left: T? = i < currentList.count ? currentList[i] : nil
|
||||
let right: T? = j < rightList.count ? rightList[j] : nil
|
||||
|
||||
if let left = left, let right = right {
|
||||
if left.stableId == right.stableId && left != right {
|
||||
updatedIndices.append((i, right, previousIndices[left.stableId]!))
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
if left == right {
|
||||
i += 1
|
||||
j += 1
|
||||
} else if left < right {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else if !(left > right) {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else {
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
} else if let _ = left {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else if let _ = right {
|
||||
j += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//print("remove:\n\(removeIndices)")
|
||||
|
||||
for index in removeIndices.reversed() {
|
||||
currentList.remove(at: index)
|
||||
for i in 0 ..< updatedIndices.count {
|
||||
if updatedIndices[i].0 >= index {
|
||||
updatedIndices[i].0 -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*print("\n current after removes:\n")
|
||||
m = 0
|
||||
for right in currentList {
|
||||
print("\(m): \(right.stableId)")
|
||||
m += 1
|
||||
}
|
||||
|
||||
print("update:\n\(updatedIndices.map({ "\($0.0), \($0.1.stableId) (was \($0.2)))" }))")*/
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
var k = 0
|
||||
while true {
|
||||
let left: T?
|
||||
|
||||
//print("i=\(i), j=\(j), k=\(k)")
|
||||
|
||||
if k < updatedIndices.count && updatedIndices[k].0 < i {
|
||||
//print("updated[k=\(k)]=\(updatedIndices[k].0)<i=\(i), k++")
|
||||
k += 1
|
||||
}
|
||||
|
||||
if k < updatedIndices.count {
|
||||
if updatedIndices[k].0 == i {
|
||||
left = updatedIndices[k].1
|
||||
//print("override left = \(updatedIndices[k].1.stableId)")
|
||||
} else {
|
||||
left = i < currentList.count ? currentList[i] : nil
|
||||
}
|
||||
} else {
|
||||
left = i < currentList.count ? currentList[i] : nil
|
||||
}
|
||||
|
||||
let right: T? = j < rightList.count ? rightList[j] : nil
|
||||
|
||||
if let left = left, let right = right {
|
||||
if left == right {
|
||||
//print("\(left.stableId)==\(right.stableId)")
|
||||
//print("i++, j++")
|
||||
i += 1
|
||||
j += 1
|
||||
} else if left > right {
|
||||
//print("\(left.stableId)>\(right.stableId)")
|
||||
//print("insert \(right.stableId) at \(i)")
|
||||
//print("i++, j++")
|
||||
let previousIndex = previousIndices[right.stableId]
|
||||
insertItems.append((i, right, previousIndex))
|
||||
currentList.insert(right, at: i)
|
||||
if k < updatedIndices.count {
|
||||
for l in k ..< updatedIndices.count {
|
||||
updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2)
|
||||
}
|
||||
}
|
||||
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
//print("\(left.stableId)<\(right.stableId)")
|
||||
//print("i++")
|
||||
i += 1
|
||||
}
|
||||
} else if let _ = left {
|
||||
//print("\(left!.stableId)>nil")
|
||||
//print("i++")
|
||||
i += 1
|
||||
} else if let right = right {
|
||||
//print("nil<\(right.stableId)")
|
||||
//print("insert \(right.stableId) at \(i)")
|
||||
//print("i++")
|
||||
//print("j++")
|
||||
let previousIndex = previousIndices[right.stableId]
|
||||
insertItems.append((i, right, previousIndex))
|
||||
currentList.insert(right, at: i)
|
||||
|
||||
if k < updatedIndices.count {
|
||||
for l in k ..< updatedIndices.count {
|
||||
updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2)
|
||||
}
|
||||
}
|
||||
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for (index, item, _) in updatedIndices {
|
||||
currentList[index] = item
|
||||
}
|
||||
|
||||
assert(currentList == rightList, "currentList == rightList")
|
||||
|
||||
return (removeIndices, insertItems, updatedIndices)
|
||||
}
|
||||
|
||||
public func mergeListsStableWithUpdatesReversed<T>(leftList: [T], rightList: [T]) -> ([Int], [(Int, T, Int?)], [(Int, T, Int)]) where T: Comparable, T: Identifiable {
|
||||
var removeIndices: [Int] = []
|
||||
var insertItems: [(Int, T, Int?)] = []
|
||||
var updatedIndices: [(Int, T, Int)] = []
|
||||
|
||||
#if (arch(i386) || arch(x86_64)) && os(iOS)
|
||||
var existingStableIds: [T.T: T] = [:]
|
||||
for item in leftList {
|
||||
if let _ = existingStableIds[item.stableId] {
|
||||
assertionFailure()
|
||||
} else {
|
||||
existingStableIds[item.stableId] = item
|
||||
}
|
||||
}
|
||||
existingStableIds.removeAll()
|
||||
for item in rightList {
|
||||
if let other = existingStableIds[item.stableId] {
|
||||
print("\(other) has the same stableId as \(item): \(item.stableId)")
|
||||
assertionFailure()
|
||||
} else {
|
||||
existingStableIds[item.stableId] = item
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
var currentList = leftList
|
||||
|
||||
var i = 0
|
||||
var previousIndices: [T.T: Int] = [:]
|
||||
for left in leftList {
|
||||
previousIndices[left.stableId] = i
|
||||
i += 1
|
||||
}
|
||||
|
||||
i = 0
|
||||
var j = 0
|
||||
while true {
|
||||
let left: T? = i < currentList.count ? currentList[i] : nil
|
||||
let right: T? = j < rightList.count ? rightList[j] : nil
|
||||
|
||||
if let left = left, let right = right {
|
||||
if left.stableId == right.stableId && left != right {
|
||||
updatedIndices.append((i, right, previousIndices[left.stableId]!))
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
if left == right {
|
||||
i += 1
|
||||
j += 1
|
||||
} else if left > right {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else if !(left < right) {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else {
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
} else if let _ = left {
|
||||
removeIndices.append(i)
|
||||
i += 1
|
||||
} else if let _ = right {
|
||||
j += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
//print("remove:\n\(removeIndices)")
|
||||
|
||||
for index in removeIndices.reversed() {
|
||||
currentList.remove(at: index)
|
||||
for i in 0 ..< updatedIndices.count {
|
||||
if updatedIndices[i].0 >= index {
|
||||
updatedIndices[i].0 -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
var k = 0
|
||||
while true {
|
||||
let left: T?
|
||||
|
||||
if k < updatedIndices.count && updatedIndices[k].0 < i {
|
||||
k += 1
|
||||
}
|
||||
|
||||
if k < updatedIndices.count {
|
||||
if updatedIndices[k].0 == i {
|
||||
left = updatedIndices[k].1
|
||||
} else {
|
||||
left = i < currentList.count ? currentList[i] : nil
|
||||
}
|
||||
} else {
|
||||
left = i < currentList.count ? currentList[i] : nil
|
||||
}
|
||||
|
||||
let right: T? = j < rightList.count ? rightList[j] : nil
|
||||
|
||||
if let left = left, let right = right {
|
||||
if left == right {
|
||||
i += 1
|
||||
j += 1
|
||||
} else if left < right {
|
||||
let previousIndex = previousIndices[right.stableId]
|
||||
insertItems.append((i, right, previousIndex))
|
||||
currentList.insert(right, at: i)
|
||||
if k < updatedIndices.count {
|
||||
for l in k ..< updatedIndices.count {
|
||||
updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2)
|
||||
}
|
||||
}
|
||||
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
i += 1
|
||||
}
|
||||
} else if let _ = left {
|
||||
i += 1
|
||||
} else if let right = right {
|
||||
let previousIndex = previousIndices[right.stableId]
|
||||
insertItems.append((i, right, previousIndex))
|
||||
currentList.insert(right, at: i)
|
||||
|
||||
if k < updatedIndices.count {
|
||||
for l in k ..< updatedIndices.count {
|
||||
updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2)
|
||||
}
|
||||
}
|
||||
|
||||
i += 1
|
||||
j += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for (index, item, _) in updatedIndices {
|
||||
currentList[index] = item
|
||||
}
|
||||
|
||||
assert(currentList == rightList, "currentList == rightList")
|
||||
|
||||
return (removeIndices, insertItems, updatedIndices)
|
||||
}
|
||||
|
||||
@ -122,7 +122,10 @@ public func outgoingMessageWithChatContextResult(_ results: ChatContextResultCol
|
||||
attributes.append(InlineBotMessageAttribute(peerId: results.botId))
|
||||
|
||||
switch result.message {
|
||||
case let .auto(caption, replyMarkup):
|
||||
case let .auto(caption, entities, replyMarkup):
|
||||
if let entities = entities {
|
||||
attributes.append(entities)
|
||||
}
|
||||
if let replyMarkup = replyMarkup {
|
||||
attributes.append(replyMarkup)
|
||||
}
|
||||
|
||||
@ -551,8 +551,20 @@ public final class PendingMessageManager {
|
||||
}
|
||||
if let uniqueId = uniqueId {
|
||||
switch content {
|
||||
case let .media(inputMedia):
|
||||
singleMedias.append(.inputSingleMedia(media: inputMedia, randomId: uniqueId))
|
||||
case let .media(inputMedia, text):
|
||||
var messageEntities: [Api.MessageEntity]?
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||
messageEntities = apiTextAttributeEntities(attribute, associatedPeers: message.peers)
|
||||
}
|
||||
}
|
||||
|
||||
var singleFlags: Int32 = 0
|
||||
if let _ = messageEntities {
|
||||
singleFlags |= 1 << 0
|
||||
}
|
||||
|
||||
singleMedias.append(.inputSingleMedia(media: inputMedia, flags: singleFlags, randomId: uniqueId, message: text, entities: messageEntities))
|
||||
default:
|
||||
return .complete()
|
||||
}
|
||||
@ -726,8 +738,8 @@ public final class PendingMessageManager {
|
||||
|> mapError { _ -> NoError in
|
||||
return NoError()
|
||||
}
|
||||
case let .media(inputMedia):
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, randomId: uniqueId, replyMarkup: nil), tag: dependencyTag)
|
||||
case let .media(inputMedia, text):
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities), tag: dependencyTag)
|
||||
|> mapError { _ -> NoError in
|
||||
return NoError()
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import TelegramCorePrivateModule
|
||||
|
||||
enum PendingMessageUploadedContent {
|
||||
case text(String)
|
||||
case media(Api.InputMedia)
|
||||
case media(Api.InputMedia, String)
|
||||
case forward(ForwardSourceInfoAttribute)
|
||||
case chatContextResult(OutgoingChatContextResultMessageAttribute)
|
||||
case secretMedia(Api.InputEncryptedFile, Int32, SecretFileEncryptionKey)
|
||||
@ -64,19 +64,19 @@ func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods
|
||||
} else if let media = media.first {
|
||||
if let image = media as? TelegramMediaImage, let _ = largestImageRepresentation(image.representations) {
|
||||
if let reference = image.reference, case let .cloud(id, accessHash) = reference {
|
||||
return .ready(.media(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: id, accessHash: accessHash), caption: text, ttlSeconds: nil)))
|
||||
return .ready(.media(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: id, accessHash: accessHash), ttlSeconds: nil), text))
|
||||
} else {
|
||||
return .upload(uploadedMediaImageContent(network: network, postbox: postbox, peerId: peerId, image: image, text: text, autoremoveAttribute: autoremoveAttribute))
|
||||
}
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
if let resource = file.resource as? CloudDocumentMediaResource {
|
||||
return .ready(.media(Api.InputMedia.inputMediaDocument(id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash), caption: text)))
|
||||
return .ready(.media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash), ttlSeconds: nil), text))
|
||||
} else {
|
||||
return .upload(uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, peerId: peerId, messageId: messageId, text: text, attributes: attributes, file: file))
|
||||
}
|
||||
} else if let contact = media as? TelegramMediaContact {
|
||||
let input = Api.InputMedia.inputMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName)
|
||||
return .ready(.media(input))
|
||||
return .ready(.media(input, text))
|
||||
} else if let map = media as? TelegramMediaMap {
|
||||
let input: Api.InputMedia
|
||||
if let liveBroadcastingTimeout = map.liveBroadcastingTimeout {
|
||||
@ -86,7 +86,7 @@ func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods
|
||||
} else {
|
||||
input = .inputMediaGeoPoint(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude))
|
||||
}
|
||||
return .ready(.media(input))
|
||||
return .ready(.media(input, text))
|
||||
} else {
|
||||
return .ready(.text(text))
|
||||
}
|
||||
@ -194,7 +194,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, peerI
|
||||
flags |= 1 << 1
|
||||
ttlSeconds = autoremoveAttribute.timeout
|
||||
}
|
||||
return .single(.progress(1.0)) |> then(.single(.content(.media(.inputMediaPhoto(flags: flags, id: .inputPhoto(id: id, accessHash: accessHash), caption: text, ttlSeconds: ttlSeconds)))))
|
||||
return .single(.progress(1.0)) |> then(.single(.content(.media(.inputMediaPhoto(flags: flags, id: .inputPhoto(id: id, accessHash: accessHash), ttlSeconds: ttlSeconds), text))))
|
||||
}
|
||||
case let .localReference(key):
|
||||
referenceKey = key
|
||||
@ -221,14 +221,14 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, peerI
|
||||
|> mapToSignal { inputPeer -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||
if let inputPeer = inputPeer {
|
||||
if autoremoveAttribute != nil {
|
||||
return .single(.content(.media(.inputMediaUploadedPhoto(flags: flags, file: file, caption: text, stickers: nil, ttlSeconds: ttlSeconds))))
|
||||
return .single(.content(.media(.inputMediaUploadedPhoto(flags: flags, file: file, stickers: nil, ttlSeconds: ttlSeconds), text)))
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: flags, file: file, caption: text, stickers: nil, ttlSeconds: ttlSeconds)))
|
||||
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: flags, file: file, stickers: nil, ttlSeconds: ttlSeconds)))
|
||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||
switch result {
|
||||
case let .messageMediaPhoto(_, photo, _, _):
|
||||
case let .messageMediaPhoto(_, photo, _):
|
||||
if let photo = photo, let mediaImage = telegramMediaImageFromApiPhoto(photo), let reference = mediaImage.reference, case let .cloud(id, accessHash) = reference {
|
||||
var flags: Int32 = 0
|
||||
var ttlSeconds: Int32?
|
||||
@ -236,7 +236,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, peerI
|
||||
flags |= 1 << 1
|
||||
ttlSeconds = autoremoveAttribute.timeout
|
||||
}
|
||||
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(.media(.inputMediaPhoto(flags: flags, id: .inputPhoto(id: id, accessHash: accessHash), caption: text, ttlSeconds: ttlSeconds))), media: mediaImage)
|
||||
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(.media(.inputMediaPhoto(flags: flags, id: .inputPhoto(id: id, accessHash: accessHash), ttlSeconds: ttlSeconds), text)), media: mediaImage)
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -359,7 +359,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
||||
switch result {
|
||||
case let .media(media):
|
||||
if let file = media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
|
||||
return .single(.progress(1.0)) |> then(.single(.content(.media(Api.InputMedia.inputMediaDocument(id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash), caption: text)))))
|
||||
return .single(.progress(1.0)) |> then(.single(.content(.media(Api.InputMedia.inputMediaDocument(flags: 0, id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash), ttlSeconds: nil), text))))
|
||||
}
|
||||
case let .localReference(key):
|
||||
referenceKey = key
|
||||
@ -460,7 +460,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
||||
}
|
||||
|
||||
if ttlSeconds != nil {
|
||||
return .single(.content(.media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnail, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), caption: text, stickers: nil, ttlSeconds: ttlSeconds))))
|
||||
return .single(.content(.media(.inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnail, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, ttlSeconds: ttlSeconds), text)))
|
||||
}
|
||||
|
||||
return postbox.modify { modifier -> Api.InputPeer? in
|
||||
@ -469,13 +469,13 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||
|> mapToSignal { inputPeer -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||
if let inputPeer = inputPeer {
|
||||
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: .inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnail, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), caption: text, stickers: nil, ttlSeconds: ttlSeconds)))
|
||||
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: .inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnail, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, ttlSeconds: ttlSeconds)))
|
||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||
switch result {
|
||||
case let .messageMediaDocument(_, document, _, _):
|
||||
case let .messageMediaDocument(_, document, _):
|
||||
if let document = document, let mediaFile = telegramMediaFileFromApiDocument(document), let resource = mediaFile.resource as? CloudDocumentMediaResource {
|
||||
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(.media(.inputMediaDocument(id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash), caption: text))), media: mediaFile)
|
||||
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(.media(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash), ttlSeconds: nil), text)), media: mediaFile)
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
||||
@ -64,7 +64,7 @@ public func requestPeerPhotos(account:Account, peerId:PeerId) -> Signal<[Telegra
|
||||
}
|
||||
}
|
||||
} else if let peer = peer, let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0)) |> map {Optional($0)}
|
||||
return account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0, hash: 0)) |> map {Optional($0)}
|
||||
|> mapError {_ in}
|
||||
|> `catch` {
|
||||
return Signal<Api.messages.Messages?, Void>.single(nil)
|
||||
@ -75,18 +75,22 @@ public func requestPeerPhotos(account:Account, peerId:PeerId) -> Signal<[Telegra
|
||||
let chats: [Api.Chat]
|
||||
let users: [Api.User]
|
||||
switch result {
|
||||
case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .messages(apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let.messagesSlice(_, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .messages(apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let.messagesSlice(_, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
chats = []
|
||||
users = []
|
||||
}
|
||||
|
||||
return account.postbox.modify { modifier -> [Message] in
|
||||
|
||||
@ -79,7 +79,7 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
}
|
||||
return account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: 0, addOffset: 0, limit: 100, maxId: Int32.max - 1, minId: 0))
|
||||
return account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: 0, addOffset: 0, limit: 100, maxId: Int32.max - 1, minId: 0, hash: 0))
|
||||
|> map {Optional($0)}
|
||||
|> `catch` { _ -> Signal<Api.messages.Messages?, MTRpcError> in
|
||||
return .single(nil)
|
||||
@ -117,6 +117,10 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
chats = []
|
||||
users = []
|
||||
}
|
||||
|
||||
return account.postbox.modify { modifier -> [Message] in
|
||||
@ -183,18 +187,22 @@ public func downloadMessage(account: Account, messageId: MessageId) -> Signal<Me
|
||||
let chats: [Api.Chat]
|
||||
let users: [Api.User]
|
||||
switch result {
|
||||
case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .messages(apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let.messagesSlice(_, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .messages(apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let.messagesSlice(_, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
chats = []
|
||||
users = []
|
||||
}
|
||||
|
||||
let postboxSignal = account.postbox.modify { modifier -> Message? in
|
||||
@ -239,7 +247,7 @@ public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, timesta
|
||||
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
return .single(modifier.findClosestMessageIdByTimestamp(peerId: peerId, timestamp: timestamp))
|
||||
} else if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0))
|
||||
return account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|
||||
|> map { result -> MessageId? in
|
||||
let messages: [Api.Message]
|
||||
switch result {
|
||||
@ -249,6 +257,8 @@ public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, timesta
|
||||
messages = apiMessages
|
||||
case let.messagesSlice(_, apiMessages, _, _):
|
||||
messages = apiMessages
|
||||
case .messagesNotModified:
|
||||
messages = []
|
||||
}
|
||||
for message in messages {
|
||||
if let message = StoreMessage(apiMessage: message), case let .Id(id) = message.id {
|
||||
|
||||
@ -20,7 +20,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 75
|
||||
return 76
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
||||
@ -64,6 +64,10 @@ private func fetchMessage(modifier: Modifier, account: Account, messageId: Messa
|
||||
apiMessages = messages
|
||||
apiChats = chats
|
||||
apiUsers = users
|
||||
case .messagesNotModified:
|
||||
apiMessages = []
|
||||
apiChats = []
|
||||
apiUsers = []
|
||||
}
|
||||
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
|
||||
@ -16,7 +16,7 @@ public enum StandaloneMedia {
|
||||
|
||||
private enum StandaloneMessageContent {
|
||||
case text(String)
|
||||
case media(Api.InputMedia)
|
||||
case media(Api.InputMedia, String)
|
||||
}
|
||||
|
||||
private enum StandaloneSendMessageEvent {
|
||||
@ -33,25 +33,25 @@ public func standaloneSendMessage(account: Account, peerId: PeerId, text: String
|
||||
if let media = media {
|
||||
switch media {
|
||||
case let .image(data):
|
||||
content = uploadedImage(account: account, text: text, data: data)
|
||||
content = uploadedImage(account: account, data: data)
|
||||
|> mapError { _ -> StandaloneSendMessageError in return .generic }
|
||||
|> map { next -> StandaloneSendMessageEvent in
|
||||
switch next {
|
||||
case let .progress(progress):
|
||||
return .progress(progress)
|
||||
case let .result(media):
|
||||
return .result(.media(media))
|
||||
return .result(.media(media, text))
|
||||
}
|
||||
}
|
||||
case let .file(data, mimeType, attributes):
|
||||
content = uploadedFile(account: account, text: text, data: data, mimeType: mimeType, attributes: attributes)
|
||||
content = uploadedFile(account: account, data: data, mimeType: mimeType, attributes: attributes)
|
||||
|> mapError { _ -> StandaloneSendMessageError in return .generic }
|
||||
|> map { next -> StandaloneSendMessageEvent in
|
||||
switch next {
|
||||
case let .progress(progress):
|
||||
return .progress(progress)
|
||||
case let .result(media):
|
||||
return .result(.media(media))
|
||||
return .result(.media(media, text))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,8 +116,8 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
|> mapError { _ -> NoError in
|
||||
return NoError()
|
||||
}
|
||||
case let .media(inputMedia):
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, randomId: uniqueId, replyMarkup: nil))
|
||||
case let .media(inputMedia, text):
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities))
|
||||
|> mapError { _ -> NoError in
|
||||
return NoError()
|
||||
}
|
||||
@ -141,13 +141,13 @@ private enum UploadMediaEvent {
|
||||
case result(Api.InputMedia)
|
||||
}
|
||||
|
||||
private func uploadedImage(account: Account, text: String, data: Data) -> Signal<UploadMediaEvent, StandaloneSendMessageError> {
|
||||
private func uploadedImage(account: Account, data: Data) -> Signal<UploadMediaEvent, StandaloneSendMessageError> {
|
||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image))
|
||||
|> mapError { _ -> StandaloneSendMessageError in return .generic }
|
||||
|> map { next -> UploadMediaEvent in
|
||||
switch next {
|
||||
case let .inputFile(inputFile):
|
||||
return .result(Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, caption: text, stickers: nil, ttlSeconds: nil))
|
||||
return .result(Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil))
|
||||
case .inputSecretFile:
|
||||
preconditionFailure()
|
||||
case let .progress(progress):
|
||||
@ -156,13 +156,13 @@ private func uploadedImage(account: Account, text: String, data: Data) -> Signal
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadedFile(account: Account, text: String, data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) -> Signal<UploadMediaEvent, PendingMessageUploadError> {
|
||||
private func uploadedFile(account: Account, data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) -> Signal<UploadMediaEvent, PendingMessageUploadError> {
|
||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: statsCategoryForFileWithAttributes(attributes)))
|
||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||
|> map { next -> UploadMediaEvent in
|
||||
switch next {
|
||||
case let .inputFile(inputFile):
|
||||
return .result(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), caption: text, stickers: nil, ttlSeconds: nil))
|
||||
return .result(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, ttlSeconds: nil))
|
||||
case .inputSecretFile:
|
||||
preconditionFailure()
|
||||
case let .progress(progress):
|
||||
|
||||
@ -28,11 +28,11 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri
|
||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||
|> mapToSignal { inputPeer -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
||||
if let inputPeer = inputPeer {
|
||||
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, caption: "", stickers: nil, ttlSeconds: nil)))
|
||||
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil)))
|
||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
||||
switch media {
|
||||
case let .messageMediaPhoto(_, photo, _, _):
|
||||
case let .messageMediaPhoto(_, photo, _):
|
||||
if let photo = photo {
|
||||
if let mediaImage = telegramMediaImageFromApiPhoto(photo) {
|
||||
return .single(.result(mediaImage))
|
||||
@ -67,11 +67,11 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin
|
||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||
|> mapToSignal { inputPeer -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
||||
if let inputPeer = inputPeer {
|
||||
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), caption: text, stickers: nil, ttlSeconds: nil)))
|
||||
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), stickers: nil, ttlSeconds: nil)))
|
||||
|> mapError { _ -> StandaloneUploadMediaError in return .generic }
|
||||
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
||||
switch media {
|
||||
case let .messageMediaDocument(_, document, _, _):
|
||||
case let .messageMediaDocument(_, document, _):
|
||||
if let document = document {
|
||||
if let mediaFile = telegramMediaFileFromApiDocument(document) {
|
||||
return .single(.result(mediaFile))
|
||||
|
||||
@ -266,48 +266,48 @@ extension Api.Message {
|
||||
}
|
||||
}
|
||||
|
||||
func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerId:PeerId) -> (String?, Media?, Int32?) {
|
||||
func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerId:PeerId) -> (Media?, Int32?) {
|
||||
if let media = media {
|
||||
switch media {
|
||||
case let .messageMediaPhoto(_, photo, caption, ttlSeconds):
|
||||
case let .messageMediaPhoto(_, photo, ttlSeconds):
|
||||
if let photo = photo {
|
||||
if let mediaImage = telegramMediaImageFromApiPhoto(photo) {
|
||||
return (caption, mediaImage, ttlSeconds)
|
||||
return (mediaImage, ttlSeconds)
|
||||
}
|
||||
} else {
|
||||
return (nil, TelegramMediaExpiredContent(data: .image), nil)
|
||||
return (TelegramMediaExpiredContent(data: .image), nil)
|
||||
}
|
||||
case let .messageMediaContact(phoneNumber, firstName, lastName, userId):
|
||||
let contactPeerId: PeerId? = userId == 0 ? nil : PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||
let mediaContact = TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: contactPeerId)
|
||||
return (nil, mediaContact, nil)
|
||||
return (mediaContact, nil)
|
||||
case let .messageMediaGeo(geo):
|
||||
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil)
|
||||
return (nil, mediaMap, nil)
|
||||
return (mediaMap, 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)
|
||||
return (nil, mediaMap, nil)
|
||||
return (mediaMap, nil)
|
||||
case let .messageMediaGeoLive(geo, period):
|
||||
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period)
|
||||
return (nil, mediaMap, nil)
|
||||
case let .messageMediaDocument(_, document, caption, ttlSeconds):
|
||||
return (mediaMap, nil)
|
||||
case let .messageMediaDocument(_, document, ttlSeconds):
|
||||
if let document = document {
|
||||
if let mediaFile = telegramMediaFileFromApiDocument(document) {
|
||||
return (caption, mediaFile, ttlSeconds)
|
||||
return (mediaFile, ttlSeconds)
|
||||
}
|
||||
} else {
|
||||
return (nil, TelegramMediaExpiredContent(data: .file), nil)
|
||||
return (TelegramMediaExpiredContent(data: .file), nil)
|
||||
}
|
||||
case let .messageMediaWebPage(webpage):
|
||||
if let mediaWebpage = telegramMediaWebpageFromApiWebpage(webpage) {
|
||||
return (nil, mediaWebpage, nil)
|
||||
return (mediaWebpage, nil)
|
||||
}
|
||||
case .messageMediaUnsupported:
|
||||
return (nil, TelegramMediaUnsupported(), nil)
|
||||
return (TelegramMediaUnsupported(), nil)
|
||||
case .messageMediaEmpty:
|
||||
break
|
||||
case let .messageMediaGame(game):
|
||||
return (nil, TelegramMediaGame(apiGame: game), nil)
|
||||
return (TelegramMediaGame(apiGame: game), nil)
|
||||
case let .messageMediaInvoice(flags, title, description, photo, receiptMsgId, currency, totalAmount, startParam):
|
||||
var parsedFlags = TelegramMediaInvoiceFlags()
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
@ -316,11 +316,11 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
parsedFlags.insert(.shippingAddressRequested)
|
||||
}
|
||||
return (nil, 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, flags: parsedFlags), 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, flags: parsedFlags), nil)
|
||||
}
|
||||
}
|
||||
|
||||
return (nil, nil, nil)
|
||||
return (nil, nil)
|
||||
}
|
||||
|
||||
func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [MessageTextEntity] {
|
||||
@ -432,16 +432,13 @@ extension StoreMessage {
|
||||
}
|
||||
}
|
||||
|
||||
var messageText = message
|
||||
let messageText = message
|
||||
var medias: [Media] = []
|
||||
|
||||
var consumableContent: (Bool, Bool)? = nil
|
||||
|
||||
if let media = media {
|
||||
let (mediaText, mediaValue, expirationTimer) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let mediaText = mediaText {
|
||||
messageText = mediaText
|
||||
}
|
||||
let (mediaValue, expirationTimer) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let mediaValue = mediaValue {
|
||||
medias.append(mediaValue)
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ private func inputSecretChat(postbox: Postbox, peerId: PeerId) -> Signal<Api.Inp
|
||||
private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId) -> Signal<(Int32, Int32), VerifyReadStateError> {
|
||||
return inputPeer(postbox: postbox, peerId: peerId)
|
||||
|> mapToSignal { inputPeer -> Signal<(Int32, Int32), VerifyReadStateError> in
|
||||
return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: Int32.max, offsetDate: Int32.max, addOffset: 0, limit: 1, maxId: Int32.max, minId: 1))
|
||||
return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: Int32.max, offsetDate: Int32.max, addOffset: 0, limit: 1, maxId: Int32.max, minId: 1, hash: 0))
|
||||
|> retryRequest
|
||||
|> mapToSignalPromotingError { result -> Signal<(Int32, Int32), VerifyReadStateError> in
|
||||
let apiMessages: [Api.Message]
|
||||
@ -53,6 +53,8 @@ private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId
|
||||
apiMessages = messages
|
||||
case let .messagesSlice(_, messages, _, _):
|
||||
apiMessages = messages
|
||||
case .messagesNotModified:
|
||||
apiMessages = []
|
||||
}
|
||||
if let message = apiMessages.first, let timestamp = message.timestamp {
|
||||
return .single((message.rawId, timestamp))
|
||||
|
||||
@ -8,7 +8,7 @@ import Foundation
|
||||
extension Api.MessageMedia {
|
||||
var preCachedResources: [(MediaResource, Data)]? {
|
||||
switch self {
|
||||
case let .messageMediaPhoto(_, photo, _, _):
|
||||
case let .messageMediaPhoto(_, photo, _):
|
||||
if let photo = photo {
|
||||
switch photo {
|
||||
case let .photo(_, _, _, _, sizes):
|
||||
@ -34,7 +34,7 @@ extension Api.MessageMedia {
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .messageMediaDocument(_, document, _, _):
|
||||
case let .messageMediaDocument(_, document, _):
|
||||
if let document = document {
|
||||
switch document {
|
||||
case .document:
|
||||
@ -283,6 +283,17 @@ extension Api.Update {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var channelPts: Int32? {
|
||||
switch self {
|
||||
case let .updateNewChannelMessage(_, pts, _):
|
||||
return pts
|
||||
case let .updateEditChannelMessage(_, pts, _):
|
||||
return pts
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Api.Updates {
|
||||
@ -421,6 +432,39 @@ extension Api.Updates {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
var channelPts: Int32? {
|
||||
switch self {
|
||||
case let .updates(updates, _, _, _, _):
|
||||
var result: Int32?
|
||||
for update in updates {
|
||||
if let channelPts = update.channelPts {
|
||||
if result == nil || channelPts > result! {
|
||||
result = channelPts
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
case let .updatesCombined(updates, _, _, _, _, _):
|
||||
var result: Int32?
|
||||
for update in updates {
|
||||
if let channelPts = update.channelPts {
|
||||
if result == nil || channelPts > result! {
|
||||
result = channelPts
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
case let .updateShort(update, _):
|
||||
if let message = update.channelPts {
|
||||
return channelPts
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Api.Updates {
|
||||
|
||||
@ -14,7 +14,7 @@ public func webpagePreview(account: Account, url: String, webpageId: MediaId? =
|
||||
if let webpageId = webpageId, let webpage = modifier.getMedia(webpageId) as? TelegramMediaWebpage {
|
||||
return .single(webpage)
|
||||
} else {
|
||||
return account.network.request(Api.functions.messages.getWebPagePreview(message: url))
|
||||
return account.network.request(Api.functions.messages.getWebPagePreview(flags: 0, message: url, entities: nil))
|
||||
|> `catch` { _ -> Signal<Api.MessageMedia, NoError> in
|
||||
return .single(.messageMediaEmpty)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user