Update Ghostgram features

This commit is contained in:
ichmagmaus 812
2026-03-07 18:15:32 +01:00
parent 1a3303b059
commit 24a7ec39d9
902 changed files with 148295 additions and 62348 deletions
@@ -482,12 +482,6 @@ private class AdMessagesHistoryContextImpl {
}
self.isActivated = true
// MISC: Block ads if setting enabled
if MiscSettingsManager.shared.shouldBlockAds {
self.stateValue = State(interPostInterval: nil, startDelay: nil, betweenDelay: nil, messages: [])
return
}
let peerId = self.peerId
let accountPeerId = self.account.peerId
let account = self.account
@@ -516,7 +510,8 @@ private class AdMessagesHistoryContextImpl {
return account.postbox.transaction { transaction -> (interPostInterval: Int32?, startDelay: Int32?, betweenDelay: Int32?, messages: [Message]) in
switch result {
case let .sponsoredMessages(_, postsBetween, startDelay, betweenDelay, messages, chats, users):
case let .sponsoredMessages(sponsoredMessagesData):
let (postsBetween, startDelay, betweenDelay, messages, chats, users) = (sponsoredMessagesData.postsBetween, sponsoredMessagesData.startDelay, sponsoredMessagesData.betweenDelay, sponsoredMessagesData.messages, sponsoredMessagesData.chats, sponsoredMessagesData.users)
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
@@ -524,7 +519,8 @@ private class AdMessagesHistoryContextImpl {
for message in messages {
switch message {
case let .sponsoredMessage(flags, randomId, url, title, message, entities, photo, media, color, buttonText, sponsorInfo, additionalInfo, minDisplayDuration, maxDisplayDuration):
case let .sponsoredMessage(sponsoredMessageData):
let (flags, randomId, url, title, message, entities, apiPhoto, media, color, buttonText, sponsorInfo, additionalInfo, minDisplayDuration, maxDisplayDuration) = (sponsoredMessageData.flags, sponsoredMessageData.randomId, sponsoredMessageData.url, sponsoredMessageData.title, sponsoredMessageData.message, sponsoredMessageData.entities, sponsoredMessageData.photo, sponsoredMessageData.media, sponsoredMessageData.color, sponsoredMessageData.buttonText, sponsoredMessageData.sponsorInfo, sponsoredMessageData.additionalInfo, sponsoredMessageData.minDisplayDuration, sponsoredMessageData.maxDisplayDuration)
var parsedEntities: [MessageTextEntity] = []
if let entities = entities {
parsedEntities = messageTextEntitiesFromApiEntities(entities)
@@ -537,7 +533,8 @@ private class AdMessagesHistoryContextImpl {
var backgroundEmojiId: Int64?
if let color {
switch color {
case let .peerColor(_, color, backgroundEmojiIdValue):
case let .peerColor(peerColorData):
let (color, backgroundEmojiIdValue) = (peerColorData.color, peerColorData.backgroundEmojiId)
nameColorIndex = color
backgroundEmojiId = backgroundEmojiIdValue
default:
@@ -545,7 +542,7 @@ private class AdMessagesHistoryContextImpl {
}
}
let photo = photo.flatMap { telegramMediaImageFromApiPhoto($0) }
let photo = apiPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
let contentMedia = textMediaAndExpirationTimerFromApiMedia(media, peerId).media
parsedMessages.append(CachedMessage(
@@ -64,7 +64,6 @@ func _internal_applyMaxReadIndexInteractively(transaction: Transaction, stateMan
}
}
} else if index.id.peerId.namespace == Namespaces.Peer.CloudUser || index.id.peerId.namespace == Namespaces.Peer.CloudGroup || index.id.peerId.namespace == Namespaces.Peer.CloudChannel {
// GHOST MODE: Don't send read receipts (blue checkmarks)
if !GhostModeManager.shared.shouldHideReadReceipts {
stateManager.notifyAppliedIncomingReadMessages([index.id])
}
@@ -167,7 +166,7 @@ func _internal_toggleForumThreadUnreadMarkInteractively(transaction: Transaction
if peer.isForum {
} else if peer.isMonoForum {
if let inputPeer = apiInputPeer(peer), let subPeer = transaction.getPeer(PeerId(threadId)).flatMap(apiInputPeer) {
let _ = network.request(Api.functions.messages.markDialogUnread(flags: 1 << 0, parentPeer: inputPeer, peer: .inputDialogPeer(peer: subPeer))).start()
let _ = network.request(Api.functions.messages.markDialogUnread(flags: 1 << 0, parentPeer: inputPeer, peer: .inputDialogPeer(.init(peer: subPeer)))).start()
}
}
} else {
@@ -298,17 +298,20 @@ func managedSynchronizeAttachMenuBots(accountPeerId: PeerId, postbox: Postbox, n
}
return postbox.transaction { transaction -> Void in
switch result {
case let .attachMenuBots(hash, bots, users):
case let .attachMenuBots(attachMenuBotsData):
let (hash, bots, users) = (attachMenuBotsData.hash, attachMenuBotsData.bots, attachMenuBotsData.users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
var resultBots: [AttachMenuBots.Bot] = []
for bot in bots {
switch bot {
case let .attachMenuBot(apiFlags, botId, name, apiPeerTypes, botIcons):
case let .attachMenuBot(attachMenuBotData):
let (apiFlags, botId, name, apiPeerTypes, botIcons) = (attachMenuBotData.flags, attachMenuBotData.botId, attachMenuBotData.shortName, attachMenuBotData.peerTypes, attachMenuBotData.icons)
var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:]
for icon in botIcons {
switch icon {
case let .attachMenuBotIcon(_, name, icon, _):
case let .attachMenuBotIcon(attachMenuBotIconData):
let (_, name, icon, _) = (attachMenuBotIconData.flags, attachMenuBotIconData.name, attachMenuBotIconData.icon, attachMenuBotIconData.colors)
if let iconName = AttachMenuBots.Bot.IconName(string: name), let icon = telegramMediaFileFromApiDocument(icon, altDocuments: []) {
icons[iconName] = icon
}
@@ -524,7 +527,8 @@ func _internal_getAttachMenuBot(accountPeerId: PeerId, postbox: Postbox, network
|> mapToSignal { result -> Signal<AttachMenuBot, GetAttachMenuBotError> in
return postbox.transaction { transaction -> Signal<AttachMenuBot, GetAttachMenuBotError> in
switch result {
case let .attachMenuBotsBot(bot, users):
case let .attachMenuBotsBot(attachMenuBotsBotData):
let (bot, users) = (attachMenuBotsBotData.bot, attachMenuBotsBotData.users)
var peer: Peer?
for user in users {
let telegramUser = TelegramUser(user: user)
@@ -539,11 +543,13 @@ func _internal_getAttachMenuBot(accountPeerId: PeerId, postbox: Postbox, network
}
switch bot {
case let .attachMenuBot(apiFlags, _, name, apiPeerTypes, botIcons):
case let .attachMenuBot(attachMenuBotData):
let (apiFlags, _, name, apiPeerTypes, botIcons) = (attachMenuBotData.flags, attachMenuBotData.botId, attachMenuBotData.shortName, attachMenuBotData.peerTypes, attachMenuBotData.icons)
var icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile] = [:]
for icon in botIcons {
switch icon {
case let .attachMenuBotIcon(_, name, icon, _):
case let .attachMenuBotIcon(attachMenuBotIconData):
let (_, name, icon, _) = (attachMenuBotIconData.flags, attachMenuBotIconData.name, attachMenuBotIconData.icon, attachMenuBotIconData.colors)
if let iconName = AttachMenuBots.Bot.IconName(string: name), let icon = telegramMediaFileFromApiDocument(icon, altDocuments: []) {
icons[iconName] = icon
}
@@ -727,12 +733,12 @@ func _internal_getBotApp(account: Account, reference: BotAppReference) -> Signal
let app: Api.InputBotApp
switch reference {
case let .id(id, accessHash):
app = .inputBotAppID(id: id, accessHash: accessHash)
app = .inputBotAppID(.init(id: id, accessHash: accessHash))
case let .shortName(peerId, shortName):
guard let bot = transaction.getPeer(peerId), let inputBot = apiInputUser(bot) else {
return .fail(.generic)
}
app = .inputBotAppShortName(botId: inputBot, shortName: shortName)
app = .inputBotAppShortName(.init(botId: inputBot, shortName: shortName))
}
return account.network.request(Api.functions.messages.getBotApp(app: app, hash: 0))
@@ -741,9 +747,11 @@ func _internal_getBotApp(account: Account, reference: BotAppReference) -> Signal
}
|> mapToSignal { result -> Signal<BotApp, GetBotAppError> in
switch result {
case let .botApp(botAppFlags, app):
case let .botApp(botAppData):
let (botAppFlags, app) = (botAppData.flags, botAppData.app)
switch app {
case let .botApp(flags, id, accessHash, shortName, title, description, photo, document, hash):
case let .botApp(botAppData):
let (flags, id, accessHash, shortName, title, description, photo, document, hash) = (botAppData.flags, botAppData.id, botAppData.accessHash, botAppData.shortName, botAppData.title, botAppData.description, botAppData.photo, botAppData.document, botAppData.hash)
let _ = flags
var appFlags = BotApp.Flags()
if (botAppFlags & (1 << 0)) != 0 {
@@ -769,7 +777,8 @@ func _internal_getBotApp(account: Account, reference: BotAppReference) -> Signal
extension BotApp {
convenience init?(apiBotApp: Api.BotApp) {
switch apiBotApp {
case let .botApp(_, id, accessHash, shortName, title, description, photo, document, hash):
case let .botApp(botAppData):
let (id, accessHash, shortName, title, description, photo, document, hash) = (botAppData.id, botAppData.accessHash, botAppData.shortName, botAppData.title, botAppData.description, botAppData.photo, botAppData.document, botAppData.hash)
self.init(id: id, accessHash: accessHash, shortName: shortName, title: title, description: description, photo: telegramMediaImageFromApiPhoto(photo), document: document.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }, hash: hash, flags: [])
case .botAppNotModified:
return nil
@@ -19,7 +19,7 @@ public enum RequestSimpleWebViewSource : Equatable {
func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: PeerId, url: String?, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal<RequestWebViewResult, RequestWebViewError> {
var serializedThemeParams: Api.DataJSON?
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
serializedThemeParams = .dataJSON(data: dataString)
serializedThemeParams = .dataJSON(.init(data: dataString))
}
return postbox.transaction { transaction -> Signal<RequestWebViewResult, RequestWebViewError> in
guard let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else {
@@ -51,7 +51,8 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P
}
|> mapToSignal { result -> Signal<RequestWebViewResult, RequestWebViewError> in
switch result {
case let .webViewResultUrl(flags, queryId, url):
case let .webViewResultUrl(webViewResultUrlData):
let (flags, queryId, url) = (webViewResultUrlData.flags, webViewResultUrlData.queryId, webViewResultUrlData.url)
var resultFlags: RequestWebViewResult.Flags = []
if (flags & (1 << 1)) != 0 {
resultFlags.insert(.fullSize)
@@ -70,7 +71,7 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P
func _internal_requestMainWebView(postbox: Postbox, network: Network, peerId: PeerId, botId: PeerId, source: RequestSimpleWebViewSource, themeParams: [String: Any]?) -> Signal<RequestWebViewResult, RequestWebViewError> {
var serializedThemeParams: Api.DataJSON?
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
serializedThemeParams = .dataJSON(data: dataString)
serializedThemeParams = .dataJSON(.init(data: dataString))
}
return postbox.transaction { transaction -> Signal<RequestWebViewResult, RequestWebViewError> in
guard let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else {
@@ -101,7 +102,8 @@ func _internal_requestMainWebView(postbox: Postbox, network: Network, peerId: Pe
}
|> mapToSignal { result -> Signal<RequestWebViewResult, RequestWebViewError> in
switch result {
case let .webViewResultUrl(flags, queryId, url):
case let .webViewResultUrl(webViewResultUrlData):
let (flags, queryId, url) = (webViewResultUrlData.flags, webViewResultUrlData.queryId, webViewResultUrlData.url)
var resultFlags: RequestWebViewResult.Flags = []
if (flags & (1 << 1)) != 0 {
resultFlags.insert(.fullSize)
@@ -160,7 +162,7 @@ private func keepWebViewSignal(network: Network, stateManager: AccountStateManag
replyFlags |= 1 << 0
topMsgId = Int32(clamping: threadId)
}
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyToMessageId.id, topMsgId: topMsgId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil, monoforumPeerId: monoforumPeerId, todoItemId: nil)
replyTo = .inputReplyToMessage(.init(flags: replyFlags, replyToMsgId: replyToMessageId.id, topMsgId: topMsgId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil, monoforumPeerId: monoforumPeerId, todoItemId: nil))
}
let signal: Signal<Never, KeepWebViewError> = network.request(Api.functions.messages.prolongWebView(flags: flags, peer: peer, bot: bot, queryId: queryId, replyTo: replyTo, sendAs: sendAs))
|> mapError { _ -> KeepWebViewError in
@@ -204,7 +206,7 @@ private func keepWebViewSignal(network: Network, stateManager: AccountStateManag
func _internal_requestWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, botId: PeerId, url: String?, payload: String?, themeParams: [String: Any]?, fromMenu: Bool, replyToMessageId: MessageId?, threadId: Int64?) -> Signal<RequestWebViewResult, RequestWebViewError> {
var serializedThemeParams: Api.DataJSON?
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
serializedThemeParams = .dataJSON(data: dataString)
serializedThemeParams = .dataJSON(.init(data: dataString))
}
return postbox.transaction { transaction -> Signal<RequestWebViewResult, RequestWebViewError> in
@@ -248,9 +250,9 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager:
} else if topMsgId != nil {
replyFlags |= 1 << 0
}
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyToMessageId.id, topMsgId: topMsgId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil, monoforumPeerId: monoforumPeerId, todoItemId: nil)
replyTo = .inputReplyToMessage(.init(flags: replyFlags, replyToMsgId: replyToMessageId.id, topMsgId: topMsgId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil, monoforumPeerId: monoforumPeerId, todoItemId: nil))
} else if let monoforumPeerId {
replyTo = .inputReplyToMonoForum(monoforumPeerId: monoforumPeerId)
replyTo = .inputReplyToMonoForum(.init(monoforumPeerId: monoforumPeerId))
}
return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform, replyTo: replyTo, sendAs: nil))
@@ -259,7 +261,8 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager:
}
|> mapToSignal { result -> Signal<RequestWebViewResult, RequestWebViewError> in
switch result {
case let .webViewResultUrl(webViewFlags, queryId, url):
case let .webViewResultUrl(webViewResultUrlData):
let (webViewFlags, queryId, url) = (webViewResultUrlData.flags, webViewResultUrlData.queryId, webViewResultUrlData.url)
var resultFlags: RequestWebViewResult.Flags = []
if (webViewFlags & (1 << 1)) != 0 {
resultFlags.insert(.fullSize)
@@ -273,7 +276,7 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager:
} else {
keepAlive = nil
}
return .single(RequestWebViewResult(flags: resultFlags, queryId: queryId, url: url, keepAliveSignal: keepAlive))
}
}
@@ -309,7 +312,7 @@ func _internal_sendWebViewData(postbox: Postbox, network: Network, stateManager:
func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, compact: Bool, fullscreen: Bool, allowWrite: Bool) -> Signal<RequestWebViewResult, RequestWebViewError> {
var serializedThemeParams: Api.DataJSON?
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
serializedThemeParams = .dataJSON(data: dataString)
serializedThemeParams = .dataJSON(.init(data: dataString))
}
return postbox.transaction { transaction -> Signal<RequestWebViewResult, RequestWebViewError> in
@@ -320,12 +323,12 @@ func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManage
let app: Api.InputBotApp
switch appReference {
case let .id(id, accessHash):
app = .inputBotAppID(id: id, accessHash: accessHash)
app = .inputBotAppID(.init(id: id, accessHash: accessHash))
case let .shortName(peerId, shortName):
guard let bot = transaction.getPeer(peerId), let inputBot = apiInputUser(bot) else {
return .fail(.generic)
}
app = .inputBotAppShortName(botId: inputBot, shortName: shortName)
app = .inputBotAppShortName(.init(botId: inputBot, shortName: shortName))
}
var flags: Int32 = 0
@@ -351,7 +354,8 @@ func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManage
}
|> mapToSignal { result -> Signal<RequestWebViewResult, RequestWebViewError> in
switch result {
case let .webViewResultUrl(flags, queryId, url):
case let .webViewResultUrl(webViewResultUrlData):
let (flags, queryId, url) = (webViewResultUrlData.flags, webViewResultUrlData.queryId, webViewResultUrlData.url)
var resultFlags: RequestWebViewResult.Flags = []
if (flags & (1 << 1)) != 0 {
resultFlags.insert(.fullSize)
@@ -415,7 +419,7 @@ public enum InvokeBotCustomMethodError {
}
func _internal_invokeBotCustomMethod(postbox: Postbox, network: Network, botId: PeerId, method: String, params: String) -> Signal<String, InvokeBotCustomMethodError> {
let params = Api.DataJSON.dataJSON(data: params)
let params = Api.DataJSON.dataJSON(.init(data: params))
return postbox.transaction { transaction -> Signal<String, InvokeBotCustomMethodError> in
guard let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else {
return .fail(.generic)
@@ -425,7 +429,8 @@ func _internal_invokeBotCustomMethod(postbox: Postbox, network: Network, botId:
return .generic
}
|> map { result -> String in
if case let .dataJSON(data) = result {
if case let .dataJSON(dataJSONData) = result {
let data = dataJSONData.data
return data
} else {
return ""
@@ -1164,13 +1169,15 @@ fileprivate func _internal_requestConnectedStarRefBots(account: Account, id: En
}
return account.postbox.transaction { transaction -> (items: [EngineConnectedStarRefBotsContext.Item], totalCount: Int, nextOffset: (timestamp: Int32, link: String)?)? in
switch result {
case let .connectedStarRefBots(count, connectedBots, users):
case let .connectedStarRefBots(connectedStarRefBotsData):
let (count, connectedBots, users) = (connectedStarRefBotsData.count, connectedStarRefBotsData.connectedBots, connectedStarRefBotsData.users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
var items: [EngineConnectedStarRefBotsContext.Item] = []
for connectedBot in connectedBots {
switch connectedBot {
case let .connectedBotStarRef(_, url, date, botId, commissionPermille, durationMonths, participants, revenue):
case let .connectedBotStarRef(connectedBotStarRefData):
let (url, date, botId, commissionPermille, durationMonths, participants, revenue) = (connectedBotStarRefData.url, connectedBotStarRefData.date, connectedBotStarRefData.botId, connectedBotStarRefData.commissionPermille, connectedBotStarRefData.durationMonths, connectedBotStarRefData.participants, connectedBotStarRefData.revenue)
guard let botPeer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId))) else {
continue
}
@@ -1233,7 +1240,8 @@ fileprivate func _internal_requestSuggestedStarRefBots(account: Account, id: Eng
}
return account.postbox.transaction { transaction -> (items: [EngineSuggestedStarRefBotsContext.Item], totalCount: Int, nextOffset: String?)? in
switch result {
case let .suggestedStarRefBots(_, count, suggestedBots, users, nextOffset):
case let .suggestedStarRefBots(suggestedStarRefBotsData):
let (count, suggestedBots, users, nextOffset) = (suggestedStarRefBotsData.count, suggestedStarRefBotsData.suggestedBots, suggestedStarRefBotsData.users, suggestedStarRefBotsData.nextOffset)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
var items: [EngineSuggestedStarRefBotsContext.Item] = []
@@ -1278,12 +1286,14 @@ func _internal_connectStarRefBot(account: Account, id: EnginePeer.Id, botId: Eng
|> mapToSignal { result -> Signal<EngineConnectedStarRefBotsContext.Item, ConnectStarRefBotError> in
return account.postbox.transaction { transaction -> EngineConnectedStarRefBotsContext.Item? in
switch result {
case let .connectedStarRefBots(_, connectedBots, users):
case let .connectedStarRefBots(connectedStarRefBotsData):
let (connectedBots, users) = (connectedStarRefBotsData.connectedBots, connectedStarRefBotsData.users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
if let bot = connectedBots.first {
switch bot {
case let .connectedBotStarRef(_, url, date, botId, commissionPermille, durationMonths, participants, revenue):
case let .connectedBotStarRef(connectedBotStarRefData):
let (url, date, botId, commissionPermille, durationMonths, participants, revenue) = (connectedBotStarRefData.url, connectedBotStarRefData.date, connectedBotStarRefData.botId, connectedBotStarRefData.commissionPermille, connectedBotStarRefData.durationMonths, connectedBotStarRefData.participants, connectedBotStarRefData.revenue)
guard let botPeer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId))) else {
return nil
}
@@ -1333,9 +1343,10 @@ fileprivate func _internal_removeConnectedStarRefBot(account: Account, id: Engin
|> mapToSignal { result -> Signal<Never, ConnectStarRefBotError> in
return account.postbox.transaction { transaction -> Void in
switch result {
case let .connectedStarRefBots(_, connectedBots, users):
case let .connectedStarRefBots(connectedStarRefBotsData):
let (connectedBots, users) = (connectedStarRefBotsData.connectedBots, connectedStarRefBotsData.users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
let _ = connectedBots
}
@@ -1369,12 +1380,14 @@ func _internal_getStarRefBotConnection(account: Account, id: EnginePeer.Id, targ
}
return account.postbox.transaction { transaction -> EngineConnectedStarRefBotsContext.Item? in
switch result {
case let .connectedStarRefBots(_, connectedBots, users):
case let .connectedStarRefBots(connectedStarRefBotsData):
let (connectedBots, users) = (connectedStarRefBotsData.connectedBots, connectedStarRefBotsData.users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
if let bot = connectedBots.first {
switch bot {
case let .connectedBotStarRef(flags, url, date, botId, commissionPermille, durationMonths, participants, revenue):
case let .connectedBotStarRef(connectedBotStarRefData):
let (flags, url, date, botId, commissionPermille, durationMonths, participants, revenue) = (connectedBotStarRefData.flags, connectedBotStarRefData.url, connectedBotStarRefData.date, connectedBotStarRefData.botId, connectedBotStarRefData.commissionPermille, connectedBotStarRefData.durationMonths, connectedBotStarRefData.participants, connectedBotStarRefData.revenue)
let isRevoked = (flags & (1 << 1)) != 0
if isRevoked {
return nil
@@ -1431,9 +1444,19 @@ func _internal_getPossibleStarRefBotTargets(account: Account) -> Signal<[EngineP
if let apiChannels {
switch apiChannels {
case let .chats(chats), let .chatsSlice(_, chats):
case let .chats(chatsData):
let chats = chatsData.chats
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(chats: chats, users: []))
for chat in chats {
if let peer = transaction.getPeer(chat.peerId) {
result.append(EnginePeer(peer))
}
}
case let .chatsSlice(chatsSliceData):
let chats = chatsSliceData.chats
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(chats: chats, users: []))
for chat in chats {
if let peer = transaction.getPeer(chat.peerId) {
result.append(EnginePeer(peer))
@@ -15,12 +15,14 @@ func _internal_clearCloudDraftsInteractively(postbox: Postbox, network: Network,
}
var keys = Set<Key>()
switch updates {
case let .updates(updates, users, chats, _, _):
case let .updates(updatesData):
let (updates, users, chats) = (updatesData.updates, updatesData.users, updatesData.chats)
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
for update in updates {
switch update {
case let .updateDraftMessage(_, peer, topMsgId, savedPeerId, _):
case let .updateDraftMessage(updateDraftMessageData):
let (peer, topMsgId, savedPeerId) = (updateDraftMessageData.peer, updateDraftMessageData.topMsgId, updateDraftMessageData.savedPeerId)
var threadId: Int64?
if let savedPeerId {
threadId = savedPeerId.peerId.toInt64()
@@ -55,10 +57,10 @@ func _internal_clearCloudDraftsInteractively(postbox: Postbox, network: Network,
var innerFlags: Int32 = 0
innerFlags |= 1 << 0
replyTo = .inputReplyToMessage(flags: innerFlags, replyToMsgId: 0, topMsgId: topMsgId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil, monoforumPeerId: nil, todoItemId: nil)
replyTo = .inputReplyToMessage(.init(flags: innerFlags, replyToMsgId: 0, topMsgId: topMsgId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil, monoforumPeerId: nil, todoItemId: nil))
} else if let monoforumPeerId {
flags |= (1 << 0)
replyTo = .inputReplyToMonoForum(monoforumPeerId: monoforumPeerId)
replyTo = .inputReplyToMonoForum(.init(monoforumPeerId: monoforumPeerId))
}
signals.append(network.request(Api.functions.messages.saveDraft(flags: flags, replyTo: replyTo, peer: inputPeer, message: "", entities: nil, media: nil, effect: nil, suggestedPost: nil))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
@@ -129,7 +129,8 @@ func _internal_clearCallHistory(account: Account, forEveryone: Bool) -> Signal<N
|> mapToSignal { result -> Signal<Void, Bool> in
if let result = result {
switch result {
case let .affectedFoundMessages(pts, ptsCount, offset, _):
case let .affectedFoundMessages(affectedFoundMessagesData):
let (pts, ptsCount, offset) = (affectedFoundMessagesData.pts, affectedFoundMessagesData.ptsCount, affectedFoundMessagesData.offset)
account.stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
if offset == 0 {
return .fail(true)
@@ -219,7 +219,8 @@ func _internal_clearAuthorHistory(account: Account, peerId: PeerId, memberId: Pe
|> mapToSignal { result -> Signal<Void, Bool> in
if let result = result {
switch result {
case let .affectedHistory(pts, ptsCount, offset):
case let .affectedHistory(affectedHistoryData):
let (pts, ptsCount, offset) = (affectedHistoryData.pts, affectedHistoryData.ptsCount, affectedHistoryData.offset)
account.stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
if offset == 0 {
return .fail(true)
@@ -465,17 +465,19 @@ public final class EngineStoryViewListContext {
|> mapToSignal { result -> Signal<InternalState, NoError> in
return account.postbox.transaction { transaction -> InternalState in
switch result {
case let .storyViewsList(_, count, viewsCount, forwardsCount, reactionsCount, views, chats, users, nextOffset):
case let .storyViewsList(storyViewsListData):
let (count, viewsCount, forwardsCount, reactionsCount, views, chats, users, nextOffset) = (storyViewsListData.count, storyViewsListData.viewsCount, storyViewsListData.forwardsCount, storyViewsListData.reactionsCount, storyViewsListData.views, storyViewsListData.chats, storyViewsListData.users, storyViewsListData.nextOffset)
let peers = AccumulatedPeers(chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: peers)
var items: [Item] = []
for view in views {
switch view {
case let .storyView(flags, userId, date, reaction):
case let .storyView(storyViewData):
let (flags, userId, date, reaction) = (storyViewData.flags, storyViewData.userId, storyViewData.date, storyViewData.reaction)
let isBlocked = (flags & (1 << 0)) != 0
let isBlockedFromStories = (flags & (1 << 1)) != 0
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
let previousData: CachedUserData
@@ -511,7 +513,8 @@ public final class EngineStoryViewListContext {
}
)))
}
case let .storyViewPublicForward(flags, message):
case let .storyViewPublicForward(storyViewPublicForwardData):
let (flags, message) = (storyViewPublicForwardData.flags, storyViewPublicForwardData.message)
let _ = flags
if let storeMessage = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: false), let message = locallyRenderedMessage(message: storeMessage, peers: peers.peers) {
items.append(.forward(Item.Forward(
@@ -519,7 +522,8 @@ public final class EngineStoryViewListContext {
storyStats: transaction.getPeerStoryStats(peerId: message.id.peerId)
)))
}
case let .storyViewPublicRepost(flags, peerId, story):
case let .storyViewPublicRepost(storyViewPublicRepostData):
let (flags, peerId, story) = (storyViewPublicRepostData.flags, storyViewPublicRepostData.peerId, storyViewPublicRepostData.story)
let _ = flags
if let peer = transaction.getPeer(peerId.peerId) {
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peer.id, transaction: transaction), case let .item(item) = storedItem, let media = item.media {
@@ -685,14 +689,16 @@ public final class EngineStoryViewListContext {
|> mapToSignal { result -> Signal<InternalState, NoError> in
return account.postbox.transaction { transaction -> InternalState in
switch result {
case let .storyReactionsList(_, count, reactions, chats, users, nextOffset):
case let .storyReactionsList(storyReactionsListData):
let (count, reactions, chats, users, nextOffset) = (storyReactionsListData.count, storyReactionsListData.reactions, storyReactionsListData.chats, storyReactionsListData.users, storyReactionsListData.nextOffset)
let peers = AccumulatedPeers(chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: peers)
var items: [Item] = []
for reaction in reactions {
switch reaction {
case let .storyReaction(peerId, date, reaction):
case let .storyReaction(storyReactionData):
let (peerId, date, reaction) = (storyReactionData.peerId, storyReactionData.date, storyReactionData.reaction)
if let peer = transaction.getPeer(peerId.peerId) {
if let parsedReaction = MessageReaction.Reaction(apiReaction: reaction) {
let reactionFile: TelegramMediaFile?
@@ -713,14 +719,16 @@ public final class EngineStoryViewListContext {
)))
}
}
case let .storyReactionPublicForward(message):
case let .storyReactionPublicForward(storyReactionPublicForwardData):
let message = storyReactionPublicForwardData.message
if let storeMessage = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: false), let message = locallyRenderedMessage(message: storeMessage, peers: peers.peers) {
items.append(.forward(Item.Forward(
message: EngineMessage(message),
storyStats: transaction.getPeerStoryStats(peerId: message.id.peerId)
)))
}
case let .storyReactionPublicRepost(peerId, story):
case let .storyReactionPublicRepost(storyReactionPublicRepostData):
let (peerId, story) = (storyReactionPublicRepostData.peerId, storyReactionPublicRepostData.story)
if let peer = transaction.getPeer(peerId.peerId) {
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peer.id, transaction: transaction), case let .item(item) = storedItem, let media = item.media {
items.append(.repost(Item.Repost(
@@ -25,7 +25,8 @@ public func _internal_exportMessageLink(postbox: Postbox, network: Network, peer
return network.request(Api.functions.channels.exportMessageLink(flags: flags, channel: input, id: sourceMessageId.id)) |> mapError { _ in return }
|> map { res in
switch res {
case let .exportedMessageLink(link, _):
case let .exportedMessageLink(exportedMessageLinkData):
let (link, _) = (exportedMessageLinkData.link, exportedMessageLinkData.html)
return link
}
} |> `catch` { _ -> Signal<String?, NoError> in
@@ -16,10 +16,10 @@ func _internal_editMessageFactCheck(account: Account, messageId: EngineMessage.I
return account.network.request(Api.functions.messages.editFactCheck(
peer: inputPeer,
msgId: messageId.id,
text: .textWithEntities(
text: .textWithEntities(.init(
text: text,
entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())
)
))
))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
@@ -96,11 +96,13 @@ func _internal_getMessagesFactCheckByPeerId(account: Account, peerId: EnginePeer
for result in results {
let messageId = messageIds[index]
switch result {
case let .factCheck(_, country, text, hash):
case let .factCheck(factCheckData):
let (_, country, text, hash) = (factCheckData.flags, factCheckData.country, factCheckData.text, factCheckData.hash)
let content: FactCheckMessageAttribute.Content
if let text, let country {
switch text {
case let .textWithEntities(text, entities):
case let .textWithEntities(textWithEntitiesData):
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
content = .Loaded(text: text, entities: messageTextEntitiesFromApiEntities(entities), country: country)
}
} else {
@@ -61,20 +61,23 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po
if let peer = supportPeers[peerId] {
var signal: Signal<Api.messages.Messages, MTRpcError>?
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup {
signal = network.request(Api.functions.messages.getMessages(id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) })))
signal = network.request(Api.functions.messages.getMessages(id: messageIds.map({ Api.InputMessage.inputMessageID(.init(id: $0.id)) })))
} else if peerId.namespace == Namespaces.Peer.CloudChannel {
if let inputChannel = apiInputChannel(peer) {
signal = network.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) })))
signal = network.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.map({ Api.InputMessage.inputMessageID(.init(id: $0.id)) })))
}
}
if let signal = signal {
signals.append(signal |> map { result in
switch result {
case let .messages(messages, _, chats, users):
case let .messages(messagesData):
let (messages, _, chats, users) = (messagesData.messages, messagesData.topics, messagesData.chats, messagesData.users)
return (peer, messages, chats, users)
case let .messagesSlice(_, _, _, _, _, messages, _, chats, users):
case let .messagesSlice(messagesSliceData):
let (_, _, _, _, _, messages, _, chats, users) = (messagesSliceData.flags, messagesSliceData.count, messagesSliceData.nextRate, messagesSliceData.offsetIdOffset, messagesSliceData.searchFlood, messagesSliceData.messages, messagesSliceData.topics, messagesSliceData.chats, messagesSliceData.users)
return (peer, messages, chats, users)
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
case let .channelMessages(channelMessagesData):
let (_, _, _, _, messages, apiTopics, chats, users) = (channelMessagesData.flags, channelMessagesData.pts, channelMessagesData.count, channelMessagesData.offsetIdOffset, channelMessagesData.messages, channelMessagesData.topics, channelMessagesData.chats, channelMessagesData.users)
let _ = apiTopics
return (peer, messages, chats, users)
case .messagesNotModified:
@@ -20,7 +20,8 @@ func _internal_markAllChatsAsRead(postbox: Postbox, network: Network, stateManag
var signals: [Signal<Void, NoError>] = []
for peer in result {
switch peer {
case let .dialogPeer(peer):
case let .dialogPeer(dialogPeerData):
let peer = dialogPeerData.peer
let peerId = peer.peerId
if peerId.namespace == Namespaces.Peer.CloudChannel {
if let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) {
@@ -42,7 +43,8 @@ func _internal_markAllChatsAsRead(postbox: Postbox, network: Network, stateManag
|> mapToSignal { result -> Signal<Void, NoError> in
if let result = result {
switch result {
case let .affectedMessages(pts, ptsCount):
case let .affectedMessages(affectedMessagesData):
let (pts, ptsCount) = (affectedMessagesData.pts, affectedMessagesData.ptsCount)
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
}
}
@@ -37,7 +37,8 @@ func _internal_messageReadStats(account: Account, id: MessageId) -> Signal<Messa
return MessageReadStats(reactionCount: 0, peers: [], readTimestamps: [:])
}
switch result {
case let .outboxReadDate(date):
case let .outboxReadDate(outboxReadDateData):
let date = outboxReadDateData.date
return MessageReadStats(reactionCount: 0, peers: [EnginePeer(peer)], readTimestamps: [peer.id: date])
}
}
@@ -47,7 +48,8 @@ func _internal_messageReadStats(account: Account, id: MessageId) -> Signal<Messa
var items: [(Int64, Int32)] = []
for item in result {
switch item {
case let .readParticipantDate(userId, date):
case let .readParticipantDate(readParticipantDateData):
let (userId, date) = (readParticipantDateData.userId, readParticipantDateData.date)
items.append((userId, date))
}
}
@@ -60,7 +62,8 @@ func _internal_messageReadStats(account: Account, id: MessageId) -> Signal<Messa
let reactionCount: Signal<Int, NoError> = account.network.request(Api.functions.messages.getMessageReactionsList(flags: 0, peer: inputPeer, id: id.id, reaction: nil, offset: nil, limit: 1))
|> map { result -> Int in
switch result {
case let .messageReactionsList(_, count, _, _, _, _):
case let .messageReactionsList(messageReactionsListData):
let count = messageReactionsListData.count
return Int(count)
}
}
@@ -23,15 +23,18 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa
return account.postbox.transaction { transaction -> TelegramMediaPoll? in
var resultPoll: TelegramMediaPoll?
switch result {
case let .updates(updates, _, _, _, _):
case let .updates(updatesData):
let updates = updatesData.updates
for update in updates {
switch update {
case let .updateMessagePoll(_, id, poll, results):
case let .updateMessagePoll(updateMessagePollData):
let (id, poll, results) = (updateMessagePollData.pollId, updateMessagePollData.poll, updateMessagePollData.results)
let pollId = MediaId(namespace: Namespaces.Media.CloudPoll, id: id)
resultPoll = transaction.getMedia(pollId) as? TelegramMediaPoll
if let poll = poll {
switch poll {
case let .poll(_, flags, question, answers, closePeriod, _):
case let .poll(pollData):
let (flags, question, answers, closePeriod) = (pollData.flags, pollData.question, pollData.answers, pollData.closePeriod)
let publicity: TelegramMediaPollPublicity
if (flags & (1 << 1)) != 0 {
publicity = .public
@@ -47,7 +50,8 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa
let questionText: String
let questionEntities: [MessageTextEntity]
switch question {
case let .textWithEntities(text, entities):
case let .textWithEntities(textWithEntitiesData):
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
questionText = text
questionEntities = messageTextEntitiesFromApiEntities(entities)
}
@@ -57,7 +61,8 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa
let resultsMin: Bool
switch results {
case let .pollResults(flags, _, _, _, _, _):
case let .pollResults(pollResultsData):
let flags = pollResultsData.flags
resultsMin = (flags & (1 << 0)) != 0
}
resultPoll = resultPoll?.withUpdatedResults(TelegramMediaPollResults(apiResults: results), min: resultsMin)
@@ -142,7 +147,7 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager
pollMediaFlags |= 1 << 1
}
return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(flags: pollMediaFlags, poll: .poll(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary())), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil), correctAnswers: correctAnswers, solution: mappedSolution, solutionEntities: mappedSolutionEntities), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil))
return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(.init(flags: pollMediaFlags, poll: .poll(.init(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, solution: mappedSolution, solutionEntities: mappedSolutionEntities)), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
@@ -280,18 +285,22 @@ private final class PollResultsOptionContext {
return ([], 0, nil)
}
switch result {
case let .votesList(_, count, votes, chats, users, nextOffset):
case let .votesList(votesListData):
let (count, votes, chats, users, nextOffset) = (votesListData.count, votesListData.votes, votesListData.chats, votesListData.users, votesListData.nextOffset)
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
var resultPeers: [RenderedPeer] = []
for vote in votes {
let peerId: PeerId
switch vote {
case let .messagePeerVote(peerIdValue, _, _):
case let .messagePeerVote(messagePeerVoteData):
let peerIdValue = messagePeerVoteData.peer
peerId = peerIdValue.peerId
case let .messagePeerVoteInputOption(peerIdValue, _):
case let .messagePeerVoteInputOption(messagePeerVoteInputOptionData):
let peerIdValue = messagePeerVoteInputOptionData.peer
peerId = peerIdValue.peerId
case let .messagePeerVoteMultiple(peerIdValue, _, _):
case let .messagePeerVoteMultiple(messagePeerVoteMultipleData):
let peerIdValue = messagePeerVoteMultipleData.peer
peerId = peerIdValue.peerId
}
if let peer = transaction.getPeer(peerId) {
@@ -30,7 +30,8 @@ func _internal_getPreparedInlineMessage(account: Account, botId: EnginePeer.Id,
}
return account.postbox.transaction { transaction -> PreparedInlineMessage? in
switch result {
case let .preparedInlineMessage(queryId, result, apiPeerTypes, cacheTime, users):
case let .preparedInlineMessage(preparedInlineMessageData):
let (queryId, result, apiPeerTypes, cacheTime, users) = (preparedInlineMessageData.queryId, preparedInlineMessageData.result, preparedInlineMessageData.peerTypes, preparedInlineMessageData.cacheTime, preparedInlineMessageData.users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: users))
let _ = cacheTime
return PreparedInlineMessage(
@@ -152,7 +152,8 @@ func _internal_keepShortcutMessagesUpdated(account: Account) -> Signal<Never, No
return account.postbox.transaction { transaction in
var state = transaction.getPreferencesEntry(key: PreferencesKeys.shortcutMessages())?.get(QuickReplyMessageShortcutsState.self) ?? QuickReplyMessageShortcutsState(shortcuts: [])
switch result {
case let .quickReplies(quickReplies, messages, chats, users):
case let .quickReplies(quickRepliesData):
let (quickReplies, messages, chats, users) = (quickRepliesData.quickReplies, quickRepliesData.messages, quickRepliesData.chats, quickRepliesData.users)
let previousShortcuts = state.shortcuts
state.shortcuts.removeAll()
@@ -171,7 +172,8 @@ func _internal_keepShortcutMessagesUpdated(account: Account) -> Signal<Never, No
for quickReply in quickReplies {
switch quickReply {
case let .quickReply(shortcutId, shortcut, topMessage, _):
case let .quickReply(quickReplyData):
let (shortcutId, shortcut, topMessage, _) = (quickReplyData.shortcutId, quickReplyData.shortcut, quickReplyData.topMessage, quickReplyData.count)
state.shortcuts.append(QuickReplyMessageShortcut(
id: shortcutId,
shortcut: shortcut
@@ -543,7 +545,8 @@ public final class TelegramBusinessGreetingMessage: Codable, Equatable {
extension TelegramBusinessGreetingMessage {
convenience init(apiGreetingMessage: Api.BusinessGreetingMessage) {
switch apiGreetingMessage {
case let .businessGreetingMessage(shortcutId, recipients, noActivityDays):
case let .businessGreetingMessage(businessGreetingMessageData):
let (shortcutId, recipients, noActivityDays) = (businessGreetingMessageData.shortcutId, businessGreetingMessageData.recipients, businessGreetingMessageData.noActivityDays)
self.init(
shortcutId: shortcutId,
recipients: TelegramBusinessRecipients(apiValue: recipients),
@@ -715,14 +718,16 @@ public final class TelegramBusinessIntro: Codable, Equatable {
extension TelegramBusinessAwayMessage {
convenience init(apiAwayMessage: Api.BusinessAwayMessage) {
switch apiAwayMessage {
case let .businessAwayMessage(flags, shortcutId, schedule, recipients):
case let .businessAwayMessage(businessAwayMessageData):
let (flags, shortcutId, schedule, recipients) = (businessAwayMessageData.flags, businessAwayMessageData.shortcutId, businessAwayMessageData.schedule, businessAwayMessageData.recipients)
let mappedSchedule: Schedule
switch schedule {
case .businessAwayMessageScheduleAlways:
mappedSchedule = .always
case .businessAwayMessageScheduleOutsideWorkHours:
mappedSchedule = .outsideWorkingHours
case let .businessAwayMessageScheduleCustom(startDate, endDate):
case let .businessAwayMessageScheduleCustom(businessAwayMessageScheduleCustomData):
let (startDate, endDate) = (businessAwayMessageScheduleCustomData.startDate, businessAwayMessageScheduleCustomData.endDate)
mappedSchedule = .custom(beginTimestamp: startDate, endTimestamp: endDate)
}
@@ -741,7 +746,9 @@ extension TelegramBusinessAwayMessage {
extension TelegramBusinessIntro {
convenience init(apiBusinessIntro: Api.BusinessIntro) {
switch apiBusinessIntro {
case let .businessIntro(_, title, description, sticker):
case let .businessIntro(businessIntroData):
let (flags, title, description, sticker) = (businessIntroData.flags, businessIntroData.title, businessIntroData.description, businessIntroData.sticker)
let _ = flags
self.init(title: title, text: description, stickerFile: sticker.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: []) })
}
}
@@ -752,15 +759,15 @@ extension TelegramBusinessIntro {
if let stickerFile = self.stickerFile {
if let fileResource = stickerFile.resource as? CloudDocumentMediaResource, let resource = stickerFile.resource as? TelegramCloudMediaResourceWithFileReference, let reference = resource.fileReference {
flags |= 1 << 0
sticker = .inputDocument(id: fileResource.fileId, accessHash: fileResource.accessHash, fileReference: Buffer(data: reference))
sticker = .inputDocument(.init(id: fileResource.fileId, accessHash: fileResource.accessHash, fileReference: Buffer(data: reference)))
}
}
return .inputBusinessIntro(
return .inputBusinessIntro(.init(
flags: flags,
title: self.title,
description: self.text,
sticker: sticker
)
))
}
}
@@ -768,7 +775,8 @@ extension TelegramBusinessBotRights {
init(apiValue: Api.BusinessBotRights) {
var value: TelegramBusinessBotRights = []
switch apiValue {
case let .businessBotRights(flags):
case let .businessBotRights(businessBotRightsData):
let flags = businessBotRightsData.flags
if (flags & (1 << 0)) != 0 {
value.insert(.reply)
}
@@ -820,7 +828,8 @@ extension TelegramBusinessBotRights {
extension TelegramBusinessRecipients {
convenience init(apiValue: Api.BusinessRecipients) {
switch apiValue {
case let .businessRecipients(flags, users):
case let .businessRecipients(businessRecipientsData):
let (flags, users) = (businessRecipientsData.flags, businessRecipientsData.users)
var categories: Categories = []
if (flags & (1 << 0)) != 0 {
categories.insert(.existingChats)
@@ -846,7 +855,8 @@ extension TelegramBusinessRecipients {
convenience init(apiValue: Api.BusinessBotRecipients) {
switch apiValue {
case let .businessBotRecipients(flags, users, excludeUsers):
case let .businessBotRecipients(businessBotRecipientsData):
let (flags, users, excludeUsers) = (businessBotRecipientsData.flags, businessBotRecipientsData.users, businessBotRecipientsData.excludeUsers)
var categories: Categories = []
if (flags & (1 << 0)) != 0 {
categories.insert(.existingChats)
@@ -897,7 +907,7 @@ extension TelegramBusinessRecipients {
flags |= 1 << 4
}
return .inputBusinessRecipients(flags: flags, users: users)
return .inputBusinessRecipients(.init(flags: flags, users: users))
}
func apiInputBotValue(additionalPeers: [Peer], excludePeers: [Peer]) -> Api.InputBusinessBotRecipients {
@@ -934,7 +944,7 @@ extension TelegramBusinessRecipients {
flags |= 1 << 6
}
return .inputBusinessBotRecipients(flags: flags, users: users, excludeUsers: excludeUsers)
return .inputBusinessBotRecipients(.init(flags: flags, users: users, excludeUsers: excludeUsers))
}
}
@@ -948,11 +958,11 @@ func _internal_updateBusinessGreetingMessage(account: Account, greetingMessage:
|> mapToSignal { additionalPeers in
var mappedMessage: Api.InputBusinessGreetingMessage?
if let greetingMessage {
mappedMessage = .inputBusinessGreetingMessage(
mappedMessage = .inputBusinessGreetingMessage(.init(
shortcutId: greetingMessage.shortcutId,
recipients: greetingMessage.recipients.apiInputValue(additionalPeers: additionalPeers),
noActivityDays: Int32(clamping: greetingMessage.inactivityDays)
)
))
}
var flags: Int32 = 0
@@ -997,7 +1007,7 @@ func _internal_updateBusinessAwayMessage(account: Account, awayMessage: Telegram
case .outsideWorkingHours:
mappedSchedule = .businessAwayMessageScheduleOutsideWorkHours
case let .custom(beginTimestamp, endTimestamp):
mappedSchedule = .businessAwayMessageScheduleCustom(startDate: beginTimestamp, endDate: endTimestamp)
mappedSchedule = .businessAwayMessageScheduleCustom(Api.BusinessAwayMessageSchedule.Cons_businessAwayMessageScheduleCustom(startDate: beginTimestamp, endDate: endTimestamp))
}
var flags: Int32 = 0
@@ -1005,12 +1015,12 @@ func _internal_updateBusinessAwayMessage(account: Account, awayMessage: Telegram
flags |= 1 << 0
}
mappedMessage = .inputBusinessAwayMessage(
mappedMessage = .inputBusinessAwayMessage(.init(
flags: flags,
shortcutId: awayMessage.shortcutId,
schedule: mappedSchedule,
recipients: awayMessage.recipients.apiInputValue(additionalPeers: additionalPeers)
)
))
}
var flags: Int32 = 0
@@ -1169,7 +1179,7 @@ public func _internal_setAccountConnectedBot(account: Account, bot: TelegramAcco
var flags: Int32 = 0
var mappedRights: Api.BusinessBotRights?
var mappedBot: Api.InputUser = .inputUserEmpty
var mappedRecipients: Api.InputBusinessBotRecipients = .inputBusinessBotRecipients(flags: 0, users: nil, excludeUsers: nil)
var mappedRecipients: Api.InputBusinessBotRecipients = .inputBusinessBotRecipients(.init(flags: 0, users: nil, excludeUsers: nil))
if let bot, let inputBotUser = botUser.flatMap(apiInputUser) {
mappedBot = inputBotUser
@@ -1219,7 +1229,7 @@ public func _internal_setAccountConnectedBot(account: Account, bot: TelegramAcco
if bot.rights.contains(.manageStories) {
rightsFlags |= (1 << 13)
}
mappedRights = .businessBotRights(flags: rightsFlags)
mappedRights = .businessBotRights(Api.BusinessBotRights.Cons_businessBotRights(flags: rightsFlags))
mappedRecipients = bot.recipients.apiInputBotValue(additionalPeers: additionalPeers, excludePeers: excludePeers)
} else {
flags |= 1 << 1
@@ -156,7 +156,8 @@ private class ReplyThreadHistoryContextImpl {
|> mapToSignal { discussionMessage -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
return account.postbox.transaction { transaction -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
switch discussionMessage {
case let .discussionMessage(_, messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users):
case let .discussionMessage(discussionMessageData):
let (messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users) = (discussionMessageData.messages, discussionMessageData.maxId, discussionMessageData.readInboxMaxId, discussionMessageData.readOutboxMaxId, discussionMessageData.unreadCount, discussionMessageData.chats, discussionMessageData.users)
let parsedMessages = messages.compactMap { message -> StoreMessage? in
StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForumOrMonoForum)
}
@@ -476,7 +477,8 @@ private class ReplyThreadHistoryContextImpl {
let validateSignal = strongSelf.account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: Int32(clamping: threadId)))
|> map { result -> (MessageId?, Int) in
switch result {
case let .discussionMessage(_, _, _, readInboxMaxId, _, unreadCount, _, _):
case let .discussionMessage(discussionMessageData):
let (readInboxMaxId, unreadCount) = (discussionMessageData.readInboxMaxId, discussionMessageData.unreadCount)
return (readInboxMaxId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }), Int(unreadCount))
}
}
@@ -670,7 +672,8 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
}
return account.postbox.transaction { transaction -> DiscussionMessage? in
switch discussionMessage {
case let .discussionMessage(_, messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users):
case let .discussionMessage(discussionMessageData):
let (messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users) = (discussionMessageData.messages, discussionMessageData.maxId, discussionMessageData.readInboxMaxId, discussionMessageData.readOutboxMaxId, discussionMessageData.unreadCount, discussionMessageData.chats, discussionMessageData.users)
let parsedMessages = messages.compactMap { message -> StoreMessage? in
StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peer.isForumOrMonoForum)
}
@@ -29,10 +29,12 @@ func _internal_reportAdMessage(account: Account, opaqueId: Data, option: Data?)
}
|> map { result -> ReportAdMessageResult in
switch result {
case let .sponsoredMessageReportResultChooseOption(title, options):
case let .sponsoredMessageReportResultChooseOption(sponsoredMessageReportResultChooseOptionData):
let (title, options) = (sponsoredMessageReportResultChooseOptionData.title, sponsoredMessageReportResultChooseOptionData.options)
return .options(title: title, options: options.map {
switch $0 {
case let .sponsoredMessageReportOption(text, option):
case let .sponsoredMessageReportOption(sponsoredMessageReportOptionData):
let (text, option) = (sponsoredMessageReportOptionData.text, sponsoredMessageReportOptionData.option)
return ReportAdMessageResult.Option(text: text, option: option.makeData())
}
})
@@ -63,14 +63,17 @@ func _internal_reportContent(account: Account, subject: ReportContentSubject, op
}
|> map { result -> ReportContentResult in
switch result {
case let .reportResultChooseOption(title, options):
case let .reportResultChooseOption(reportResultChooseOptionData):
let (title, options) = (reportResultChooseOptionData.title, reportResultChooseOptionData.options)
return .options(title: title, options: options.map {
switch $0 {
case let .messageReportOption(text, option):
case let .messageReportOption(messageReportOptionData):
let (text, option) = (messageReportOptionData.text, messageReportOptionData.option)
return ReportContentResult.Option(text: text, option: option.makeData())
}
})
case let .reportResultAddComment(flags, option):
case let .reportResultAddComment(reportResultAddCommentData):
let (flags, option) = (reportResultAddCommentData.flags, reportResultAddCommentData.option)
return .addComment(optional: (flags & (1 << 0)) != 0, option: option.makeData())
case .reportResultReported:
return .reported
@@ -1,3 +1,4 @@
import SGLogging
import Foundation
import Postbox
import SwiftSignalKit
@@ -52,7 +53,7 @@ public struct RequestChatContextResultsResult {
}
}
func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String, incompleteResults: Bool = false, staleCachedResults: Bool = false) -> Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> {
func _internal_requestChatContextResults(IQTP: Bool = false, account: Account, botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String, incompleteResults: Bool = false, staleCachedResults: Bool = false) -> Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> {
return account.postbox.transaction { transaction -> (bot: Peer, peer: Peer)? in
if let bot = transaction.getPeer(botId), let peer = transaction.getPeer(peerId) {
return (bot, peer)
@@ -119,7 +120,7 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId
if let (latitude, longitude) = location {
flags |= (1 << 0)
let geoPointFlags: Int32 = 0
geoPoint = Api.InputGeoPoint.inputGeoPoint(flags: geoPointFlags, lat: latitude, long: longitude, accuracyRadius: nil)
geoPoint = Api.InputGeoPoint.inputGeoPoint(.init(flags: geoPointFlags, lat: latitude, long: longitude, accuracyRadius: nil))
}
var signal: Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> = account.network.request(Api.functions.messages.getInlineBotResults(flags: flags, bot: inputBot, peer: inputPeer, geoPoint: geoPoint, query: query, offset: offset))
@@ -127,6 +128,10 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId
return ChatContextResultCollection(apiResults: result, botId: bot.id, peerId: peerId, query: query, geoPoint: location)
}
|> mapError { error -> RequestChatContextResultsError in
// MARK: Swiftgram
if IQTP {
SGLogger.shared.log("SGIQTP", "Error requesting inline results: \(error.errorDescription ?? "nil")")
}
if error.errorDescription == "BOT_INLINE_GEO_REQUIRED" {
return .locationRequired
} else {
@@ -104,7 +104,7 @@ func _internal_requestMessageActionCallback(account: Account, messageId: Message
guard let kdfResult = passwordKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic)
}
return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)))
return .single(.inputCheckPasswordSRP(.init(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))))
} else {
return .fail(.twoStepAuthMissing)
}
@@ -146,7 +146,8 @@ func _internal_requestMessageActionCallback(account: Account, messageId: Message
return .none
}
switch result {
case let .botCallbackAnswer(flags, message, url, _):
case let .botCallbackAnswer(botCallbackAnswerData):
let (flags, message, url) = (botCallbackAnswerData.flags, botCallbackAnswerData.message, botCallbackAnswerData.url)
if let message = message {
if (flags & (1 << 1)) != 0 {
return .alert(message)
@@ -168,9 +169,39 @@ func _internal_requestMessageActionCallback(account: Account, messageId: Message
}
public enum MessageActionUrlAuthResult {
public struct Flags: OptionSet {
public var rawValue: Int32
public init(rawValue: Int32) {
self.rawValue = rawValue
}
public static let requestWriteAccess = Flags(rawValue: 1 << 0)
public static let requestPhoneNumber = Flags(rawValue: 1 << 1)
}
public struct ClientData : Equatable {
public let browser: String
public let platform: String
public let ip: String
public let region: String
public init(browser: String, platform: String, ip: String, region: String) {
self.browser = browser
self.platform = platform
self.ip = ip
self.region = region
}
}
case `default`
case accepted(String)
case request(String, Peer, Bool)
case accepted(url: String?)
case request(domain: String, bot: Peer, clientData: ClientData?, flags: Flags)
}
public enum MessageActionUrlAuthError {
case generic
case urlExpired
}
public enum MessageActionUrlSubject {
@@ -212,19 +243,35 @@ func _internal_requestMessageActionUrlAuth(account: Account, subject: MessageAct
switch result {
case .urlAuthResultDefault:
return .default
case let .urlAuthResultAccepted(url):
return .accepted(url)
case let .urlAuthResultRequest(flags, bot, domain):
return .request(domain, TelegramUser(user: bot), (flags & (1 << 0)) != 0)
case let .urlAuthResultAccepted(urlAuthResultAcceptedData):
let url = urlAuthResultAcceptedData.url
return .accepted(url: url)
case let .urlAuthResultRequest(urlAuthResultRequestData):
let (apiFlags, bot, domain) = (urlAuthResultRequestData.flags, urlAuthResultRequestData.bot, urlAuthResultRequestData.domain)
var clientData: MessageActionUrlAuthResult.ClientData?
if let browser = urlAuthResultRequestData.browser, let platform = urlAuthResultRequestData.platform, let ip = urlAuthResultRequestData.ip, let region = urlAuthResultRequestData.region {
clientData = MessageActionUrlAuthResult.ClientData(browser: browser, platform: platform, ip: ip, region: region)
}
var flags: MessageActionUrlAuthResult.Flags = []
if (apiFlags & (1 << 0)) != 0 {
flags.insert(.requestWriteAccess)
}
if (apiFlags & (1 << 1)) != 0 {
flags.insert(.requestPhoneNumber)
}
return .request(domain: domain, bot: TelegramUser(user: bot), clientData: clientData, flags: flags)
}
}
}
func _internal_acceptMessageActionUrlAuth(account: Account, subject: MessageActionUrlSubject, allowWriteAccess: Bool) -> Signal<MessageActionUrlAuthResult, NoError> {
func _internal_acceptMessageActionUrlAuth(account: Account, subject: MessageActionUrlSubject, allowWriteAccess: Bool, sharePhoneNumber: Bool) -> Signal<MessageActionUrlAuthResult, MessageActionUrlAuthError> {
var flags: Int32 = 0
if allowWriteAccess {
flags |= Int32(1 << 0)
}
if sharePhoneNumber {
flags |= Int32(1 << 3)
}
let request: Signal<Api.UrlAuthResult?, MTRpcError>
switch subject {
@@ -250,16 +297,14 @@ func _internal_acceptMessageActionUrlAuth(account: Account, subject: MessageActi
return request
|> `catch` { _ -> Signal<Api.UrlAuthResult?, NoError> in
return .single(nil)
|> mapError { _ -> MessageActionUrlAuthError in
return .generic
}
|> map { result -> MessageActionUrlAuthResult in
guard let result = result else {
return .default
}
switch result {
case let .urlAuthResultAccepted(url):
return .accepted(url)
case let .urlAuthResultAccepted(urlAuthResultAcceptedData):
let url = urlAuthResultAcceptedData.url
return .accepted(url: url)
default:
return .default
}
@@ -88,26 +88,30 @@ private func mergedState(transaction: Transaction, seedConfiguration: SeedConfig
let totalCount: Int32
let nextRate: Int32?
switch result {
case let .channelMessages(_, _, count, _, apiMessages, apiTopics, apiChats, apiUsers):
case let .channelMessages(channelMessagesData):
let (_, _, count, _, apiMessages, apiTopics, apiChats, apiUsers) = (channelMessagesData.flags, channelMessagesData.pts, channelMessagesData.count, channelMessagesData.offsetIdOffset, channelMessagesData.messages, channelMessagesData.topics, channelMessagesData.chats, channelMessagesData.users)
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
totalCount = count
nextRate = nil
case let .messages(apiMessages, _, apiChats, apiUsers):
case let .messages(messagesData):
let (apiMessages, _, apiChats, apiUsers) = (messagesData.messages, messagesData.topics, messagesData.chats, messagesData.users)
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = Int32(messages.count)
nextRate = nil
case let .messagesSlice(_, count, apiNextRate, _, _, apiMessages, _, apiChats, apiUsers):
case let .messagesSlice(messagesSliceData):
let (_, count, apiNextRate, _, _, apiMessages, _, apiChats, apiUsers) = (messagesSliceData.flags, messagesSliceData.count, messagesSliceData.nextRate, messagesSliceData.offsetIdOffset, messagesSliceData.searchFlood, messagesSliceData.messages, messagesSliceData.topics, messagesSliceData.chats, messagesSliceData.users)
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = count
nextRate = apiNextRate
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
chats = []
users = []
@@ -282,13 +286,17 @@ func _internal_getSearchMessageCount(account: Account, location: SearchMessagesL
return account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromPeer, savedPeerId: savedPeerId, savedReaction: nil, topMsgId: topMsgId, filter: .inputMessagesFilterEmpty, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> Int? in
switch result {
case let .channelMessages(_, _, count, _, _, _, _, _):
case let .channelMessages(channelMessagesData):
let count = channelMessagesData.count
return Int(count)
case let .messages(messages, _, _, _):
case let .messages(messagesData):
let messages = messagesData.messages
return messages.count
case let .messagesNotModified(count):
case let .messagesNotModified(messagesNotModifiedData):
let count = messagesNotModifiedData.count
return Int(count)
case let .messagesSlice(_, count, _, _, _, _, _, _, _):
case let .messagesSlice(messagesSliceData):
let count = messagesSliceData.count
return Int(count)
}
}
@@ -298,7 +306,7 @@ func _internal_getSearchMessageCount(account: Account, location: SearchMessagesL
}
}
func _internal_searchMessages(account: Account, location: SearchMessagesLocation, query: String, state: SearchMessagesState?, centerId: MessageId?, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> {
func _internal_searchMessages(account: Account, location: SearchMessagesLocation, query: String, state: SearchMessagesState?, centerId: MessageId?, limit: Int32 = 100, forceLocal: Bool = false) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> {
if case let .peer(peerId, fromId, tags, reactions, threadId, minDate, maxDate) = location, fromId == nil, tags == nil, peerId == account.peerId, let reactions, let reaction = reactions.first, (minDate == nil || minDate == 0), (maxDate == nil || maxDate == 0) {
return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
let messages = transaction.getMessagesWithCustomTag(peerId: peerId, namespace: Namespaces.Message.Cloud, threadId: threadId, customTag: ReactionsMessageAttribute.messageTag(reaction: reaction), from: MessageIndex.upperBound(peerId: peerId, namespace: Namespaces.Message.Cloud), includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: Namespaces.Message.Cloud), limit: 500)
@@ -329,14 +337,31 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
let remoteSearchResult: Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError>
switch location {
case let .peer(peerId, fromId, tags, reactions, threadId, minDate, maxDate):
if peerId.namespace == Namespaces.Peer.SecretChat {
if peerId.namespace == Namespaces.Peer.SecretChat || forceLocal {
return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
var readStates: [PeerId: CombinedPeerReadState] = [:]
var threadInfo: [MessageId: MessageHistoryThreadData] = [:]
if let readState = transaction.getCombinedPeerReadState(peerId) {
readStates[peerId] = readState
}
let result = transaction.searchMessages(peerId: peerId, query: query, tags: tags)
// MARK: Swiftgram
var result: [Message] = []
if forceLocal {
transaction.withAllMessages(peerId: peerId, { message in
if result.count >= limit {
return false
}
if let tags = tags, message.tags != tags {
return true
}
if message.text.contains(query) {
result.append(message)
}
return true
})
} else {
result = transaction.searchMessages(peerId: peerId, query: query, tags: tags)
}
for message in result {
for attribute in message.attributes {
@@ -604,11 +629,13 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
if let result {
switch result {
case let .messagesSlice(_, _, _, _, searchFlood, _, _, _, _):
case let .messagesSlice(messagesSliceData):
let searchFlood = messagesSliceData.searchFlood
if let searchFlood {
transaction.updatePreferencesEntry(key: PreferencesKeys.globalPostSearchState(), { _ in
switch searchFlood {
case let .searchPostsFlood(_, totalDaily, remains, waitTill, starsAmount):
case let .searchPostsFlood(searchPostsFloodData):
let (_, totalDaily, remains, waitTill, starsAmount) = (searchPostsFloodData.flags, searchPostsFloodData.totalDaily, searchPostsFloodData.remains, searchPostsFloodData.waitTill, searchPostsFloodData.starsAmount)
return PreferencesEntry(TelegramGlobalPostSearchState(
totalFreeSearches: totalDaily,
remainingFreeSearches: remains,
@@ -673,12 +700,12 @@ func _internal_downloadMessage(accountPeerId: PeerId, postbox: Postbox, network:
let signal: Signal<Api.messages.Messages, MTRpcError>
if messageId.peerId.namespace == Namespaces.Peer.CloudChannel {
if let channel = apiInputChannel(peer) {
signal = network.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(id: messageId.id)]))
signal = network.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(.init(id: messageId.id))]))
} else {
signal = .complete()
}
} else {
signal = network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)]))
signal = network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(.init(id: messageId.id))]))
}
return signal
@@ -694,25 +721,29 @@ func _internal_downloadMessage(accountPeerId: PeerId, postbox: Postbox, network:
let chats: [Api.Chat]
let users: [Api.User]
switch result {
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
case let .channelMessages(channelMessagesData):
let (_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers) = (channelMessagesData.flags, channelMessagesData.pts, channelMessagesData.count, channelMessagesData.offsetIdOffset, channelMessagesData.messages, channelMessagesData.topics, channelMessagesData.chats, channelMessagesData.users)
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case let .messages(apiMessages, _, apiChats, apiUsers):
case let .messages(messagesData):
let (apiMessages, _, apiChats, apiUsers) = (messagesData.messages, messagesData.topics, messagesData.chats, messagesData.users)
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, _, apiMessages, _, apiChats, apiUsers):
case let .messagesSlice(messagesSliceData):
let (_, _, _, _, _, apiMessages, _, apiChats, apiUsers) = (messagesSliceData.flags, messagesSliceData.count, messagesSliceData.nextRate, messagesSliceData.offsetIdOffset, messagesSliceData.searchFlood, messagesSliceData.messages, messagesSliceData.topics, messagesSliceData.chats, messagesSliceData.users)
messages = apiMessages
chats = apiChats
users = apiUsers
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
chats = []
users = []
}
let postboxSignal = postbox.transaction { transaction -> Message? in
var peers: [PeerId: Peer] = [:]
@@ -762,12 +793,12 @@ func fetchRemoteMessage(accountPeerId: PeerId, postbox: Postbox, source: FetchMe
}
} else if id.peerId.namespace == Namespaces.Peer.CloudChannel {
if let channel = peer.inputChannel {
signal = source.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(id: id.id)]))
signal = source.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(.init(id: id.id))]))
} else {
signal = .fail(MTRpcError(errorCode: 400, errorDescription: "Peer Not Found"))
}
} else if id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup {
signal = source.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: id.id)]))
signal = source.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(.init(id: id.id))]))
} else {
signal = .fail(MTRpcError(errorCode: 400, errorDescription: "Invalid Peer"))
}
@@ -785,25 +816,29 @@ func fetchRemoteMessage(accountPeerId: PeerId, postbox: Postbox, source: FetchMe
let chats: [Api.Chat]
let users: [Api.User]
switch result {
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
case let .channelMessages(channelMessagesData):
let (_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers) = (channelMessagesData.flags, channelMessagesData.pts, channelMessagesData.count, channelMessagesData.offsetIdOffset, channelMessagesData.messages, channelMessagesData.topics, channelMessagesData.chats, channelMessagesData.users)
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case let .messages(apiMessages, _, apiChats, apiUsers):
case let .messages(messagesData):
let (apiMessages, _, apiChats, apiUsers) = (messagesData.messages, messagesData.topics, messagesData.chats, messagesData.users)
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messagesSlice(_, _, _, _, _, apiMessages, _, apiChats, apiUsers):
case let .messagesSlice(messagesSliceData):
let (_, _, _, _, _, apiMessages, _, apiChats, apiUsers) = (messagesSliceData.flags, messagesSliceData.count, messagesSliceData.nextRate, messagesSliceData.offsetIdOffset, messagesSliceData.searchFlood, messagesSliceData.messages, messagesSliceData.topics, messagesSliceData.chats, messagesSliceData.users)
messages = apiMessages
chats = apiChats
users = apiUsers
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
chats = []
users = []
}
return postbox.transaction { transaction -> Message? in
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
@@ -856,13 +891,17 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
case let .messages(apiMessages, _, _, _):
case let .messages(messagesData):
let apiMessages = messagesData.messages
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
case let .channelMessages(channelMessagesData):
let apiMessages = channelMessagesData.messages
messages = apiMessages
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _, _):
case let .messagesSlice(messagesSliceData):
let apiMessages = messagesSliceData.messages
messages = apiMessages
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
}
for message in messages {
@@ -893,13 +932,17 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
case let .messages(apiMessages, _, _, _):
case let .messages(messagesData):
let apiMessages = messagesData.messages
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
case let .channelMessages(channelMessagesData):
let apiMessages = channelMessagesData.messages
messages = apiMessages
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _, _):
case let .messagesSlice(messagesSliceData):
let apiMessages = messagesSliceData.messages
messages = apiMessages
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
}
for message in messages {
@@ -926,13 +969,17 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
case let .messages(apiMessages, _, _, _):
case let .messages(messagesData):
let apiMessages = messagesData.messages
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
case let .channelMessages(channelMessagesData):
let apiMessages = channelMessagesData.messages
messages = apiMessages
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _, _):
case let .messagesSlice(messagesSliceData):
let apiMessages = messagesSliceData.messages
messages = apiMessages
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
}
for message in messages {
@@ -950,13 +997,17 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
|> map { result -> MessageIndex? in
let messages: [Api.Message]
switch result {
case let .messages(apiMessages, _, _, _):
case let .messages(messagesData):
let apiMessages = messagesData.messages
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
case let .channelMessages(channelMessagesData):
let apiMessages = channelMessagesData.messages
messages = apiMessages
case let .messagesSlice(_, _, _, _, _, apiMessages, _, _, _):
case let .messagesSlice(messagesSliceData):
let apiMessages = messagesSliceData.messages
messages = apiMessages
case .messagesNotModified:
case let .messagesNotModified(messagesNotModifiedData):
let _ = messagesNotModifiedData.count
messages = []
}
for message in messages {
@@ -1031,14 +1082,16 @@ func _internal_updatedRemotePeer(accountPeerId: PeerId, postbox: Postbox, networ
return postbox.transaction { transaction -> Signal<Peer, UpdatedRemotePeerError> in
let chats: [Api.Chat]
switch result {
case let .chats(c):
case let .chats(chatsData):
let c = chatsData.chats
chats = c
case let .chatsSlice(_, c):
case let .chatsSlice(chatsSliceData):
let c = chatsSliceData.chats
chats = c
}
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: [])
if let firstId = chats.first?.peerId, let updatedPeer = parsedPeers.get(firstId), updatedPeer.id == peer.id {
return postbox.transaction { transaction -> Peer in
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
@@ -1062,9 +1115,11 @@ func _internal_updatedRemotePeer(accountPeerId: PeerId, postbox: Postbox, networ
return postbox.transaction { transaction -> Signal<Peer, UpdatedRemotePeerError> in
let chats: [Api.Chat]
switch result {
case let .chats(c):
case let .chats(chatsData):
let c = chatsData.chats
chats = c
case let .chatsSlice(_, c):
case let .chatsSlice(chatsSliceData):
let c = chatsSliceData.chats
chats = c
}
@@ -1102,7 +1157,8 @@ func _internal_refreshGlobalPostSearchState(account: Account) -> Signal<Never, N
}
transaction.updatePreferencesEntry(key: PreferencesKeys.globalPostSearchState(), { _ in
switch result {
case let .searchPostsFlood(_, totalDaily, remains, waitTill, starsAmount):
case let .searchPostsFlood(searchPostsFloodData):
let (_, totalDaily, remains, waitTill, starsAmount) = (searchPostsFloodData.flags, searchPostsFloodData.totalDaily, searchPostsFloodData.remains, searchPostsFloodData.waitTill, searchPostsFloodData.starsAmount)
return PreferencesEntry(TelegramGlobalPostSearchState(
totalFreeSearches: totalDaily,
remainingFreeSearches: remains,
@@ -130,25 +130,29 @@ func _internal_peerSendAsAvailablePeers(accountPeerId: PeerId, network: Network,
return .single([])
}
switch result {
case let .sendAsPeers(sendAsPeers, chats, _):
case let .sendAsPeers(sendAsPeersData):
let (sendAsPeers, chats) = (sendAsPeersData.peers, sendAsPeersData.chats)
return postbox.transaction { transaction -> [SendAsPeer] in
var subscribers: [PeerId: Int32] = [:]
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: [])
var premiumRequiredPeerIds = Set<PeerId>()
for sendAsPeer in sendAsPeers {
if case let .sendAsPeer(flags, peer) = sendAsPeer, (flags & (1 << 0)) != 0 {
if case let .sendAsPeer(sendAsPeerData) = sendAsPeer, (sendAsPeerData.flags & (1 << 0)) != 0 {
let peer = sendAsPeerData.peer
premiumRequiredPeerIds.insert(peer.peerId)
}
}
for chat in chats {
if let groupOrChannel = parsedPeers.get(chat.peerId) {
switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _, _, _, _):
case let .channel(channelData):
let participantsCount = channelData.participantsCount
if let participantsCount = participantsCount {
subscribers[groupOrChannel.id] = participantsCount
}
case let .chat(_, _, _, _, participantsCount, _, _, _, _, _):
case let .chat(chatData):
let participantsCount = chatData.participantsCount
subscribers[groupOrChannel.id] = participantsCount
default:
break
@@ -286,25 +290,29 @@ func _internal_liveStorySendAsAvailablePeers(account: Account, peerId: PeerId) -
return .single([])
}
switch result {
case let .sendAsPeers(sendAsPeers, chats, _):
case let .sendAsPeers(sendAsPeersData):
let (sendAsPeers, chats) = (sendAsPeersData.peers, sendAsPeersData.chats)
return account.postbox.transaction { transaction -> [SendAsPeer] in
var subscribers: [PeerId: Int32] = [:]
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: [])
var premiumRequiredPeerIds = Set<PeerId>()
for sendAsPeer in sendAsPeers {
if case let .sendAsPeer(flags, peer) = sendAsPeer, (flags & (1 << 0)) != 0 {
if case let .sendAsPeer(sendAsPeerData) = sendAsPeer, (sendAsPeerData.flags & (1 << 0)) != 0 {
let peer = sendAsPeerData.peer
premiumRequiredPeerIds.insert(peer.peerId)
}
}
for chat in chats {
if let groupOrChannel = parsedPeers.get(chat.peerId) {
switch chat {
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _, _, _, _):
case let .channel(channelData):
let participantsCount = channelData.participantsCount
if let participantsCount = participantsCount {
subscribers[groupOrChannel.id] = participantsCount
}
case let .chat(_, _, _, _, participantsCount, _, _, _, _, _):
case let .chat(chatData):
let participantsCount = chatData.participantsCount
subscribers[groupOrChannel.id] = participantsCount
default:
break
@@ -86,13 +86,14 @@ public final class SparseMessageList {
}
private let loadHoleDisposable = MetaDisposable()
private var loadingHole: LoadingHole?
private var isLoadingInitial: Bool = false
private var loadingPlaceholders: [MessageId: Disposable] = [:]
private var loadedPlaceholders: [MessageId: Message] = [:]
let statePromise = Promise<SparseMessageList.State>()
init(queue: Queue, account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags) {
init(queue: Queue, account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags, initialMessageIndex: MessageIndex?) {
self.queue = queue
self.account = account
self.peerId = peerId
@@ -102,6 +103,11 @@ public final class SparseMessageList {
self.resetTopSection()
if self.threadId == nil {
if initialMessageIndex != nil {
self.isLoadingInitial = true
self.updateState()
}
self.sparseItemsDisposable = (self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
@@ -112,19 +118,21 @@ public final class SparseMessageList {
guard let messageFilter = messageFilterForTagMask(messageTag) else {
return .single(SparseItems(items: []))
}
//TODO:api
return account.network.request(Api.functions.messages.getSearchResultsPositions(flags: 0, peer: inputPeer, savedPeerId: nil, filter: messageFilter, offsetId: 0, limit: 1000))
|> map { result -> SparseItems in
switch result {
case let .searchResultsPositions(totalCount, positions):
case let .searchResultsPositions(searchResultsPositionsData):
let (totalCount, apiPositions) = (searchResultsPositionsData.count, searchResultsPositionsData.positions)
struct Position: Equatable {
var id: Int32
var date: Int32
var offset: Int
}
var positions: [Position] = positions.map { position -> Position in
var positions: [Position] = apiPositions.map { position -> Position in
switch position {
case let .searchResultPosition(id, date, offset):
case let .searchResultPosition(searchResultPositionData):
let (id, date, offset) = (searchResultPositionData.msgId, searchResultPositionData.date, searchResultPositionData.offset)
return Position(id: id, date: date, offset: Int(offset))
}
}
@@ -134,7 +142,11 @@ public final class SparseMessageList {
var result = SparseItems(items: [])
for i in 0 ..< positions.count {
if i != 0 {
if i == 0 {
if initialMessageIndex != nil && positions[i].offset != 0 {
result.items.append(.range(count: positions[i].offset))
}
} else {
let deltaCount = positions[i].offset - 1 - positions[i - 1].offset
if deltaCount > 0 {
result.items.append(.range(count: deltaCount))
@@ -160,9 +172,34 @@ public final class SparseMessageList {
guard let strongSelf = self else {
return
}
strongSelf.isLoadingInitial = false
strongSelf.sparseItems = sparseItems
if strongSelf.topSection != nil {
strongSelf.updateState()
if let initialMessageIndex {
var loadHoleAnchor: MessageId?
loop: for item in sparseItems.items {
switch item {
case let .anchor(id, timestamp, _):
let anchorIndex = MessageIndex(id: id, timestamp: timestamp)
if anchorIndex <= initialMessageIndex {
loadHoleAnchor = id
break loop
}
case .range:
break
}
}
if let loadHoleAnchor {
strongSelf.loadHole(anchor: loadHoleAnchor, direction: .around, completion: {
})
} else {
if strongSelf.topSection != nil {
strongSelf.updateState()
}
}
} else {
if strongSelf.topSection != nil {
strongSelf.updateState()
}
}
})
}
@@ -591,10 +628,22 @@ public final class SparseMessageList {
if self.topSection != topSection {
self.topSection = topSection
}
self.updateState()
if self.loadingHole == nil && !self.isLoadingInitial {
self.updateState()
}
}
private func updateState() {
if self.isLoadingInitial {
self.statePromise.set(.single(SparseMessageList.State(
items: [],
totalCount: 0,
isLoading: true
)))
return
}
var items: [SparseMessageList.State.Item] = []
var minMessageId: MessageId?
if let topSection = self.topSection {
@@ -692,11 +741,11 @@ public final class SparseMessageList {
}
}
init(account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags) {
init(account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags, initialMessageIndex: MessageIndex?) {
self.queue = Queue()
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
return Impl(queue: queue, account: account, peerId: peerId, threadId: threadId, messageTag: messageTag)
return Impl(queue: queue, account: account, peerId: peerId, threadId: threadId, messageTag: messageTag, initialMessageIndex: initialMessageIndex)
})
}
@@ -836,7 +885,8 @@ public final class SparseMessageCalendar {
}
switch result {
case let .searchResultsCalendar(_, _, minDate, minMsgId, _, periods, messages, chats, users):
case let .searchResultsCalendar(searchResultsCalendarData):
let (minDate, minMsgId, periods, messages, chats, users) = (searchResultsCalendarData.minDate, searchResultsCalendarData.minMsgId, searchResultsCalendarData.periods, searchResultsCalendarData.messages, searchResultsCalendarData.chats, searchResultsCalendarData.users)
var parsedMessages: [StoreMessage] = []
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
@@ -854,7 +904,8 @@ public final class SparseMessageCalendar {
var messagesByDay: [Int32: SparseMessageCalendar.Entry] = [:]
for period in periods {
switch period {
case let .searchResultsCalendarPeriod(date, minMsgId, _, count):
case let .searchResultsCalendarPeriod(searchResultsCalendarPeriodData):
let (date, minMsgId, count) = (searchResultsCalendarPeriodData.date, searchResultsCalendarPeriodData.minMsgId, searchResultsCalendarPeriodData.count)
if let message = transaction.getMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minMsgId)) {
messagesByDay[date] = SparseMessageCalendar.Entry(message: message, count: Int(count))
}
@@ -980,7 +980,7 @@ private func apiInputPrivacyRules(privacy: EngineStoryPrivacy, transaction: Tran
privacyRules = [.inputPrivacyValueAllowCloseFriends]
case .nobody:
if privacy.additionallyIncludePeers.isEmpty {
privacyRules = [.inputPrivacyValueAllowUsers(users: [.inputUserSelf])]
privacyRules = [.inputPrivacyValueAllowUsers(.init(users: [.inputUserSelf]))]
} else {
privacyRules = []
}
@@ -1000,15 +1000,15 @@ private func apiInputPrivacyRules(privacy: EngineStoryPrivacy, transaction: Tran
}
if !privacyUsers.isEmpty {
if case .contacts = privacy.base {
privacyRules.append(.inputPrivacyValueDisallowUsers(users: privacyUsers))
privacyRules.append(.inputPrivacyValueDisallowUsers(.init(users: privacyUsers)))
} else if case .everyone = privacy.base {
privacyRules.append(.inputPrivacyValueDisallowUsers(users: privacyUsers))
privacyRules.append(.inputPrivacyValueDisallowUsers(.init(users: privacyUsers)))
} else {
privacyRules.append(.inputPrivacyValueAllowUsers(users: privacyUsers))
privacyRules.append(.inputPrivacyValueAllowUsers(.init(users: privacyUsers)))
}
}
if !privacyChats.isEmpty {
privacyRules.append(.inputPrivacyValueAllowChatParticipants(chats: privacyChats))
privacyRules.append(.inputPrivacyValueAllowChatParticipants(.init(chats: privacyChats)))
}
return privacyRules
}
@@ -1155,7 +1155,8 @@ func _internal_beginStoryLivestream(account: Account, peerId: EnginePeer.Id, rtm
account.stateManager.addUpdates(updates)
for update in updates.allUpdates {
if case let .updateStory(_, apiStory) = update, case .storyItem = apiStory {
if case let .updateStory(updateStoryData) = update, case .storyItem = updateStoryData.story {
let apiStory = updateStoryData.story
return account.postbox.transaction { transaction in
if let storedItem = Stories.StoredItem(apiStoryItem: apiStory, peerId: peerId, transaction: transaction), case let .item(item) = storedItem, let media = item.media {
let mappedItem = EngineStoryItem(
@@ -1389,9 +1390,11 @@ func _internal_uploadStoryImpl(
var id: Int32?
if let updates = updates {
for update in updates.allUpdates {
if case let .updateStory(_, story) = update {
if case let .updateStory(updateStoryData) = update {
let story = updateStoryData.story
switch story {
case let .storyItem(_, idValue, _, fromId, _, _, _, _, media, _, _, _, _, _):
case let .storyItem(storyItemData):
let (idValue, fromId, media) = (storyItemData.id, storyItemData.fromId, storyItemData.media)
if let parsedStory = Stories.StoredItem(apiStoryItem: story, peerId: toPeerId, transaction: transaction) {
var items = transaction.getStoryItems(peerId: toPeerId)
var updatedItems: [Stories.Item] = []
@@ -1521,7 +1524,8 @@ func _internal_uploadBotPreviewImpl(
return .single(.completed(nil))
}
switch resultPreviewMedia {
case let .botPreviewMedia(date, resultMedia):
case let .botPreviewMedia(botPreviewMediaData):
let (date, resultMedia) = (botPreviewMediaData.date, botPreviewMediaData.media)
return postbox.transaction { transaction -> StoryUploadResult in
var currentState: Stories.LocalState
if let value = transaction.getLocalStoryState()?.get(Stories.LocalState.self) {
@@ -1591,10 +1595,10 @@ func _internal_deleteBotPreviews(account: Account, peerId: PeerId, language: Str
var inputMedia: [Api.InputMedia] = []
for item in media {
if let image = item as? TelegramMediaImage, let resource = image.representations.last?.resource as? CloudPhotoSizeMediaResource {
inputMedia.append(.inputMediaPhoto(flags: 0, id: .inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
inputMedia.append(.inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil)))
}
}
if language == nil {
@@ -1649,10 +1653,10 @@ func _internal_deleteBotPreviewsLanguage(account: Account, peerId: PeerId, langu
var inputMedia: [Api.InputMedia] = []
for item in media {
if let image = item as? TelegramMediaImage, let resource = image.representations.last?.resource as? CloudPhotoSizeMediaResource {
inputMedia.append(.inputMediaPhoto(flags: 0, id: .inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
inputMedia.append(.inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil)))
}
}
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current -> CachedPeerData? in
@@ -1717,7 +1721,7 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng
if let result = result, case let .content(uploadedContent) = result, case let .media(media, _) = uploadedContent.content {
inputMedia = media
} else if case let .existing(media) = media, let file = media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia = .inputMediaUploadedDocument(flags: 0, file: .inputFileStoryDocument(id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), thumb: nil, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil)
inputMedia = .inputMediaUploadedDocument(.init(flags: 0, file: .inputFileStoryDocument(.init(id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))))), thumb: nil, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: nil, videoCover: nil, videoTimestamp: nil, ttlSeconds: nil))
updatingCoverTime = true
} else {
inputMedia = nil
@@ -1779,9 +1783,11 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng
|> mapToSignal { updates -> Signal<StoryUploadResult, NoError> in
if let updates = updates {
for update in updates.allUpdates {
if case let .updateStory(_, story) = update {
if case let .updateStory(updateStoryData) = update {
let story = updateStoryData.story
switch story {
case let .storyItem(_, _, _, _, _, _, _, _, media, _, _, _, _, _):
case let .storyItem(storyItemData):
let media = storyItemData.media
let parsedMedia = textMediaAndExpirationTimerFromApiMedia(media, account.peerId).media
if let parsedMedia = parsedMedia, let originalMedia = originalMedia {
applyMediaResourceChanges(from: originalMedia, to: parsedMedia, postbox: account.postbox, force: false, skipPreviews: updatingCoverTime)
@@ -1921,7 +1927,8 @@ func _internal_checkStoriesUploadAvailability(account: Account, target: Stories.
return account.network.request(Api.functions.stories.canSendStory(peer: inputPeer))
|> map { result -> StoriesUploadAvailability in
switch result {
case let .canSendStoryCount(countRemains):
case let .canSendStoryCount(canSendStoryCountData):
let countRemains = canSendStoryCountData.countRemains
return .available(remainingCount: countRemains)
}
}
@@ -2146,11 +2153,14 @@ func _internal_updatePinnedToTopStories(account: Account, peerId: PeerId, ids: [
extension Api.StoryItem {
var id: Int32 {
switch self {
case let .storyItem(_, id, _, _, _, _, _, _, _, _, _, _, _, _):
case let .storyItem(storyItemData):
let id = storyItemData.id
return id
case let .storyItemDeleted(id):
case let .storyItemDeleted(storyItemDeletedData):
let id = storyItemDeletedData.id
return id
case let .storyItemSkipped(_, id, _, _):
case let .storyItemSkipped(storyItemSkippedData):
let id = storyItemSkippedData.id
return id
}
}
@@ -2159,7 +2169,8 @@ extension Api.StoryItem {
extension Stories.Item.Views {
init(apiViews: Api.StoryViews) {
switch apiViews {
case let .storyViews(flags, viewsCount, forwardsCount, reactions, reactionsCount, recentViewers):
case let .storyViews(storyViewsData):
let (flags, viewsCount, forwardsCount, reactions, reactionsCount, recentViewers) = (storyViewsData.flags, storyViewsData.viewsCount, storyViewsData.forwardsCount, storyViewsData.reactions, storyViewsData.reactionsCount, storyViewsData.recentViewers)
//storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;
let hasList = (flags & (1 << 1)) != 0
var seenPeerIds: [PeerId] = []
@@ -2170,7 +2181,8 @@ extension Stories.Item.Views {
if let reactions = reactions {
for result in reactions {
switch result {
case let .reactionCount(_, chosenOrder, reaction, count):
case let .reactionCount(reactionCountData):
let (chosenOrder, reaction, count) = (reactionCountData.chosenOrder, reactionCountData.reaction, reactionCountData.count)
if let reaction = MessageReaction.Reaction(apiReaction: reaction) {
mappedReactions.append(MessageReaction(value: reaction, count: count, chosenOrder: chosenOrder.flatMap(Int.init)))
}
@@ -2192,7 +2204,8 @@ extension Stories.Item.Views {
extension Stories.Item.ForwardInfo {
init?(apiForwardInfo: Api.StoryFwdHeader) {
switch apiForwardInfo {
case let .storyFwdHeader(flags, from, fromName, storyId):
case let .storyFwdHeader(storyFwdHeaderData):
let (flags, from, fromName, storyId) = (storyFwdHeaderData.flags, storyFwdHeaderData.from, storyFwdHeaderData.fromName, storyFwdHeaderData.storyId)
let isModified = (flags & (1 << 3)) != 0
if let from = from, let storyId = storyId {
self = .known(peerId: from.peerId, storyId: storyId, isModified: isModified)
@@ -2209,7 +2222,8 @@ extension Stories.Item.ForwardInfo {
extension Stories.StoredItem {
init?(apiStoryItem: Api.StoryItem, existingItem: Stories.Item? = nil, peerId: PeerId, transaction: Transaction) {
switch apiStoryItem {
case let .storyItem(flags, id, date, fromId, forwardFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction, albums):
case let .storyItem(storyItemData):
let (flags, id, date, fromId, forwardFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction, albums) = (storyItemData.flags, storyItemData.id, storyItemData.date, storyItemData.fromId, storyItemData.fwdFrom, storyItemData.expireDate, storyItemData.caption, storyItemData.entities, storyItemData.media, storyItemData.mediaAreas, storyItemData.privacy, storyItemData.views, storyItemData.sentReaction, storyItemData.albums)
var folderIds: [Int64]?
if let albums {
folderIds = albums.map(Int64.init)
@@ -2233,15 +2247,18 @@ extension Stories.StoredItem {
base = .everyone
case .privacyValueDisallowAll:
base = .nobody
case let .privacyValueAllowUsers(users):
case let .privacyValueAllowUsers(privacyValueAllowUsersData):
let users = privacyValueAllowUsersData.users
for id in users {
additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id)))
}
case let .privacyValueDisallowUsers(users):
case let .privacyValueDisallowUsers(privacyValueDisallowUsersData):
let users = privacyValueDisallowUsersData.users
for id in users {
additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id)))
}
case let .privacyValueAllowChatParticipants(chats):
case let .privacyValueAllowChatParticipants(privacyValueAllowChatParticipantsData):
let chats = privacyValueAllowChatParticipantsData.chats
for id in chats {
if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudGroup, id: EnginePeer.Id.Id._internalFromInt64Value(id))) {
additionalPeerIds.append(peer.id)
@@ -2296,7 +2313,8 @@ extension Stories.StoredItem {
var parsedAlternativeMedia: [Media] = []
switch media {
case let .messageMediaDocument(_, _, altDocuments, _, _, _):
case let .messageMediaDocument(messageMediaDocumentData):
let altDocuments = messageMediaDocumentData.altDocuments
if let altDocuments {
parsedAlternativeMedia = altDocuments.compactMap { telegramMediaFileFromApiDocument($0, altDocuments: []) }
}
@@ -2333,7 +2351,8 @@ extension Stories.StoredItem {
} else {
return nil
}
case let .storyItemSkipped(flags, id, date, expireDate):
case let .storyItemSkipped(storyItemSkippedData):
let (flags, id, date, expireDate) = (storyItemSkippedData.flags, storyItemSkippedData.id, storyItemSkippedData.date, storyItemSkippedData.expireDate)
let isCloseFriends = (flags & (1 << 8)) != 0
let isLiveItem = (flags & (1 << 9)) != 0
self = .placeholder(Stories.Placeholder(id: id, timestamp: date, expirationTimestamp: expireDate, isCloseFriends: isCloseFriends, isLiveItem: isLiveItem))
@@ -2363,9 +2382,10 @@ func _internal_getStoryById(accountPeerId: PeerId, postbox: Postbox, network: Ne
}
return postbox.transaction { transaction -> EngineStoryItem? in
switch result {
case let .stories(_, _, stories, _, chats, users):
case let .stories(storiesData):
let (stories, chats, users) = (storiesData.stories, storiesData.chats, storiesData.users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(transaction: transaction, chats: chats, users: users))
if let storyItem = stories.first.flatMap({ Stories.StoredItem(apiStoryItem: $0, peerId: peerId, transaction: transaction) }) {
if let entry = CodableEntry(storyItem) {
transaction.setStory(id: storyId, value: entry)
@@ -2431,9 +2451,10 @@ func _internal_getStoriesById(accountPeerId: PeerId, postbox: Postbox, network:
}
return postbox.transaction { transaction -> [Stories.StoredItem] in
switch result {
case let .stories(_, _, stories, _, chats, users):
case let .stories(storiesData):
let (stories, chats, users) = (storiesData.stories, storiesData.chats, storiesData.users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(transaction: transaction, chats: chats, users: users))
return stories.compactMap { apiStoryItem -> Stories.StoredItem? in
return Stories.StoredItem(apiStoryItem: apiStoryItem, peerId: peer.id, transaction: transaction)
}
@@ -2462,9 +2483,10 @@ func _internal_getStoriesById(accountPeerId: PeerId, postbox: Postbox, source: F
}
return postbox.transaction { transaction -> [Stories.StoredItem]? in
switch result {
case let .stories(_, _, stories, _, chats, users):
case let .stories(storiesData):
let (stories, chats, users) = (storiesData.stories, storiesData.chats, storiesData.users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(transaction: transaction, chats: chats, users: users))
return stories.compactMap { apiStoryItem -> Stories.StoredItem? in
return Stories.StoredItem(apiStoryItem: apiStoryItem, peerId: peerId, transaction: transaction)
}
@@ -2518,7 +2540,8 @@ func _internal_getStoryViews(account: Account, peerId: PeerId, ids: [Int32]) ->
return account.postbox.transaction { transaction -> [Int32: Stories.Item.Views] in
var parsedViews: [Int32: Stories.Item.Views] = [:]
switch result {
case let .storyViews(views, users):
case let .storyViews(storyViewsData):
let (views, users) = (storyViewsData.views, storyViewsData.users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
for i in 0 ..< views.count {
@@ -2587,7 +2610,8 @@ func _internal_exportStoryLink(account: Account, peerId: EnginePeer.Id, id: Int3
return nil
}
switch result {
case let .exportedStoryLink(link):
case let .exportedStoryLink(exportedStoryLinkData):
let link = exportedStoryLinkData.link
return link
}
}
@@ -2645,7 +2669,8 @@ func _internal_refreshSeenStories(postbox: Postbox, network: Network) -> Signal<
return postbox.transaction { transaction -> Void in
for update in updates.allUpdates {
switch update {
case let .updateReadStories(peerIdValue, maxId):
case let .updateReadStories(updateReadStoriesData):
let (peerIdValue, maxId) = (updateReadStoriesData.peer, updateReadStoriesData.maxId)
let peerId = peerIdValue.peerId
var update = false
if let value = transaction.getPeerStoryState(peerId: peerId) {
@@ -2693,7 +2718,8 @@ extension Stories.ConfigurationState {
extension Stories.StealthModeState {
init(apiMode: Api.StoriesStealthMode) {
switch apiMode {
case let .storiesStealthMode(_, activeUntilDate, cooldownUntilDate):
case let .storiesStealthMode(storiesStealthModeData):
let (activeUntilDate, cooldownUntilDate) = (storiesStealthModeData.activeUntilDate, storiesStealthModeData.cooldownUntilDate)
self.init(
activeUntilTimestamp: activeUntilDate,
cooldownUntilTimestamp: cooldownUntilDate
@@ -402,7 +402,8 @@ public final class StorySubscriptionsContext {
let _ = (self.postbox.transaction { transaction -> Void in
var updatedStealthMode: Api.StoriesStealthMode?
switch result {
case let .allStoriesNotModified(_, state, stealthMode):
case let .allStoriesNotModified(allStoriesNotModifiedData):
let (state, stealthMode) = (allStoriesNotModifiedData.state, allStoriesNotModifiedData.stealthMode)
self.loadedStateMark = .value(state)
let (currentStateValue, _) = transaction.getAllStorySubscriptions(key: subscriptionsKey)
let currentState = currentStateValue.flatMap { $0.get(Stories.SubscriptionsState.self) }
@@ -421,7 +422,8 @@ public final class StorySubscriptionsContext {
if isRefresh && !isHidden {
updatedStealthMode = stealthMode
}
case let .allStories(flags, _, state, peerStories, chats, users, stealthMode):
case let .allStories(allStoriesData):
let (flags, state, peerStories, chats, users, stealthMode) = (allStoriesData.flags, allStoriesData.state, allStoriesData.peerStories, allStoriesData.chats, allStoriesData.users, allStoriesData.stealthMode)
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
let hasMore: Bool = (flags & (1 << 0)) != 0
@@ -431,11 +433,12 @@ public final class StorySubscriptionsContext {
for peerStorySet in peerStories {
switch peerStorySet {
case let .peerStories(_, peerIdValue, maxReadId, stories):
case let .peerStories(peerStoriesData):
let (_, peerIdValue, maxReadId, stories) = (peerStoriesData.flags, peerStoriesData.peer, peerStoriesData.maxReadId, peerStoriesData.stories)
let peerId = peerIdValue.peerId
let previousPeerEntries: [StoryItemsTableEntry] = transaction.getStoryItems(peerId: peerId)
var updatedPeerEntries: [StoryItemsTableEntry] = []
for story in stories {
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peerId, transaction: transaction) {
@@ -889,10 +892,12 @@ public final class PeerStoryListContext: StoryListContext {
if let updatedFolders {
switch updatedFolders {
case let .albums(_, albums):
case let .albums(albumsData):
let albums = albumsData.albums
for album in albums {
switch album {
case let .storyAlbum(_, albumId, title, iconPhoto, iconVideo):
case let .storyAlbum(storyAlbumData):
let (albumId, title, iconPhoto, iconVideo) = (storyAlbumData.albumId, storyAlbumData.title, storyAlbumData.iconPhoto, storyAlbumData.iconVideo)
let _ = iconPhoto
let _ = iconVideo
folderItems.append(State.Folder(
@@ -915,7 +920,8 @@ public final class PeerStoryListContext: StoryListContext {
}
switch result {
case let .stories(_, count, stories, pinnedStories, chats, users):
case let .stories(storiesData):
let (count, stories, pinnedStories, chats, users) = (storiesData.count, storiesData.stories, storiesData.pinnedToTop, storiesData.chats, storiesData.users)
totalCount = Int(count)
hasMore = stories.count >= limit
@@ -1410,7 +1416,8 @@ public final class PeerStoryListContext: StoryListContext {
}
if let result {
switch result {
case let .storyAlbum(_, albumId, _, _, _):
case let .storyAlbum(storyAlbumData):
let albumId = storyAlbumData.albumId
var state = self.stateValue
state.availableFolders.append(StoryListContextState.Folder(id: Int64(albumId), title: title))
self.stateValue = state
@@ -1914,7 +1921,8 @@ public final class PeerStoryListContext: StoryListContext {
}).start(next: { result in
if let result {
switch result {
case let .storyAlbum(_, albumId, _, _, _):
case let .storyAlbum(storyAlbumData):
let albumId = storyAlbumData.albumId
let _ = (account.postbox.transaction { transaction -> Void in
let key = ValueBoxKey(length: 8 + 1)
key.setInt64(0, value: peerId.toInt64())
@@ -2146,7 +2154,8 @@ public final class SearchStoryListContext: StoryListContext {
var nextOffsetValue: String?
switch result {
case let .foundStories(_, count, stories, nextOffset, chats, users):
case let .foundStories(foundStoriesData):
let (count, stories, nextOffset, chats, users) = (foundStoriesData.count, foundStoriesData.stories, foundStoriesData.nextOffset, foundStoriesData.chats, foundStoriesData.users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(transaction: transaction, chats: chats, users: users))
totalCount = Int(count)
@@ -2154,7 +2163,8 @@ public final class SearchStoryListContext: StoryListContext {
for story in stories {
switch story {
case let .foundStory(peer, story):
case let .foundStory(foundStoryData):
let (peer, story) = (foundStoryData.peer, foundStoryData.story)
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peer.peerId, transaction: transaction) {
if case let .item(item) = storedItem, let media = item.media {
let mappedItem = EngineStoryItem(
@@ -2593,15 +2603,17 @@ public final class PeerExpiringStoryListContext {
var updatedPeerEntries: [StoryItemsTableEntry] = []
updatedPeerEntries.removeAll()
if let result = result, case let .peerStories(stories, chats, users) = result {
if let result = result, case let .peerStories(peerStoriesData) = result {
let (stories, chats, users) = (peerStoriesData.stories, peerStoriesData.chats, peerStoriesData.users)
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
switch stories {
case let .peerStories(_, peerIdValue, maxReadId, stories):
case let .peerStories(peerStoriesData):
let (_, peerIdValue, maxReadId, stories) = (peerStoriesData.flags, peerStoriesData.peer, peerStoriesData.maxReadId, peerStoriesData.stories)
let peerId = peerIdValue.peerId
let previousPeerEntries: [StoryItemsTableEntry] = transaction.getStoryItems(peerId: peerId)
for story in stories {
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peerId, transaction: transaction) {
if case .placeholder = storedItem, let previousEntry = previousPeerEntries.first(where: { $0.id == storedItem.id }) {
@@ -2613,15 +2625,15 @@ public final class PeerExpiringStoryListContext {
}
}
}
transaction.setPeerStoryState(peerId: peerId, state: Stories.PeerState(
maxReadId: maxReadId ?? 0
).postboxRepresentation)
}
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
}
transaction.setStoryItems(peerId: peerId, items: updatedPeerEntries)
}
|> ignoreValues
@@ -2774,15 +2786,17 @@ public func _internal_pollPeerStories(postbox: Postbox, network: Network, accoun
var updatedPeerEntries: [StoryItemsTableEntry] = []
updatedPeerEntries.removeAll()
if let result = result, case let .peerStories(stories, chats, users) = result {
if let result = result, case let .peerStories(peerStoriesData) = result {
let (stories, chats, users) = (peerStoriesData.stories, peerStoriesData.chats, peerStoriesData.users)
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
switch stories {
case let .peerStories(_, peerIdValue, maxReadId, stories):
case let .peerStories(peerStoriesData):
let (_, peerIdValue, maxReadId, stories) = (peerStoriesData.flags, peerStoriesData.peer, peerStoriesData.maxReadId, peerStoriesData.stories)
let peerId = peerIdValue.peerId
let previousPeerEntries: [StoryItemsTableEntry] = transaction.getStoryItems(peerId: peerId)
for story in stories {
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peerId, transaction: transaction) {
if case .placeholder = storedItem, let previousEntry = previousPeerEntries.first(where: { $0.id == storedItem.id }) {
@@ -2794,17 +2808,17 @@ public func _internal_pollPeerStories(postbox: Postbox, network: Network, accoun
}
}
}
transaction.setPeerStoryState(peerId: peerId, state: Stories.PeerState(
maxReadId: maxReadId ?? 0
).postboxRepresentation)
}
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
}
transaction.setStoryItems(peerId: peerId, items: updatedPeerEntries)
var isContactOrMember = false
if transaction.isPeerContact(peerId: peerId) {
isContactOrMember = true
@@ -3373,10 +3387,10 @@ public final class BotPreviewStoryListContext: StoryListContext {
var inputMedia: [Api.InputMedia] = []
for item in media {
if let image = item as? TelegramMediaImage, let resource = image.representations.last?.resource as? CloudPhotoSizeMediaResource {
inputMedia.append(.inputMediaPhoto(flags: 0, id: .inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(Api.InputMedia.inputMediaPhoto(flags: 0, id: Api.InputPhoto.inputPhoto(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), ttlSeconds: nil))
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
inputMedia.append(.inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil)))
}
}
@@ -45,7 +45,8 @@ func _internal_summarizeMessage(account: Account, messageId: EngineMessage.Id, t
|> mapToSignal { result -> Signal<Void, SummarizeError> in
return account.postbox.transaction { transaction in
switch result {
case let .textWithEntities(text, entities):
case let .textWithEntities(textWithEntitiesData):
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
transaction.updateMessage(messageId, update: { currentMessage in
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
var attributes = currentMessage.attributes
@@ -1,3 +1,4 @@
import SGSimpleSettings
import Foundation
import SwiftSignalKit
import Postbox
@@ -96,15 +97,22 @@ public extension TelegramEngine {
}
public func requestMessageActionUrlAuth(subject: MessageActionUrlSubject) -> Signal<MessageActionUrlAuthResult, NoError> {
_internal_requestMessageActionUrlAuth(account: self.account, subject: subject)
return _internal_requestMessageActionUrlAuth(account: self.account, subject: subject)
}
public func acceptMessageActionUrlAuth(subject: MessageActionUrlSubject, allowWriteAccess: Bool) -> Signal<MessageActionUrlAuthResult, NoError> {
return _internal_acceptMessageActionUrlAuth(account: self.account, subject: subject, allowWriteAccess: allowWriteAccess)
public func acceptMessageActionUrlAuth(subject: MessageActionUrlSubject, allowWriteAccess: Bool, sharePhoneNumber: Bool) -> Signal<MessageActionUrlAuthResult, MessageActionUrlAuthError> {
return _internal_acceptMessageActionUrlAuth(account: self.account, subject: subject, allowWriteAccess: allowWriteAccess, sharePhoneNumber: sharePhoneNumber)
}
public func searchMessages(location: SearchMessagesLocation, query: String, state: SearchMessagesState?, centerId: MessageId? = nil, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> {
return _internal_searchMessages(account: self.account, location: location, query: query, state: state, centerId: centerId, limit: limit)
// TODO(swiftgram): Try to fallback on error when searching. RX is hard...
|> mapToSignal { result -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in
if (result.0.totalCount > 0) {
return .single(result)
}
return _internal_searchMessages(account: self.account, location: location, query: query, state: state, centerId: centerId, limit: limit, forceLocal: true)
}
}
public func getSearchMessageCount(location: SearchMessagesLocation, query: String) -> Signal<Int?, NoError> {
@@ -399,8 +407,8 @@ public extension TelegramEngine {
return _internal_updateStarsReactionPrivacy(account: self.account, messageId: id, privacy: privacy)
}
public func requestChatContextResults(botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String, incompleteResults: Bool = false, staleCachedResults: Bool = false) -> Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> {
return _internal_requestChatContextResults(account: self.account, botId: botId, peerId: peerId, query: query, location: location, offset: offset, incompleteResults: incompleteResults, staleCachedResults: staleCachedResults)
public func requestChatContextResults(IQTP: Bool = false, botId: PeerId, peerId: PeerId, query: String, location: Signal<(Double, Double)?, NoError> = .single(nil), offset: String, incompleteResults: Bool = false, staleCachedResults: Bool = false) -> Signal<RequestChatContextResultsResult?, RequestChatContextResultsError> {
return _internal_requestChatContextResults(IQTP: IQTP, account: self.account, botId: botId, peerId: peerId, query: query, location: location, offset: offset, incompleteResults: incompleteResults, staleCachedResults: staleCachedResults)
}
public func removeRecentlyUsedHashtag(string: String) -> Signal<Void, NoError> {
@@ -495,8 +503,8 @@ public extension TelegramEngine {
}
}
public func sparseMessageList(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags) -> SparseMessageList {
return SparseMessageList(account: self.account, peerId: peerId, threadId: threadId, messageTag: tag)
public func sparseMessageList(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags, initialMessageIndex: MessageIndex? = nil) -> SparseMessageList {
return SparseMessageList(account: self.account, peerId: peerId, threadId: threadId, messageTag: tag, initialMessageIndex: initialMessageIndex)
}
public func sparseMessageCalendar(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags, displayMedia: Bool) -> SparseMessageCalendar {
@@ -544,11 +552,14 @@ public extension TelegramEngine {
signals.append(self.account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: "", fromId: nil, savedPeerId: inputSavedPeer, savedReaction: nil, topMsgId: topMsgId, filter: filter, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1, maxId: 0, minId: 0, hash: 0))
|> map { result -> (count: Int32?, topId: Int32?) in
switch result {
case let .messagesSlice(_, count, _, _, _, messages, _, _, _):
case let .messagesSlice(messagesSliceData):
let (count, messages) = (messagesSliceData.count, messagesSliceData.messages)
return (count, messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
case let .channelMessages(_, _, count, _, messages, _, _, _):
case let .channelMessages(channelMessagesData):
let (count, messages) = (channelMessagesData.count, channelMessagesData.messages)
return (count, messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
case let .messages(messages, _, _, _):
case let .messages(messagesData):
let messages = messagesData.messages
return (Int32(messages.count), messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
case .messagesNotModified:
return (nil, nil)
@@ -589,11 +600,16 @@ public extension TelegramEngine {
}
public func translate(text: String, toLang: String, entities: [MessageTextEntity] = []) -> Signal<(String, [MessageTextEntity])?, TranslationError> {
return _internal_translate(network: self.account.network, text: text, toLang: toLang, entities: entities)
return sgWrappedTranslateSingle(text: text, toLang: toLang, default: _internal_translate(network: self.account.network, text: text, toLang: toLang, entities: entities))
}
public func translate(texts: [(String, [MessageTextEntity])], toLang: String) -> Signal<[(String, [MessageTextEntity])], TranslationError> {
return _internal_translateTexts(network: self.account.network, texts: texts, toLang: toLang)
return sgWrappedTranslateMultiple(texts: texts,toLang: toLang, default: _internal_translateTexts(network: self.account.network, texts: texts, toLang: toLang))
}
// MARK: Swiftgram
public func translateMessagesViaText(messagesDict: [EngineMessage.Id: String], fromLang: String?, toLang: String, generateEntitiesFunction: @escaping (String) -> [MessageTextEntity], enableLocalIfPossible: Bool) -> Signal<Never, TranslationError> {
return _internal_translateMessagesViaText(account: self.account, messagesDict: messagesDict, fromLang: fromLang, toLang: toLang, enableLocalIfPossible: enableLocalIfPossible, generateEntitiesFunction: generateEntitiesFunction)
}
public func translateMessages(messageIds: [EngineMessage.Id], fromLang: String?, toLang: String, enableLocalIfPossible: Bool) -> Signal<Never, TranslationError> {
@@ -1471,6 +1487,10 @@ public extension TelegramEngine {
}
public func markStoryAsSeen(peerId: EnginePeer.Id, id: Int32, asPinned: Bool) -> Signal<Never, NoError> {
// MARK: Swiftgram
if SGSimpleSettings.shared.isStealthModeEnabled {
return .never()
}
return _internal_markStoryAsSeen(account: self.account, peerId: peerId, id: id, asPinned: asPinned)
}
@@ -1707,3 +1727,66 @@ func _internal_monoforumPerformSuggestedPostAction(account: Account, id: EngineM
}
}
}
// MARK: Swiftgram
private func sgWrappedTranslateSingle(
text: String,
toLang: String,
`default`: Signal<(String, [MessageTextEntity])?, TranslationError>
) -> Signal<(String, [MessageTextEntity])?, TranslationError> {
if SGSimpleSettings.shared.translationBackend == SGSimpleSettings.TranslationBackend.gtranslate.rawValue {
return gtranslate(text, toLang)
|> map { ($0, []) }
|> mapError { _ in .generic }
}
return `default`
|> `catch` { originalError in
gtranslate(text, toLang)
|> map { ($0, []) }
|> mapError { _ in originalError }
}
}
private func sgWrappedTranslateMultiple(
texts: [(String, [MessageTextEntity])],
toLang: String,
`default`: Signal<[(String, [MessageTextEntity])], TranslationError>
) -> Signal<[(String, [MessageTextEntity])], TranslationError> {
if SGSimpleSettings.shared.translationBackend == SGSimpleSettings.TranslationBackend.gtranslate.rawValue {
let translatedSignals: [Signal<(String, [MessageTextEntity]), TranslationError>] = texts.map { (text, _) in
gtranslate(text, toLang)
|> map { ($0, []) }
|> mapError { _ in .generic }
}
return combineLatest(translatedSignals)
}
return `default`
|> `catch` { originalError in
let translatedSignals: [Signal<(String, [MessageTextEntity]), TranslationError>] = texts.map { (text, _) in
gtranslate(text, toLang)
|> map { ($0, []) }
|> mapError { _ in originalError }
}
return combineLatest(translatedSignals)
}
}
@@ -85,11 +85,13 @@ func _internal_keepCachedTimeZoneListUpdated(account: Account) -> Signal<Never,
return account.postbox.transaction { transaction in
switch result {
case let .timezonesList(timezones, hash):
case let .timezonesList(timezonesListData):
let (timezones, hash) = (timezonesListData.timezones, timezonesListData.hash)
var items: [TimeZoneList.Item] = []
for item in timezones {
switch item {
case let .timezone(id, name, utcOffset):
case let .timezone(timezoneData):
let (id, name, utcOffset) = (timezoneData.id, timezoneData.name, timezoneData.utcOffset)
items.append(TimeZoneList.Item(id: id, title: name, utcOffset: utcOffset))
}
}
@@ -49,7 +49,8 @@ func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: Me
switch result {
case let .success(transcribedAudio):
switch transcribedAudio {
case let .transcribedAudio(flags, transcriptionId, text, trialRemainingCount, trialUntilDate):
case let .transcribedAudio(transcribedAudioData):
let (flags, transcriptionId, text, trialRemainingCount, trialUntilDate) = (transcribedAudioData.flags, transcribedAudioData.transcriptionId, transcribedAudioData.text, transcribedAudioData.trialRemainsNum, transcribedAudioData.trialRemainsUntilDate)
let isPending = (flags & (1 << 0)) != 0
updatedAttribute = AudioTranscriptionMessageAttribute(id: transcriptionId, text: text, isPending: isPending, didRate: false, error: nil)
@@ -1,3 +1,9 @@
#if DEBUG
import SGSimpleSettings
#endif
import SGTranslationLangFix
import SwiftSoup
import Foundation
import Postbox
import SwiftSignalKit
@@ -18,7 +24,7 @@ func _internal_translate(network: Network, text: String, toLang: String, entitie
var flags: Int32 = 0
flags |= (1 << 1)
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: [.textWithEntities(text: text, entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary()))], toLang: toLang))
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: [.textWithEntities(.init(text: text, entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())))], toLang: sgTranslationLangFix(toLang)))
|> mapError { error -> TranslationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
@@ -38,8 +44,10 @@ func _internal_translate(network: Network, text: String, toLang: String, entitie
}
|> mapToSignal { result -> Signal<(String, [MessageTextEntity])?, TranslationError> in
switch result {
case let .translateResult(results):
if case let .textWithEntities(text, entities) = results.first {
case let .translateResult(translateResultData):
let results = translateResultData.result
if case let .textWithEntities(textWithEntitiesData) = results.first {
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
return .single((text, messageTextEntitiesFromApiEntities(entities)))
} else {
return .single(nil)
@@ -54,7 +62,7 @@ func _internal_translateTexts(network: Network, texts: [(String, [MessageTextEnt
var apiTexts: [Api.TextWithEntities] = []
for text in texts {
apiTexts.append(.textWithEntities(text: text.0, entities: apiEntitiesFromMessageTextEntities(text.1, associatedPeers: SimpleDictionary())))
apiTexts.append(.textWithEntities(.init(text: text.0, entities: apiEntitiesFromMessageTextEntities(text.1, associatedPeers: SimpleDictionary()))))
}
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: apiTexts, toLang: toLang))
@@ -76,9 +84,11 @@ func _internal_translateTexts(network: Network, texts: [(String, [MessageTextEnt
|> mapToSignal { result -> Signal<[(String, [MessageTextEntity])], TranslationError> in
var texts: [(String, [MessageTextEntity])] = []
switch result {
case let .translateResult(results):
case let .translateResult(translateResultData):
let results = translateResultData.result
for result in results {
if case let .textWithEntities(text, entities) = result {
if case let .textWithEntities(textWithEntitiesData) = result {
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
texts.append((text, messageTextEntitiesFromApiEntities(entities)))
}
}
@@ -176,18 +186,18 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin
var result: [Api.TextWithEntities] = []
for messageId in messageIds {
if let text = resultTexts[AnyHashable(messageId)] {
result.append(.textWithEntities(text: text, entities: []))
result.append(.textWithEntities(.init(text: text, entities: [])))
} else if let text = messageTexts[messageId] {
result.append(.textWithEntities(text: text, entities: []))
result.append(.textWithEntities(.init(text: text, entities: [])))
} else {
result.append(.textWithEntities(text: "", entities: []))
result.append(.textWithEntities(.init(text: "", entities: [])))
}
}
return .single(.translateResult(result: result))
return .single(.translateResult(.init(result: result)))
}
}
} else {
msgs = account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang))
msgs = account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: sgTranslationLangFix(toLang)))
|> map(Optional.init)
|> mapError { error -> TranslationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
@@ -210,11 +220,13 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin
return combineLatest(msgs, combineLatest(pollSignals), combineLatest(audioTranscriptionsSignals))
|> mapToSignal { (result, pollResults, audioTranscriptionsResults) -> Signal<Void, TranslationError> in
return account.postbox.transaction { transaction in
if case let .translateResult(results) = result {
if case let .translateResult(translateResultData) = result {
let results = translateResultData.result
var index = 0
for result in results {
let messageId = messageIds[index]
if case let .textWithEntities(text, entities) = result {
if case let .textWithEntities(textWithEntitiesData) = result {
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
let updatedAttribute: TranslationMessageAttribute = TranslationMessageAttribute(text: text, entities: messageTextEntitiesFromApiEntities(entities), toLang: toLang)
transaction.updateMessage(messageId, update: { currentMessage in
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
@@ -284,6 +296,42 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin
}
}
func _internal_translateMessagesViaText(account: Account, messagesDict: [EngineMessage.Id: String], fromLang: String?, toLang: String, enableLocalIfPossible: Bool, generateEntitiesFunction: @escaping (String) -> [MessageTextEntity]) -> Signal<Never, TranslationError> {
var listOfSignals: [Signal<Void, TranslationError>] = []
for (messageId, text) in messagesDict {
listOfSignals.append(
// _internal_translate(network: account.network, text: text, toLang: toLang)
// |> mapToSignal { result -> Signal<Void, TranslationError> in
// guard let translatedText = result else {
// return .complete()
// }
gtranslate(text, toLang)
|> mapError { _ -> TranslationError in
return .generic
}
|> mapToSignal { translatedText -> Signal<Void, TranslationError> in
// guard case let .result(translatedText) = result else {
// return .complete()
// }
return account.postbox.transaction { transaction in
transaction.updateMessage(messageId, update: { currentMessage in
let updatedAttribute: TranslationMessageAttribute = TranslationMessageAttribute(text: translatedText, entities: generateEntitiesFunction(translatedText), toLang: toLang)
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
var attributes = currentMessage.attributes.filter { !($0 is TranslationMessageAttribute) }
attributes.append(updatedAttribute)
return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, 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))
})
}
|> castError(TranslationError.self)
// |> castError(TranslateFetchError.self)
}
)
}
return combineLatest(listOfSignals) |> ignoreValues
}
func _internal_togglePeerMessagesTranslationHidden(account: Account, peerId: EnginePeer.Id, hidden: Bool) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Api.InputPeer? in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
@@ -334,3 +382,249 @@ func _internal_togglePeerMessagesTranslationHidden(account: Account, peerId: Eng
|> ignoreValues
}
}
// TODO(swiftgram): Refactor
public struct TranslateRule: Codable {
public let name: String
public let pattern: String
public let data_check: String
public let match_group: Int
}
public func getTranslateUrl(_ message: String,_ toLang: String) -> String {
let sanitizedMessage = message // message.replaceCharactersFromSet(characterSet:CharacterSet.newlines, replacementString: "<br>")
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&")
return "https://translate.google.com/m?hl=en&tl=\(toLang)&sl=auto&q=\(sanitizedMessage.addingPercentEncoding(withAllowedCharacters: queryCharSet) ?? "")"
}
func prepareResultString(_ str: String) -> String {
return str
// return str.htmlDecoded.replacingOccurrences(of: "<br>", with: "\n").replacingOccurrences(of: "< br>", with: "\n").replacingOccurrences(of: "<br >", with: "\n")
}
var regexCache: [String: NSRegularExpression] = [:]
public func parseTranslateResponse(_ data: String) -> String {
do {
let document = try SwiftSoup.parse(data)
if let resultContainer = try document.select("div.result-container").first() {
// new_mobile
return prepareResultString(try resultContainer.text())
} else if let tZero = try document.select("div.t0").first() {
// old_mobile
return prepareResultString(try tZero.text())
}
} catch Exception.Error(let type, let message) {
#if DEBUG
SGtrace("translate", what: "Translation parser failure, An error of type \(type) occurred: \(message)")
#endif
// print("Translation parser failure, An error of type \(type) occurred: \(message)")
} catch {
#if DEBUG
SGtrace("translate", what: "Translation parser failure, An error occurred: \(error)")
#endif
// print("Translation parser failure, An error occurred: \(error)")
}
return ""
}
public func getGTranslateLang(_ userLang: String) -> String {
var lang = userLang
let rawSuffix = "-raw"
if lang.hasSuffix(rawSuffix) {
lang = String(lang.dropLast(rawSuffix.count))
}
lang = lang.lowercased()
// Fallback To Google lang
switch (lang) {
case "zh-hans", "zh":
return "zh-CN"
case "zh-hant":
return "zh-TW"
case "he":
return "iw"
default:
break
}
// Fix for pt-br and other regional langs
// https://cloud.go
// ogle.com/tran
// slate/do
// cs/lang
// uages
lang = lang.components(separatedBy: "-")[0].components(separatedBy: "_")[0]
return lang
}
public enum TranslateFetchError {
case network
}
let TranslateSessionConfiguration = URLSessionConfiguration.ephemeral
// Create a URLSession with the ephemeral configuration
let TranslateSession = URLSession(configuration: TranslateSessionConfiguration)
public func requestTranslateUrl(url: URL) -> Signal<String, TranslateFetchError> {
return Signal { subscriber in
let completed = Atomic<Bool>(value: false)
var request = URLRequest(url: url)
request.httpMethod = "GET"
// Set headers
request.setValue("Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1;.NET CLR 1.1.4322;.NET CLR 2.0.50727;.NET CLR 3.0.04506.30)", forHTTPHeaderField: "User-Agent")
let downloadTask = TranslateSession.dataTask(with: request, completionHandler: { data, response, error in
let _ = completed.swap(true)
if let response = response as? HTTPURLResponse {
if response.statusCode == 200 {
if let data = data {
if let result = String(data: data, encoding: .utf8) {
subscriber.putNext(result)
subscriber.putCompletion()
} else {
subscriber.putError(.network)
}
} else {
// print("Empty data")
subscriber.putError(.network)
}
} else {
// print("Non 200 status")
subscriber.putError(.network)
}
} else {
// print("No response (??)")
subscriber.putError(.network)
}
})
downloadTask.resume()
return ActionDisposable {
if !completed.with({ $0 }) {
downloadTask.cancel()
}
}
}
}
public func gtranslate(_ text: String, _ toLang: String) -> Signal<String, TranslateFetchError> {
// 1) Preserve *all* line breaks, including empty ones
let lines = text.components(separatedBy: "\n")
// 2) Map each line to either a passthrough signal or a translate signal
let translationSignals: [Signal<String, TranslateFetchError>] = lines.map { rawLine in
// Grab the "core" text and its leading whitespace
let leadingWhitespace = rawLine.prefix { $0.isWhitespace }
let core = rawLine.trimmingCharacters(in: .whitespacesAndNewlines)
// If theres nothing to translate, just emit the line back
if core.isEmpty {
return .single(rawLine)
}
// Otherwise translate the core, then re-attach the indentation
return gtranslateSentence(core, toLang)
|> map { translatedCore in
return String(leadingWhitespace) + translatedCore
}
}
// 3) Combine them and re-join with newlines
return combineLatest(translationSignals)
|> map { results in
let joined = results.joined(separator: "\n")
return joined.isEmpty ? text : joined
}
}
public func gtranslateSentence(_ text: String, _ toLang: String) -> Signal<String, TranslateFetchError> {
return Signal { subscriber in
let urlString = getTranslateUrl(text, getGTranslateLang(toLang))
let url = URL(string: urlString)!
let translateSignal = requestTranslateUrl(url: url)
var translateDisposable: Disposable? = nil
translateDisposable = translateSignal.start(next: {
translatedHtml in
#if DEBUG
print("urlString: \(urlString)")
let startTime = CFAbsoluteTimeGetCurrent()
print("translatedHtml: \(translatedHtml)")
print("decodedHtml: \(translatedHtml.htmlDecoded)")
#endif
let result = parseTranslateResponse(translatedHtml)
#if DEBUG
print("translatedResult: \(result)")
SGtrace("translate", what: "Translation parsed in \(CFAbsoluteTimeGetCurrent() - startTime)")
#endif
if result.isEmpty {
// print("EMPTY RESULT")
subscriber.putError(.network) // Fake
} else {
subscriber.putNext(result)
subscriber.putCompletion()
}
}, error: { _ in
subscriber.putError(.network)
})
return ActionDisposable {
translateDisposable?.dispose()
}
}
}
public func gtranslateSplitTextBySentences(_ text: String, maxChunkLength: Int = 1500) -> [String] {
if text.count <= maxChunkLength {
return [text]
}
var chunks: [String] = []
var currentChunk = ""
text.enumerateSubstrings(in: text.startIndex..<text.endIndex, options: .bySentences) { (substring, _, _, _) in
guard let sentence = substring else { return }
if currentChunk.count + sentence.count + 1 < maxChunkLength {
currentChunk += sentence + " "
} else {
if !currentChunk.isEmpty {
chunks.append(currentChunk.trimmingCharacters(in: .whitespacesAndNewlines))
}
currentChunk = sentence + " "
}
}
if !currentChunk.isEmpty {
chunks.append(currentChunk.trimmingCharacters(in: .whitespacesAndNewlines))
}
return chunks
}
extension String {
var htmlDecoded: String {
let attributedOptions: [NSAttributedString.DocumentReadingOptionKey : Any] = [
NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html,
NSAttributedString.DocumentReadingOptionKey.characterEncoding : String.Encoding.utf8.rawValue
]
let decoded = try? NSAttributedString(data: Data(utf8), options: attributedOptions, documentAttributes: nil).string
return decoded ?? self
}
func replaceCharactersFromSet(characterSet: CharacterSet, replacementString: String = "") -> String {
return components(separatedBy: characterSet).joined(separator: replacementString)
}
}
@@ -73,7 +73,8 @@ func _internal_requestUpdatePinnedMessage(account: Account, peerId: PeerId, upda
account.stateManager.addUpdates(updates)
return account.postbox.transaction { transaction in
switch updates {
case let .updates(updates, _, _, _, _):
case let .updates(updatesData):
let updates = updatesData.updates
if updates.isEmpty {
if peerId.namespace == Namespaces.Peer.CloudChannel {
let messageId: MessageId
@@ -173,7 +174,8 @@ func _internal_requestUnpinAllMessages(account: Account, peerId: PeerId, threadI
}
|> mapToSignal { result -> Signal<Bool, InternalError> in
switch result {
case let .affectedHistory(_, _, count):
case let .affectedHistory(affectedHistoryData):
let count = affectedHistoryData.offset
if count != 0 {
return .fail(.restart)
}